前言

最近在开发一款国际版的APP,项目中需要支持客户端消息推送,自己实现肯定是不可能的,需要寻找第三方的SDK。在做技术调研的时候决定使用google的FCM框架来实现,有个缺点就是大陆是接收不到的(fq可以)。那么本章就给大家分享一下如何基于Spring Boot集成Firebase实现FCM消息推送功能。

必要条件

1、大陆开发者要准备好vpn(你懂的)。
2、申请Google Firebase账号。
3、获取Firebase秘钥。
4、有效的客户端token令牌(app客户端开发者提供)。

开发
第一步:申请开发者账号

地址:https://console.firebase.google.com/

第二步:添加一个项目

如下图所示,添加一个项目:

TPS:注意必须与android项目本地包名一致就是manifest中package的路径一样。

第三步:下载google-services.json文件

点击左上角——设置(图标)——项目设置,点击google-services.json下载,如下图所示:

将下载好的文件放到Spring Boot项目的resources目录下,例如:

第四步:集成Firebase

pom引用firebase,要fq才能下载,如果没有条件就需要手动导入下载好的jar包。

<dependency><groupId>com.google.firebase</groupId><artifactId>firebase-admin</artifactId><version>6.5.0</version>
</dependency>
第五步:编写FCM推送消息请求实体

这里只是做了个发送消息的简单封装实体,方便数据传输:

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**** 功能描述: FCM推送消息请求实体* @auther: IT实战联盟Line* @date: 2019年11月25日09:54:51*/
@NoArgsConstructor
@Data
@ApiModel(value = "FCM推送消息请求实体")
public class FCMSendMessageReqDTO implements Serializable {private static final long serialVersionUID = 8317264020451674205L;@ApiModelProperty(value = "消息标题" , required = true)private String title;@ApiModelProperty(value = "消息内容" , required = true)private String body;@ApiModelProperty(value = "用户token集合" , required = true)private String tokens;@ApiModelProperty(value = "主题" , required = false)private String topic;
}
第六步:编写FCM推送消息工具类

该工具类支持单个和批量推送,这里批量采用的是给主题推。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import com.google.auth.oauth2.GoogleCredentials;
import java.util.concurrent.ConcurrentHashMap;
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;/*** @Auther: IT实战联盟Line* @Date: 2019-11-23 14:02* @Description:  Google_FireBase推送工具类*/
public class FireBaseUtil {//存放多个实例的Mapprivate 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 {InputStream serviceAccount = Thread.currentThread().getContextClassLoader().getResourceAsStream(jsonPath);FirebaseOptions options = new FirebaseOptions.Builder().setCredentials(GoogleCredentials.fromStream(serviceAccount)).setDatabaseUrl(dataUrl).build();//初始化firebaseAppFirebaseApp 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();//发送后,返回messageIDString 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 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();//发送后,返回messageIDString response = FirebaseMessaging.getInstance(firebaseApp).send(message);System.out.println("主题推送成功: " + response);}
}
第七步:编写FCM推送Controller

一共两个Controller,单推和群推。

