Android出海实战:Firebase FCM推送

浅谈Push推送服务

我相信每一个App都有Push功能,他是一个免费且对App营销非常重要的一个功能。无论是电商的促销活动,还是社交软件的通知,亦或是其他具有时效性的提醒都离不开Push通知。国内的Push推送百花齐放,但如果我们是在国外开展业务,则可以通过Google的Firebase框架中的Could Message(0成本且最稳定)解决这个问题。本文将主要介绍Firebase Could Message(FCM)的集成步骤及注意点。

Google FCM框架概览

所谓Push通知,简言之就是从一个地方将消息通过网络发送到移动客户端,再由移动客户端处理展示给用户的过程。这里一共有三个角色:消息的发送方、消息接收方和消息本身。但真要实现起来也没有那么容易,例如消息的格式、发送的时机、投递的顺序、触达率等问题都需要我们关心,处理。Google FCM框架的出现就是为了解决这些问题,这样我们就可以将更多的注意力放置于消息本身。整体上看,FCM框架的整体工作流程如下:我们按照事件流的处理从左往右看:

第一部分:消息的构建。消息的构建有两种方式:

  1. Firebase控制台(Notifications Console GUI)
  2. FCM Admin SDK:服务端接入 FCM Admin SDK后按照一定规则构建通知消息,此种更加灵活,方便我们根据不同用户画像做不同的App营销处理。本篇篇幅有限不做过多讨论。

第二部分:FCM BackEnd(FCM 后端),由Google负责,对已构建消息的分流处理,根据不同目标发送至不同平台用户。

第三部分:平台层,也就是我们Android 设备,这里更多指的是Android设备上的Google服务,完成最原始消息的接收。也就是说,只有有Google服务的手机才能收到FCM推送。

第四部分:FCM SDK,进一步对消息进行处理,确定分发策略,最终会发送(回调)给接入了FCM SDK的目标App。

当我们接入FCM时,只需关心第一、四部分即可。Google大大简化了我们的使用过程,在此感谢!

FCM 框架接入

这里我们选择使用Firebase FCM 控制台发送push通知(可以先忽视掉后端,我们调通后直接对接后端即可,无需做任何修改),我们集成FCM框架只需要关心两方面:

  1. Firebase控制台的设置
  2. 准备接入FCM SDK的Android项目

其实本质上就是之前提到的消息的发送方和接收方建立链接的过程,一旦链接建立后,便可以直接利用这个链接发送push通知。

Firebase控制台的设置

Firebase控制台的设置步骤如下:

使用Gmail登录至Firebase首页 Firebase 控制台 (google.com),点击顶部“➕”新建一个项目。

然后就会来到这个页面,这里需要设置项目名称,如果是公司已上线项目可以取App名称,这里我们演示用,直接取名FirebaseDemo,项目名称确定后,点击下一步。

第二步主要是确定是否开启Firebase的分析服务,默认开启,这里我们重点在fcm的集成上,所以先关闭。无论开启还是关闭,都不会影响到fcm功能。设置完成后直接点击“创建项目”,短时间的等待后,将会提示项目已就绪,这时候项目就创建好了。点击继续回到首页即可。

创建Android应用

一个Firebase项目是可以包含多个应用的,最简单来说,可以包含 android 和 iOS两个平台的同名称应用。来到Firebase项目首页,我们点击Android图标创建一个Android应用:

如果当前Firebase项目已经有其他应用,则可以通过继续点击“➕”或左侧齿轮进入项目设置添加新的应用。之后便会进入到如下界面:

包名就填我们App包名即可,签名证书选填可以先不管,填写完成后点击注册应用,Firebase会进行包名校验,校验通过后来到第二步:

这里会生成一个 google-services.json 的文件,其中包含了API 密钥、项目 ID、应用 ID等诸多信息,通过这些信息就可以唯一标识一个Android应用了。

按照指示将google-services.json文件添加到项目的制定目录下:

Android项目集成

对于FCM SDK的接入,对Android的项目有如下要求:

  • Android最低版本大于等于Android4.4
  • 安装有Google服务
  • 使用 Jetpack (AndroidX),这需要满足以下版本要求:
    com.android.tools.build:gradle 3.2.1 或更高版本
    compileSdkVersion 28 或更高版本
