FCM - Google 的推送服務技術

參考資源

Firebase 雲消息傳遞官網
com.google.firebase.messagingAPI這個鏈接要FQ
firebase推送後臺接入--海外APP推送
fcm google 推送 java 服務端集成

什麼是FCM?

本篇文章主要講實現,概念大略介紹一下子啦!
推送服務在國內有很多服務商,但是如果是做海外 App ,推薦還是使用 Google 自己的推送服務,畢竟海外常用的手機型號,都是有 Google 服務的。Google 的推送服務,以前叫做 GCM(Google Cloud Message)。而自從 Google 將 Firebase 收購之後,就將推送服務併到 Firebase 的一項服務中了,現在叫做 FCM。

FCM推送消息類型

  • 通知消息,有時被視爲“顯示消息”。此類消息由 FCM SDK 自動處理。
  • 數據消息,由客戶端應用處理。

通知消息包含一組預定義的用戶可見的鍵。與其相對,數據消息只包含用戶定義的自定義鍵值對。通知消息可以包含可選數據有效負載。這兩種消息類型的有效負載上限均爲 4KB,但從 Firebase 控制檯發送>消息時除外,在那種情況下,系統會強制執行 1024 個字符的限制。

編寫Java推送功能前的準備

第一條:獲取Android或者IOS程序在firebase上申請的json。這個json去前端工程師哪裏要,這個必須有!

第二條:獲取firebase上面Android或者IOS程序的數據庫,這個也得去前端工程師要!

https://telecomm-76736ei.firebaseio.com/
長得樣式和上面差不多

第三條:獲得一個有效的token,這個也得去前端工程師要!

e1v12xfHs3g:APA91bFExfQRg1h4AZc3GqLHxW4ohe3D7Ca0xvGMJkSbY3qe9yXf4Xe10c1O4fHJ2I。
獲取有效token的時候樓主可喫過大虧哦,注意裏面的“:”常常被轉義位“%3A”,你們要一萬個小心。

第四條:你的電腦能FQ,因爲這是發送到Google服務器的。國內是屏蔽訪問國外網絡請求的,如果你想FQ可以找我,我可以幫你!

第五條,添加依賴,沒有下面的log4j依賴會報錯。

  	<dependency>
  		<groupId>com.google.firebase</groupId>
  		<artifactId>firebase-admin</artifactId>
  		<version>6.5.0</version>
	</dependency>
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
       <version>1.7.5</version>
   </dependency>
   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
       <version>1.7.5</version>
   </dependency>

Java代碼

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.AndroidConfig;
import com.google.firebase.messaging.AndroidConfig.Builder;
import com.google.firebase.messaging.AndroidNotification;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;
import com.google.firebase.messaging.TopicManagementResponse;

/**
 * Google_FireBase推送工具類
 * @author Feiqs
 *
 */
public class FireBaseUtil {
	
	//存放多個實例的Map
	private static Map<String,FirebaseApp> firebaseAppMap = new ConcurrentHashMap<>();
	//獲取AndroidConfig.Builder對象
	private static com.google.firebase.messaging.AndroidConfig.Builder androidConfigBuilder=AndroidConfig.builder();
	//獲取AndroidNotification.Builder對象
	private static AndroidNotification.Builder androidNotifiBuilder=AndroidNotification.builder();
	
	/**
	 * 判斷SDK是否初始化
	 * @param appName
	 * @return
	 */
	public static boolean isInit(String appName) {
		return firebaseAppMap.get(appName) != null;
	}
	
	/**
	 * 初始化SDK
	 * @param jsonPath      JSON路徑
	 * @param dataUrl       firebase數據庫
	 * @param appName       APP名字
	 * @throws IOException
	 */
	public static void initSDK(String jsonPath, String dataUrl,String appName) throws IOException {
		FileInputStream serviceAccount = new FileInputStream(jsonPath);
		FirebaseOptions options = new FirebaseOptions.Builder()
				.setCredentials(GoogleCredentials.fromStream(serviceAccount))
				.setDatabaseUrl(dataUrl).build();
		//初始化firebaseApp
		FirebaseApp firebaseApp = FirebaseApp.initializeApp(options);
		//存放
		firebaseAppMap.put(appName,firebaseApp);
	}
	