import com.google.firebase.messaging.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;import java.io.*;
import java.util.*;
@Api(value = "FireBase", description = "FireBase")
@RequestMapping("/")
@RestController
@Slf4j
public class FireBaseController {//渠道名字,也是APP的名字public static String appName = "FCM后台新增的项目名称";@ApiOperation(value = "批量FireBase推送", notes = "批量FireBase推送")@ApiImplicitParam(name = "fcmSendMessageReqDTO", value = "{\"title\":\"测试标题\",\"body\":\"测试内容\",\"tokens\":\"1,2\"}")@PostMapping(value = "/pushFireBaseAll", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)public void pushFireBaseAll(@RequestBody FCMSendMessageReqDTO fcmSendMessageReqDTO) {log.info("进入批量FireBase推送 pushFireBaseAll:[{}]", fcmSendMessageReqDTO.toString());//添加tokensList<String> tokens = Arrays.asList(fcmSendMessageReqDTO.getTokens().split(","));//设置Java代理,端口号是代理软件开放的端口,这个很重要。System.setProperty("proxyHost", "127.0.0.1");System.setProperty("proxyPort", "8081");//如果FirebaseApp没有初始化if (!FireBaseUtil.isInit(appName)) {String jsonPath = "fcm/xxxx-firebase-adminsdk.json";String dataUrl = "https://xxxx.firebaseio.com/";//初始化FirebaseApptry {FireBaseUtil.initSDK(jsonPath, dataUrl, appName);FireBaseUtil.registrationTopic(appName, tokens, fcmSendMessageReqDTO.getTopic());  //设置主题FireBaseUtil.sendTopicMes(appName, fcmSendMessageReqDTO.getTopic(), fcmSendMessageReqDTO.getTitle(), fcmSendMessageReqDTO.getBody());    //按主题推送} catch (Exception e) {e.printStackTrace();}} else {log.info("如果FirebaseApp已经初始化");try {FireBaseUtil.registrationTopic(appName, tokens, fcmSendMessageReqDTO.getTopic());  //设置主题FireBaseUtil.sendTopicMes(appName, fcmSendMessageReqDTO.getTopic(), fcmSendMessageReqDTO.getTitle(), fcmSendMessageReqDTO.getBody());    //按主题推送} catch (IOException e) {e.printStackTrace();} catch (FirebaseMessagingException e) {e.printStackTrace();}}}@ApiOperation(value = "FireBase推送", notes = "FireBase推送")@ApiImplicitParam(name = "fcmSendMessageReqDTO", value = "{\"title\":\"测试标题\",\"body\":\"测试内容\",\"tokens\":\"1\"}")@PostMapping(value = "/pushFireBase", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)public void pushFireBase(@RequestBody FCMSendMessageReqDTO fcmSendMessageReqDTO) {log.info("进入批量FireBase推送 pushFireBaseAll:[{}]", fcmSendMessageReqDTO.toString());//添加tokensList<String> tokens = Arrays.asList(fcmSendMessageReqDTO.getTokens().split(","));//设置Java代理,端口号是代理软件开放的端口,这个很重要。System.setProperty("proxyHost", "127.0.0.1");System.setProperty("proxyPort", "8081");//如果FirebaseApp没有初始化if (!FireBaseUtil.isInit(appName)) {String jsonPath = "fcm/xxxx-firebase-adminsdk.json";String dataUrl = "https://xxxx.firebaseio.com/";//初始化FirebaseApptry {FireBaseUtil.initSDK(jsonPath, dataUrl, appName);FireBaseUtil.pushSingle(appName, tokens.get(0), fcmSendMessageReqDTO.getTitle(), fcmSendMessageReqDTO.getBody());  //单推} catch (Exception e) {e.printStackTrace();}} else {log.info("如果FirebaseApp已经初始化");try {FireBaseUtil.pushSingle(appName, tokens.get(0), fcmSendMessageReqDTO.getTitle(), fcmSendMessageReqDTO.getBody());  //单推} catch (IOException e) {e.printStackTrace();} catch (FirebaseMessagingException e) {e.printStackTrace();}}}
}

Spring Boot 项目中集成了swagger ,小伙伴在使用的时候可以去掉。代码是没问题的,都已经测试过。

总结

1、一定要确认网络是否可以FQ,如果不行是访问不了firebase service的。否则会报以下错误,如图所示:

2、xxx.json 存放位置的目录要做好引用,小编是用mac运行的,如果是windows获取json文件的相对路径会有问题。
3、给特定设备推送消息时,需要提前获取到设备的deviceToken。
总之,以上代码可以帮助大家快速入门,并且编写出可以推送成功的示例,如果在使用中有什么问题大家可以留言一起讨论哦~~~
4、国产手机一般阉割了Google service的服务,需要自己去找第三方资源安装,会产生以下问题:

A、应用“杀死”后基本收不到消息。
B、Android8 系统不管应用是否可用都出现收不到消息问题。
有资源的小伙伴可以多测试集中机型哦。

5、设备必须是android4.0以上,Google Play Services 必须是 11.2.0以上版本(这个没有测试,拥有的资源基本都是6以上)。

