##参考资源 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依赖会报错。
1 <dependency> 2 <groupId>com.google.firebase</groupId> 3 <artifactId>firebase-admin</artifactId> 4 <version>6.5.0</version> 5 </dependency> 6 <dependency> 7 <groupId>org.slf4j</groupId> 8 <artifactId>slf4j-api</artifactId> 9 <version>1.7.5</version> 10 </dependency> 11 <dependency> 12 <groupId>org.slf4j</groupId> 13 <artifactId>slf4j-log4j12</artifactId> 14 <version>1.7.5</version> 15 </dependency>
##Java代码
1import java.io.FileInputStream; 2import java.io.IOException; 3import java.util.List; 4import java.util.Map; 5import java.util.concurrent.ConcurrentHashMap; 6import com.google.auth.oauth2.GoogleCredentials; 7import com.google.firebase.FirebaseApp; 8import com.google.firebase.FirebaseOptions; 9import com.google.firebase.messaging.AndroidConfig; 10import com.google.firebase.messaging.AndroidConfig.Builder; 11import com.google.firebase.messaging.AndroidNotification; 12import com.google.firebase.messaging.FirebaseMessaging; 13import com.google.firebase.messaging.FirebaseMessagingException; 14import com.google.firebase.messaging.Message; 15import com.google.firebase.messaging.Notification; 16import com.google.firebase.messaging.TopicManagementResponse; 17 18/** 19 * Google_FireBase推送工具类 20 * @author Feiqs 21 * 22 */ 23public class FireBaseUtil { 24 25 //存放多个实例的Map 26 private static Map<String,FirebaseApp> firebaseAppMap = new ConcurrentHashMap<>(); 27 //获取AndroidConfig.Builder对象 28 private static com.google.firebase.messaging.AndroidConfig.Builder androidConfigBuilder=AndroidConfig.builder(); 29 //获取AndroidNotification.Builder对象 30 private static AndroidNotification.Builder androidNotifiBuilder=AndroidNotification.builder(); 31 32 /** 33 * 判断SDK是否初始化 34 * @param appName 35 * @return 36 */ 37 public static boolean isInit(String appName) { 38 return firebaseAppMap.get(appName) != null; 39 } 40 41 /** 42 * 初始化SDK 43 * @param jsonPath JSON路径 44 * @param dataUrl firebase数据库 45 * @param appName APP名字 46 * @throws IOException 47 */ 48 public static void initSDK(String jsonPath, String dataUrl,String appName) throws IOException { 49 FileInputStream serviceAccount = new FileInputStream(jsonPath); 50 FirebaseOptions options = new FirebaseOptions.Builder() 51 .setCredentials(GoogleCredentials.fromStream(serviceAccount)) 52 .setDatabaseUrl(dataUrl).build(); 53 //初始化firebaseApp 54 FirebaseApp firebaseApp = FirebaseApp.initializeApp(options); 55 //存放 56 firebaseAppMap.put(appName,firebaseApp); 57 } 58 59 /** 60 * 单设备推送 61 * @param appName 应用的名字 62 * @param token 注册token 63 * @param title 推送题目 64 * @param bady 推送内容 65 * @return 66 * @throws IOException 67 * @throws FirebaseMessagingException 68 */ 69 public static void pushSingle(String appName, String token, String title, String body) throws IOException, FirebaseMessagingException{ 70 //获取实例 71 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 72 //实例为空的情况 73 if (firebaseApp == null) { 74 return; 75 } 76 //构建消息内容 77 Message message = Message.builder().setNotification(new Notification(title,body)) 78 .setToken(token) 79 .build(); 80 //发送后,返回messageID 81 String response = FirebaseMessaging.getInstance(firebaseApp).send(message); 82 System.out.println("单个设备推送成功 : "+response); 83 } 84 85 /** 86 * 给设备订阅主题 87 * @param appName 应用的名字 88 * @param Tokens 设备的token,最大1000个 89 * @param topic 要添加的主题 90 * @return 91 * @throws FirebaseMessagingException 92 * @throws IOException 93 */ 94 public static void registrationTopic(String appName, List<String> tokens, String topic) throws FirebaseMessagingException, IOException { 95 //获取实例 96 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 97 //实例不存在的情况 98 if(firebaseApp == null) { 99 return; 100 } 101 //订阅,返回主题管理结果对象。 102 TopicManagementResponse response = FirebaseMessaging.getInstance(firebaseApp).subscribeToTopic(tokens, topic); 103 System.out.println("添加设备主题,成功:" + response.getSuccessCount() + ",失败:" + response.getFailureCount()); 104 } 105 106 /** 107 * 取消设备的订阅主题 108 * @param appName 应用的名字 109 * @param tokens 设备的token,最大1000个 110 * @param topic 取消的主题 111 * @return 112 * @throws FirebaseMessagingException 113 * @throws IOException 114 */ 115 public static void cancelTopic(String appName, List<String> tokens, String topic) throws FirebaseMessagingException, IOException { 116 //获取实例 117 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 118 //实例不存在的情况 119 if(firebaseApp == null) { 120 return; 121 } 122 //取消订阅,返回主题管理结果对象。 123 TopicManagementResponse response = FirebaseMessaging.getInstance(firebaseApp).unsubscribeFromTopic(tokens, topic); 124 System.out.println("取消设备主题,成功:" + response.getSuccessCount() + ",失败:" + response.getFailureCount()); 125 } 126 127 /** 128 * 按主题推送 129 * @param appName 应用的名字 130 * @param topic 主题的名字 131 * @param title 消息题目 132 * @param body 消息体 133 * @return 134 * @throws FirebaseMessagingException 135 * @throws IOException 136 */ 137 public static void sendTopicMes(String appName, String topic, String title, String body) throws FirebaseMessagingException, IOException { 138 //获取实例 139 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 140 //实例不存在的情况 141 if(firebaseApp == null) { 142 return; 143 } 144 //构建消息 145 Message message = Message.builder() 146 .setNotification(new Notification(title,body)) 147 .setTopic(topic) 148 .build(); 149 //发送后,返回messageID 150 String response = FirebaseMessaging.getInstance(firebaseApp).send(message); 151 System.out.println("主题推送成功: " + response); 152 } 153 154 /** 155 * 单条Android设备推送消息(和pushSingle方法几乎没有区别) 156 * @param appName 应用的名字 157 * @param token 注册token 158 * @param title 推送题目 159 * @param bady 推送内容 160 * @throws FirebaseMessagingException 161 */ 162 public static void pushSingleToAndroid(String appName, String token, String title, String body) throws FirebaseMessagingException { 163 //获取实例 164 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 165 //实例为空的情况 166 if (firebaseApp == null) { 167 return; 168 } 169 androidConfigBuilder.setRestrictedPackageName("io.telecomm.telecomm"); 170 androidNotifiBuilder.setColor("#55BEB7");// 设置消息通知颜色 171 androidNotifiBuilder.setIcon("https://www.shiku.co/images/favicon.png");// 设置消息图标 172 androidNotifiBuilder.setTitle(title);// 设置消息标题 173 androidNotifiBuilder.setBody(body);// 设置消息内容 174 AndroidNotification androidNotification=androidNotifiBuilder.build(); 175 androidConfigBuilder.setNotification(androidNotification); 176 AndroidConfig androidConfig=androidConfigBuilder.build(); 177 //构建消息 178 Message message = Message.builder() 179 .setToken(token) 180 .setAndroidConfig(androidConfig) 181 .build(); 182 //发送后,返回messageID 183 String response = FirebaseMessaging.getInstance(firebaseApp).send(message); 184 System.out.println("单个安卓设备推送成功 : "+response); 185 } 186 187 /** 188 * Android按主题推送(和sendTopicMes方法几乎没有区别) 189 * @param appName 应用的名字 190 * @param topic 主题的名字 191 * @param title 消息题目 192 * @param body 消息体 193 * @return 194 * @throws FirebaseMessagingException 195 * @throws IOException 196 */ 197 public static void sendTopicMesToAndroid(String appName, String topic, String title, String body) throws FirebaseMessagingException, IOException { 198 //获取实例 199 FirebaseApp firebaseApp = firebaseAppMap.get(appName); 200 //实例为空的情况 201 if (firebaseApp == null) { 202 return; 203 } 204 androidNotifiBuilder.setColor("#55BEB7");// 设置消息通知颜色 205 androidNotifiBuilder.setIcon("https://www.shiku.co/images/favicon.png");// 设置消息图标 206 androidNotifiBuilder.setTitle(title);// 设置消息标题 207 androidNotifiBuilder.setBody(body);// 设置消息内容 208 AndroidNotification androidNotification=androidNotifiBuilder.build(); 209 androidConfigBuilder.setNotification(androidNotification); 210 AndroidConfig androidConfig=androidConfigBuilder.build(); 211 //构建消息 212 Message message = Message.builder() 213 .setTopic(topic) 214 .setAndroidConfig(androidConfig) 215 .build(); 216 String response = FirebaseMessaging.getInstance(firebaseApp).send(message); 217 System.out.println("安卓主题推送成功: " + response); 218 } 219}
##测试类
1import java.util.LinkedList; 2import java.util.List; 3 4/** 5*测试FCM 6* @author Feiqs 7* @version 创建时间:2019年4月23日 上午10:52:53 8*/ 9public class Test { 10 private static final String String = null; 11 //设备的token值 12 public static String token = "e1v12xfHs3g:APA91bFExfQRg1h4AZc3GqLHxW4ohe3D7Ca0xvGMJkSbY3qe9yXf4Xe10c1O4fHJ2IkbsNF6Z0lr97EV7G1ybP4GLDY5nGVa1ufLOtMAKhcXBfua1bGvubf5whjTLuFj6BQdflFz2n2w"; 13 //渠道名字,也是APP的名字 14 public static String appName = "myAppName"; 15 //主题名字 16 public static String topic = "China"; 17 //通知消息题目 18 public static String title = "tip"; 19 //通知消息内容 20 public static String body = "are you ok?"; 21 22 //测试内容 23 24 public static void main(String args [] ) throws Exception { 25 //添加tokens 26 List<String> tokens = new LinkedList(); 27 tokens.add(token); 28 //设置Java代理,端口号是代理软件开放的端口,这个很重要。 29 System.setProperty("proxyHost", "localhost"); 30 System.setProperty("proxyPort", "1080"); 31 //如果FirebaseApp没有初始化 32 if(!FireBaseUtil.isInit(appName)) { 33 String jsonPath = "path/to/serviceAccountKey.json" ; 34 String dataUrl = "https://telecomm-773e6e.firebaseio.com/"; 35 //初始化FirebaseApp 36 FireBaseUtil.initSDK(jsonPath, dataUrl, appName); 37 } 38 39 FireBaseUtil.pushSingle(appName, token, title, body); //单推 40 41 42 FireBaseUtil.registrationTopic(appName, tokens, topic); //设置主题 43 44 FireBaseUtil.sendTopicMes(appName, topic, title, body); //按主题推送 45 46 FireBaseUtil.cancelTopic(appName, tokens, topic); //取消主题 47 48 //安卓设备推送 49 FireBaseUtil.pushSingleToAndroid(appName, token, title, body); 50 FireBaseUtil.registrationTopic(appName, tokens, topic); //设置主题 51 FireBaseUtil.sendTopicMesToAndroid(appName, topic, title, body); 52 } 53}
##总结
- 你的电脑可以FQ,你的代码可是不可以FQ的,需要用代码设置代理IP和端口,测试代码中有提到!
- 需要和前端工测试协调好,任何一步有问题你都发送不成功,他的数据没有错,你才有机会成功!否则一点机会都没有!
- 哪个“:”千万要注意,他往往被转义为 “%3A”,当初前端工程师一口咬定没问题,害惨我了!
- 由于我的FQ软件过期了,就不给大家跑结果了,我发誓它可以运行。