參考資源
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);
}
}
總結
- 你的電腦可以FQ,你的代碼可是不可以FQ的,需要用代碼設置代理IP和端口,測試代碼中有提到!
- 需要和前端工測試協調好,任何一步有問題你都發送不成功,他的數據沒有錯,你才有機會成功!否則一點機會都沒有!
- 哪個“:”千萬要注意,他往往被轉義為 “%3A”,當初前端工程師一口咬定沒問題,害慘我了!
- 由於我的FQ軟件過期了,就不給大家跑結果了,我發誓它可以運行。