    /**
     * 單設備推送
     * @param appName      應用的名字
     * @param token        註冊token
     * @param title        推送題目
     * @param bady         推送內容
     * @return
     * @throws IOException 
     * @throws FirebaseMessagingException 
     */
    public static void pushSingle(String appName, String token, String title, String body) throws IOException, FirebaseMessagingException{
    	//獲取實例
        FirebaseApp firebaseApp = firebaseAppMap.get(appName);
        //實例爲空的情況
        if (firebaseApp == null) {
        	return;        	
        }
        //構建消息內容
        Message message = Message.builder().setNotification(new Notification(title,body))
        		.setToken(token)
        		.build();
        //發送後,返回messageID
        String response = FirebaseMessaging.getInstance(firebaseApp).send(message);
        System.out.println("單個設備推送成功 : "+response);
    }
    
	/**
	 * 給設備訂閱主題
	 * @param appName     應用的名字
	 * @param Tokens      設備的token,最大1000個
	 * @param topic       要添加的主題
	 * @return 
	 * @throws FirebaseMessagingException
	 * @throws IOException 
	 */
	public static void registrationTopic(String appName, List<String> tokens, String topic) throws FirebaseMessagingException, IOException {
    	//獲取實例
		FirebaseApp firebaseApp = firebaseAppMap.get(appName);
		//實例不存在的情況
		if(firebaseApp == null) {
			return;
		}
		//訂閱,返回主題管理結果對象。
		TopicManagementResponse response = FirebaseMessaging.getInstance(firebaseApp).subscribeToTopic(tokens, topic);
		System.out.println("添加設備主題,成功:" + response.getSuccessCount() + ",失敗:" + response.getFailureCount());
	}
    
	/**
	 * 取消設備的訂閱主題
	 * @param appName     應用的名字
	 * @param tokens      設備的token,最大1000個  
	 * @param topic       取消的主題
	 * @return   
	 * @throws FirebaseMessagingException
	 * @throws IOException 
	 */
	public static void cancelTopic(String appName, List<String> tokens, String topic) throws FirebaseMessagingException, IOException {
    	//獲取實例
    	FirebaseApp firebaseApp = firebaseAppMap.get(appName);
    	//實例不存在的情況
		if(firebaseApp == null) {
			return;
		}
		//取消訂閱,返回主題管理結果對象。
		TopicManagementResponse response = FirebaseMessaging.getInstance(firebaseApp).unsubscribeFromTopic(tokens, topic);
		System.out.println("取消設備主題,成功:" + response.getSuccessCount() + ",失敗:" + response.getFailureCount());		
	}
    
	/**
	 * 按主題推送
	 * @param appName      應用的名字
	 * @param topic        主題的名字
	 * @param title        消息題目
	 * @param body         消息體
	 * @return 
	 * @throws FirebaseMessagingException
	 * @throws IOException 
	 */
	public static void sendTopicMes(String appName, String topic, String title, String body) throws FirebaseMessagingException, IOException {
    	//獲取實例
		FirebaseApp firebaseApp = firebaseAppMap.get(appName);
		//實例不存在的情況
		if(firebaseApp == null) {
			return;
		}
		//構建消息
		Message message = Message.builder()
				.setNotification(new Notification(title,body))
				.setTopic(topic)
				.build();
		//發送後,返回messageID
		String response = FirebaseMessaging.getInstance(firebaseApp).send(message);
		System.out.println("主題推送成功: " + response);
	}
	
	/**
	 * 單條Android設備推送消息(和pushSingle方法幾乎沒有區別)
     * @param appName      應用的名字
     * @param token        註冊token
     * @param title        推送題目
     * @param bady         推送內容
	 * @throws FirebaseMessagingException 
	 */
	public static void pushSingleToAndroid(String appName, String token, String title, String body) throws FirebaseMessagingException {
		//獲取實例
        FirebaseApp firebaseApp = firebaseAppMap.get(appName);
        //實例爲空的情況
        if (firebaseApp == null) {
        	return;        	
        }
        androidConfigBuilder.setRestrictedPackageName("io.telecomm.telecomm");
		androidNotifiBuilder.setColor("#55BEB7");// 設置消息通知顏色
		androidNotifiBuilder.setIcon("https://www.shiku.co/images/favicon.png");// 設置消息圖標
		androidNotifiBuilder.setTitle(title);// 設置消息標題
		androidNotifiBuilder.setBody(body);// 設置消息內容
		AndroidNotification androidNotification=androidNotifiBuilder.build();
		androidConfigBuilder.setNotification(androidNotification);
		AndroidConfig androidConfig=androidConfigBuilder.build();
		//構建消息
		Message message = Message.builder()
				.setToken(token)
				.setAndroidConfig(androidConfig)
				.build();
		//發送後,返回messageID
        String response = FirebaseMessaging.getInstance(firebaseApp).send(message);
        System.out.println("單個安卓設備推送成功 : "+response);
	}
	