添加依赖FCM SDK依赖

这里有两种方式:

  1. 通过Firebase Android BoM
  2. 单独引入FCM SDK

因为Firebase SDK集合除了FCM还有很多其他比较有用的SDK,如果需要同时引入这些SDK,难免会有一些依赖版本冲突的情况发生,所以更推荐使用Firebase Android BoM的方式引入,只需要指定目标BoM版本,后续只需按需引入其他Firebase SDK即可,这样可以保证所有引入的库的版本是兼容的。

通过Firebase BoM引入FCM

在模块(应用级)的build.gradle配置文件中引入依赖即可:

dependencies {

    implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
    api 'com.google.firebase:firebase-messaging'

    // ... 省略其他无关代码
    // 如果后续需要引入 firebase-analytics ,只需添加如下代码即可,无需考虑 firebase-messaging 和 firebase-analytics 之间的版本兼容问题
    // implementation 'com.google.firebase:firebase-analytics'
}
集成google-services插件

FCM SDK有两种初始化方式:

  1. 代码显示调用初始化
  2. 通过google-service自动初始化

这里我们选择引入google-services插件的方式,这样一方面在编译期gradle可以自动读取google-services.json中的内容,可以很大程度上减少了手动编码出错的可能。

另一方面,我们也无需在应用启动时,手动的编写初始化代码,让业务代码更加简洁。

初始化步骤如下:

1.在项目级别 build.gradle 文件中引入 google-services 插件:

buildscript {
    repositories {
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
        maven { url "https://dl.google.com/dl/android/maven2" }
        mavenCentral()
        google()
    }
    dependencies {
        // 引入 google-service插件
        classpath 'com.google.gms:google-services:4.3.15'
        // ...省略无关代码
    }
}
 
allprojects {
    repositories {
        mavenCentral()
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
        maven { url "https://dl.google.com/dl/android/maven2" }
        maven { url 'https://jitpack.io' }
        google()
    }
}

2.在应用级目录下的build.gradle文件中应用插件(应用级目录):

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'com.google.gms.google-services' // 应用 google-service插件
}
 
// ... 省略无关代码

至此,Firebase控制台和FCM SDK的引入就都完成了。

开始发送push消息

消息主要有以下3个注意点:

  1. 消息的分类
  2. 消息的接收(Android 设备/客户端)
  3. 消息的发送(Firebase控制台)

消息的分类

Fcm将Push消息按照用途分为了两种:

消息类型处理方发送方
通知消息FCM SDK 自动处理Firebase控制台和接入FCM Admin SDK 的服务端
数据消息客户端自行处理接入了FCM Admin SDK的服务端

通知消息和数据消息都属于Fcm Push消息,那么Fcm是如何区分的呢?这就要从Push消息的格式来看。无论是通知消息还是数据消息都是以Json数据格式组织的,无非就是关键字段的Key不同罢了。
如果是通知消息,消息中将包含一个"notification"字段:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification":{
      "title":"标题",
      "body":"我是内容!"
    }
  }
}

之前有提到,Push消息会经由Fcm SDK传递到我们的客户端,这里当Fcm SDK检测到消息中包含”notification“字段时,就会将其当做一个通知消息来处理。

数据消息所谓的由客户端自行处理,也仍然经过Fcm SDK,只不过 Fcm SDK并不会对其进行任何处理,只是直接投递到客户端罢了。对应的,数据消息的识别字段是”data“。实例数据如下:

{
  "message":{
    "token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "data":{
      "Nick" : "Mario",
      "body" : "内容",
    }
  }
}

如上所见,Fcm SDK 是通过识别关键字段来进行消息的分类处理,所以上述的”notification“,“data”都是fcm识别的关键字之一,定义数据消息时就需要特别注意,按需设置关键字段。同时如果要明确发送数据消息(非通知消息)还需要避开“from”、“message_type”或以“google”或“gcm”开头的任何字词。

无论是通知消息还是数据消息都包含了一个token字段,这个字段是由Fcm SDK生成用于标识当前客户端的,客户端可以将这个值保存下来并上报给服务端,这样后续服务端就可以通过指定token字段的值,定向向指定客户端发送消息了,做到精准营销用户。
不过token的值会如下情况下发生改变,例如:

  • 在其他设备上重新登陆
  • 用户卸载/重新安装应用
  • 用户清除应用数据。