老板说:明天来加班写个FCM消息推送功能......相关推荐

  1. Flutter+FCM开发推送功能

    我是直接站在巨人的肩上了 参考文档,将fcm集成到flutter项目中. 运行遇到错误:MissingPluginException(No implementation found for metho ...

  2. 开发笔记-Android消息推送骚操作:亚马逊-SNS对接FCM和百度云推送

    写在前面: 之前使用阿里云的服务器用阿里消息推送好好的,然后因为国外业务需要使用亚马逊服务器,阿里云推送也不能用,用亚马逊的 SNS (短信消息推送服务),SNS 可以对接多家推送平台,其中 Andr ...

  3. Android 集成FCM(Google 推送)导致上架失败,提前获取设备信息ANDROID ID

    又来记笔记 大佬们~~ 近期启用之前的项目上架,首先上架的是华为市场,发现一大堆问题,各种审核被拒,搞得问候了审核员的亲戚几次,一次给你来一两条,不会全部一次性给完.奈何别人的大公司.... 大致总结 ...

  4. 用php写百度收录api推送,百度实时推送api接口应用示例

    网站质量不错的网站可以在百度站长平台/数据提交/sitemap栏目下看到实时推送的功能, 目前这个工具是邀请开放, 百度的实时推送的api接口可以实时推送我们新发布的文章, 保证百度在第一时间收录.  ...

  5. Python实现人脸识别 + 手机推送功能,老板来了你就会收到短信提示

    前言 在你上班的时候刷知乎,看视频,玩手机的时候,老板来了!不用担心,不用着急,基于最新的人脸识别 + 手机推送做出的 BossComing.老板站起来的时候,BossComing 会通过人脸识别发现 ...

  6. python、C# 写企业微信机器人推送【图文消息】

    企业微信机器人发送图文消息(基础版) 使用工具 进入代码模式 1. 引入 2. 发送方式 3. 发送到企业微信机器人步骤 3. 总代码 C#写法 看下效果图: 代码展示 使用工具 突然来兴趣搞了个机器 ...

  7. Python写的CSDN信息推送小助手

    转载请注明出处:http://blog.csdn.net/gamer_gyt 博主微博:http://weibo.com/234654758 Github:https://github.com/thi ...

  8. 收发一体超声波测距离传感器模块_超声模块,写完这篇推送,小编吐了

    超声波模块的使用,可以说任何一个玩家没有不知道的.至于教程,都烂大街了.但是为了保持教程的完整性,本小编忍吐再写一遍.本篇简要介绍一下模块的使用. 下一期,将给大家带来另类的超声模块使用方法,敬请期待 ...

  9. uniapp push 推送 个推 安卓Android添加Google 推送服务 FCM 离线推送 Dcloud

    项目甲方在国外需要用到google推送服务,看了文档中说明,如果安卓要实现离线推送,需要通过厂商来解决 在google开发者后台添加项目,获取Legancy server key 获取google-s ...

  10. flutter友盟分享_集成推送那点事-友盟/Mob-Flutter/FCM

    第 97 次推文 LZ-Says 我们都曾羡慕别人,却忘了,我们也曾是别人羡慕的我们. 推荐直接拉到底阅读原文- 前言 最近的任务呐,真是让人蛋碎一地,各种被锤. 不过比较 nice 的是,推送凑齐了 ...

最新文章

  1. HDFS分布式文件系统
  2. Nginx高效学习手册(建议收藏)
  3. 【Matlab】定义顺序增加的字符串数组(A1,A2 ... An)并写到Excel的第一行
  4. a标签传值到另一个页面_前端开发入门——HTML基础标签
  5. python 函数式编程包_python 函数支持函数式编程的包operator partial
  6. 华为薪资等级结构表_华为21级程序员月薪曝光:月薪27w,什么概念!程序员中的战斗机...
  7. 蔚来上线三款硬货:更大电池包、全新EC6、改款ES8
  8. 《经济学人》新一期封面主题:Govcoins 改变金融的数字货币
  9. DotNet中的集合对象(2): Hashtable
  10. Java程序员从笨鸟到菜鸟之(五十)细谈Hibernate(一)hibernate基本概念和体系结构...
  11. Java 垃圾回收算法
  12. 2019年山东计算机单招学校,2019年山东单招学校排名前十的有哪些?
  13. 电脑如何截长图?如何用电脑截取长图——规划全景
  14. Unity获取隐藏的游戏对象
  15. Monkey King(左偏树 可并堆)
  16. 【Three.js入门】灯光与阴影、平行光阴影属性、聚光灯的属性和应用
  17. 高级复制解决冲突用DBMS_RECTIFIER_DIFF.RECTIFY出现的问题
  18. 安利一下断言利器AssertJ
  19. 唐僧是怎么管理孙悟空的?
  20. Flash场景之间相互跳转的实现方法

热门文章

  1. Android7.1 Audio Debug相关方法
  2. Android7.1 音频声音控制策略
  3. OpenCV读取UsbCam的图像
  4. do_initcalls 的原理
  5. signal、kill、fork
  6. Android WiFi 获取 IP 过程
  7. SylixOS 操作系统Makefile 简介
  8. GIS教程-空间分析之水文分析
  9. tensorflow stack unstack操作
  10. python中的列表推导与生成器