	/**
	 * Android按主題推送(和sendTopicMes方法幾乎沒有區別)
	 * @param appName      應用的名字
	 * @param topic        主題的名字
	 * @param title        消息題目
	 * @param body         消息體
	 * @return 
	 * @throws FirebaseMessagingException
	 * @throws IOException 
	 */
	public static void sendTopicMesToAndroid(String appName, String topic, String title, String body) throws FirebaseMessagingException, IOException {
		//獲取實例
        FirebaseApp firebaseApp = firebaseAppMap.get(appName);
        //實例爲空的情況
        if (firebaseApp == null) {
        	return;        	
        }
        androidNotifiBuilder.setColor("#55BEB7");// 設置消息通知顏色
		androidNotifiBuilder.setIcon("https://www.shiku.co/images/favicon.png");// 設置消息圖標
		androidNotifiBuilder.setTitle(title);// 設置消息標題
		androidNotifiBuilder.setBody(body);// 設置消息內容
		AndroidNotification androidNotification=androidNotifiBuilder.build();
		androidConfigBuilder.setNotification(androidNotification);
		AndroidConfig androidConfig=androidConfigBuilder.build();
		//構建消息
		Message message = Message.builder()
				.setTopic(topic)
				.setAndroidConfig(androidConfig)
				.build();
		String response = FirebaseMessaging.getInstance(firebaseApp).send(message);
		System.out.println("安卓主題推送成功: " + response);
	}
}

測試類

import java.util.LinkedList;
import java.util.List;

/**
*測試FCM
* @author Feiqs
* @version 創建時間:2019年4月23日 上午10:52:53
*/
public class Test {
	private static final String String = null;
	//設備的token值
	public static String token = "e1v12xfHs3g:APA91bFExfQRg1h4AZc3GqLHxW4ohe3D7Ca0xvGMJkSbY3qe9yXf4Xe10c1O4fHJ2IkbsNF6Z0lr97EV7G1ybP4GLDY5nGVa1ufLOtMAKhcXBfua1bGvubf5whjTLuFj6BQdflFz2n2w";
	//渠道名字,也是APP的名字
	public static String appName = "myAppName";
	//主題名字
	public static String topic = "China";
	//通知消息題目
	public static String title = "tip";
	//通知消息內容
	public static String body = "are you ok?";

	//測試內容
	
	public static void main(String args [] ) throws Exception {
		//添加tokens
		List<String> tokens = new LinkedList();
		tokens.add(token);
		//設置Java代理,端口號是代理軟件開放的端口,這個很重要。
		System.setProperty("proxyHost", "localhost");
		System.setProperty("proxyPort", "1080");
		//如果FirebaseApp沒有初始化
		if(!FireBaseUtil.isInit(appName)) {
			String jsonPath = "path/to/serviceAccountKey.json" ;
			String dataUrl = "https://telecomm-773e6e.firebaseio.com/";
			//初始化FirebaseApp
			FireBaseUtil.initSDK(jsonPath, dataUrl, appName);
		}
		
		FireBaseUtil.pushSingle(appName, token, title, body);  //單推
		
		
		FireBaseUtil.registrationTopic(appName, tokens, topic);  //設置主題
		
		FireBaseUtil.sendTopicMes(appName, topic, title, body);    //按主題推送
		
		FireBaseUtil.cancelTopic(appName, tokens, topic);  //取消主題
		
		//安卓設備推送
		FireBaseUtil.pushSingleToAndroid(appName, token, title, body);
		FireBaseUtil.registrationTopic(appName, tokens, topic);  //設置主題
		FireBaseUtil.sendTopicMesToAndroid(appName, topic, title, body);
	} 	
}

總結

  1. 你的電腦可以FQ,你的代碼可是不可以FQ的,需要用代碼設置代理IP和端口,測試代碼中有提到!
  2. 需要和前端工測試協調好,任何一步有問題你都發送不成功,他的數據沒有錯,你纔有機會成功!否則一點機會都沒有!
  3. 哪個“:”千萬要注意,他往往被轉義爲 “%3A”,當初前端工程師一口咬定沒問題,害慘我了!
  4. 由於我的FQ軟件過期了,就不給大家跑結果了,我發誓它可以運行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章