这里不做过多关心,这并不会影响到什么。

消息的处理

在初始设置阶段,我们完成了客户端FCM SDK的接入,如果想要顺利收到Push消息还需要完成如下设置:

1.扩展 FirebaseMessagingService 并在AndroidMainFest.XML中声明:

<service
    android:name=".java.MyService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

2.token的保存和消息的接收

class MyService : FirebaseMessagingService() {
 
    // 一旦token有变化,onNewToken方法就会被回调
    override fun onNewToken(token: String) {
        super.onNewToken(token)
        Log.e(TAG, "new token $token")
    }
 
    override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)
        Log.e(TAG,"onMessageReceived : ${message.messageType}")
    }
 
    override fun onDeletedMessages() {
        super.onDeletedMessages()
        Log.e(TAG,"onDeletedMessages ")
    }
}

扩展 FirebaseMessagingService 后,有三个方法可以重写

  1. onNewToken:每次有新token生成时回调,我们可以利用这个机制保存token
  2. onMessageReceived:
    1. a:对于通知消息:如果App在前台并收到消息时,这个方法就会回调。RemoteMessage的数据结构和之前提到的Json一一对应,这就不展开了。若果App处于后台,消息则会直接展示在通知栏(需通知权限)
    2. b:对于数据消息:无论App处于前台还是后台,都会回调到这个方法
    3. c:参数RemoteMessage中的 Notification 类型的notification对象,用于承载通知消息的数据
  3.  onDeletedMessages : Push消息被删除时回调

至此,我们的客户端就做好了接收消息的准备。但是此时App只能在设备解锁的前提下收到消息,如果想要在解锁前收到消息,还需要完成如下设置:

添加 firebase-messaging-directboot 依赖

/ 如果是Firebase BoM方式依赖
implementation 'com.google.firebase: firebase-messaging-directboot'
// 否则
implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'

给Service添加directBootAware属性

<service
    android:name=".MyService"
    android:exported="false"
    android:directBootAware="true">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

通知权限

如果需要在通知栏展示Push消息,对于Android 13及以上设备需要显示申请通知权限

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

代码动态申请权限:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    if (ContextCompat.checkSelfPermission(this, "android.permission.POST_NOTIFICATIONS") ==
        PackageManager.PERMISSION_GRANTED
    ) {
    }  else {
       
    }
}

消息的发送

当客户端做好接收消息的准备后,就可以通过Firebase控制台创建一个Push消息测试一下了,在Firebase控制面板左侧Tab列表中找到Messaing选项

如果是第一次创建Push消息,则会来到如下界面,这里选择“创建首个宣传活动”(需要当前Firebase登录账户拥有当前项目的所有者或修改者权限)。

之后会弹起如下弹窗,选择“Firebase通知消息”。

选择“Firebase通知消息”之后,便可以进入Push消息的具体设置界面了,这里我们随便设置一个标题和通知内容。

再正式发布前,可以点击右侧的发送测试消息进行测试:

这里需要添加一个“FCM注册令牌”,还记得我们上文提到token吗,填写到这里就可以了(如果之前忘记保存了,可以通过清除缓存并重启App得到)。

添加完成后,在App测添加打印token:

override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)
        Log.e(TAG, "Title :${message.notification?.title.orEmpty()}")
        Log.e(TAG, "Body :${message.notification?.body}")
    }

然后我们将App切换到前台,点击测试,onMessageReceived就会被回到如下:

将App切换到后台后,再次点击测试,可以看到通知栏有通知收到。

但是因为我们没做设置,所以通知展示了默认图标和颜色,这里可以自定义通知图标:

// AndroidmainFest.xml 中
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
 
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

至此,整体流程完成,Yes!!!

Github地址(欢迎下载):https://github.com/loveAndroidAndroid/FirebaseDemo

出海共济

出海之路,路远且艰。更多金融出海解决方案,欢迎关注公众号 趣浪出海 ,欢迎大家一起探讨更多合规问题,稳健航行世界之海。​​​​​​​

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值