Google FireBase - fcm 推送 (Cloud Messaging)

Posted 晕菜一员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Google FireBase - fcm 推送 (Cloud Messaging)相关的知识,希望对你有一定的参考价值。

要将 Firebase 添加到您的应用,您需要有一个 Firebase 项目以及适用于您的应用的 Firebase 配置文件。

  1. 如果您还没有 Firebase 项目,请在 Firebase 控制台中创建一个。如果您已经有与自己的移动应用相关联的现有 Google 项目,请点击导入 Google 项目。如果没有,请点击添加项目
  2. 点击将 Firebase 添加到您的 Android 应用,然后按设置步骤操作。如果您是导入现有 Google 项目,系统可能会自动执行这些操作,您只需下载配置文件即可。
  3. 出现提示时,输入应用的软件包名称。请务必输入应用在使用的软件包名称;只有在将应用添加到 Firebase 项目时您才能进行此设置。
  4. 最后,您要下载一个 google-services.json 文件。您可以随时重新下载此文件
  5. 如果尚未将此文件复制到项目的模块文件夹(通常是 app/),请执行此操作。

在“根级别”的build.gradle文件添加一条规则。以包含Google服务插件:

 1 buildscript {
 2     
 3     repositories {
 4         jcenter()
 5     }
 6 
 7     dependencies {
 8         classpath \'com.android.tools.build:gradle:2.3.3\'
 9 
10         classpath \'com.google.gms:google-services:3.2.0\'
11     }
12 }
13 
14 allprojects {
15     repositories {
16         maven { url \'https://maven.google.com\' }
17         mavenCentral()
18         jcenter()
19     }
20 }

然后在模块Gradle文件中(比如app模块下),底部添加apply plugin行,以启用 Gradle 插件:

 1 apply plugin: \'com.android.application\'
 2 
 3 android {
 4      // ...
 5 }
 6 
 7 dependencies {
 8     // ...
 9 
10     compile \'com.google.android.gms:play-services-base:11.4.0\'
11     // Google Firebase cloud messaging
12     compile \'com.google.firebase:firebase-messaging:11.4.0\'
13 
14 }
15 
16 apply plugin: \'com.google.gms.google-services\'
自定义ECFCMMSGService 继承 FirebaseMessagingService , 重写onMessageReceived方法接收通知消息弹通知栏
FCM有两种消息: Data Message和 Notification Message.
(1)Notification Message :
只有app在前台的时候才会走这个方法,当app在后台的时候由系统弹通知栏,当app被杀死的时候,从Firebase后台发送是收不到的
 1 http请求:
 2 https://fcm.googleapis.com/fcm/send
 3 
 4 Content-Type:application/json
 5 Authorization:key= App Key
 6 {
 7     "notification" : {
 8       "body" : "You have a new message",
 9       "title" : "",
10       "icon" : "app icon"
11     },
12     "to" : "user token"
13 }
(2)Data Message:
不管app在后台还是前台都会走这个方法。
 1 http请求:
 2 https://fcm.googleapis.com/fcm/send
 3 
 4 Content-Type:application/json
 5 Authorization:key= App Key
 6 {
 7     "data" : {
 8       "request" : "1",
 9       "xxx" : "xxx"
10     },
11     "to" : "user token"
12 }

(3)Messages with both notification and data payload:

这种消息是在Notification Message的基础上加入一些数据,在用户点击通知栏的时候启动对应的activity并传入intent。

 1 public class ECFCMMSGService extends FirebaseMessagingService {
 2 
 3     // 它主要用于处理接收 App 正在运行的时候,接收到的推送
 4 
 5     private static final String TAG = "ECFCMMSGService";
 6 
 7     @Override
 8     public void onMessageReceived(RemoteMessage remoteMessage) {
 9         super.onMessageReceived(remoteMessage);
10 
11         // Check if message contains a data payload.
12         if (remoteMessage.getData().size() > 0) {
13             Log.d(TAG, "Message data payload: " + remoteMessage.getData());
14         }
15 
16         // Check if message contains a notification payload.
17         if (remoteMessage.getNotification() != null) {
18             Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
19 
20             sendNotification(remoteMessage.getNotification().getBody());
21         }
22     }
23 
24     private void sendNotification(String messageBody) {
25 
26         Intent intent = new Intent(this, MainActivity.class);
27         intent.putExtra("key", messageBody);
28         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
29 
30         PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
31                 PendingIntent.FLAG_ONE_SHOT);
32 
33         Bitmap icon2 = BitmapFactory.decodeResource(getResources(),
34                 R.mipmap.app_logo);
35 
36         Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
37         NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
38                 .setSmallIcon(R.mipmap.app_logo)
39                 .setContentTitle("You have a new message.")
40                 .setContentText(messageBody)
41                 .setAutoCancel(true)
42                 .setLargeIcon(icon2)
43                 .setSound(defaultSoundUri)
44                 .setContentIntent(pendingIntent);
45 
46         NotificationManager notificationManager =
47                 (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
48 
49         notificationManager.notify(new Random().nextInt() /* ID of notification */, notificationBuilder.build());
50     }
51 }

自定义 ECFCMTokenRefreshService 集成 FirebaseInstanceIdService.

用户token的创建,转换和更新,在onTokenRefresh()方法中获取token并上传到服务器。

  1 public class ECFCMTokenRefreshService extends FirebaseInstanceIdService {
  2 
  3     // 它主要用于管理 FCM 的注册令牌(下文简称 FCM_TOKEN ),以及更改等。它可以获取到用户设备唯一的一个 FCM_TOKEN ,向单个用户推送消息的时候使用
  4 
  5     private static final String TAG = "FCMTokenRefreshService";
  6 
  7     private ApiService mService;
  8     private float mRequestTime = 0;
  9     private int mErrorCount = 0;
 10     private int REQUEST_ERROR_MAX = 10;
 11     private TreeMap<String, Object> mParams;
 12 
 13     @Override
 14     public void onCreate() {
 15         super.onCreate();
 16 
 17         if (PreferencesUtils.getInstance().isFCMTokenSendServiceSuccess()) {
 18             return;
 19         }
 20 
 21         String token = PreferencesUtils.getInstance().getFcmToken();
 22 
 23         if (TextUtils.isEmpty(token)) {
 24             token = FirebaseInstanceId.getInstance().getToken();
 25         }
 26 
 27         sendFCMTokenToServer(token);
 28     }
 29 
 30     @Override
 31     public void onTokenRefresh() {
 32         super.onTokenRefresh();
 33 
 34         PreferencesUtils.getInstance().saveFCMTokenSendServiceSuccess(false);
 35 
 36         String token = FirebaseInstanceId.getInstance().getToken();
 37         Log.i(TAG, "onTokenRefresh: " + token);
 38         // Important, send the fcm token to the server
 39         sendFCMTokenToServer(token);
 40     }
 41 
 42     // http://ebike-test.zriot.net/shop-app/push/token
 43     private void sendFCMTokenToServer(final String token) {
 44 
 45         if (TextUtils.isEmpty(token)) {
 46             return;
 47         }
 48 
 49         if (mService == null) {
 50             mService = RetrofitHelper.getInstance().getApiService(ApiService.class);
 51         }
 52 
 53         PreferencesUtils.getInstance().saveFCMToken(token);
 54 
 55         if (!AccountManager.getInstance().isUserLogin()) {
 56             return;
 57         }
 58 
 59         if (mParams == null) {
 60             mParams = new TreeMap<>();
 61         }
 62 
 63         if (mParams.size() == 0) {
 64             mParams.put("uid", AccountManager.getInstance().getUserId());
 65             mParams.put("token", AccountManager.getInstance().getToken());
 66             mParams.put("fcmToken", token);
 67             mParams.put("osType", "1"); // 1: android 2 : ios 70         }
 71 
 72         mService.sendFCMTokenToServer(mParams)
 73                 .subscribeOn(Schedulers.io())
 74                 .unsubscribeOn(Schedulers.io())
 75                 .observeOn(AndroidSchedulers.mainThread())
 76                 .subscribeWith(new DisposableObserverCallBack<BaseResponse>() {
 77                     @Override
 78                     public void onNext(@NonNull BaseResponse response) {
 79 
 80                         if (response == null) {
 81                             return;
 82                         }
 83 
 84                         if (response.isRequestSuccess()) {
 85                             PreferencesUtils.getInstance().saveFCMTokenSendServiceSuccess(true);
 86                         }
 87 
 88                         mErrorCount = 0;
 89                     }
 90 
 91                     @Override
 92                     public void onError(Throwable e) {
 93                         super.onError(e);
 94 
 95                         if (mErrorCount >= REQUEST_ERROR_MAX) {
 96                             return;
 97                         }
 98 
 99                         if (!allowRequest()) {
100                             return;
101                         }
102 
103                         sendFCMTokenToServer(token);
104 
105                         mErrorCount += 1;
106                     }
107                 });
108     }
109 
110     private boolean allowRequest() {
111 
112         if (mRequestTime == 0) {
113             mRequestTime = System.currentTimeMillis();
114             return true;
115         }
116 
117         if (System.currentTimeMillis() - mRequestTime < 3000) {
118 
119             return false;
120         } else {
121 
122             mRequestTime = System.currentTimeMillis();
123             return true;
124         }
125     }
126 
127 }

在android清单文件中:注册service:

 1      <service android:name=".fcm.ECFCMMSGService"
 2             android:stopWithTask="false">
 3             <intent-filter>
 4                 <action android:name="com.google.firebase.MESSAGING_EVENT" />
 5             </intent-filter>
 6         </service>
 7 
 8         <service android:name=".fcm.ECFCMTokenRefreshService"
 9             android:stopWithTask="false">
10             <intent-filter>
11                 <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
12             </intent-filter>
13         </service>

注意:

App 是否运行,决定了推送走的两条线路

App 在运行的时候,推送如果有 Notification ,一般也是我们自己去控制的,所以最终它点击后的效果,我们是可以通过 PendingIntent 做部分定制的。

但是如果是在 App 没有运行的情况下,就完全归 FCM 服务帮你完成这一系列的操作,它点击后的效果,只能将你的 App 调起,并且把你需要的参数传递到你的 SplashActivity(Action 为 android.intent.action.MAIN 的 Activity) 上。

推送服务的 icon 和 字体颜色

FCM 的推送通知,可以配置 icon 以及 App 名称的颜色。对 icon 和 字体颜色的配置,需要在 AndroidManifest.xml 中进行。

还有一点需要注意,通常我们 App 的 Icon 都做的非常的精美,但是这种 Icon 是无法直接使用在 FCM 的推送上的。需要额外的定制,以及对应的尺寸。

FCM Icon 的标准:背景透明,以白色图案填充。(实际上,展开后的效果会将icon 进行着色,所以任何颜色最终都会被着色成我们配置的颜色,不配置默认是个浅灰色)。

当然,它和图标的适配一样,不一定需要全套,只需要配置我们需要的尺寸即可。

将以下代码行添加到 application 标记内,以设置自定义默认图标和app 名称的自定义颜色:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->

<meta-data
 android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />

<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->

<meta-data
 android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

AndroidManifest.xml

如果配置好这些,依然得到的是一个白色的小块,可以尝试升级一下 FCM 的版本,低版本好像是有这个 Bug ,在新版已经解决了。

 

问题:

Firebase控制台测试只能发送Notification Message,测试的时候把App从最近列表划掉之后能收到,而且是在没FQ的情况下都能收到。当然当进程被完全杀死就收不到了。

Data Message则需要通过server api调用,前台后台都能收到透传消息。

Android Push Notifications using Firebase Cloud Messaging FCM & PHP

 

以上是关于Google FireBase - fcm 推送 (Cloud Messaging)的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 推送通知与 PhoneGap Build 使用 cordova-plugin-fcm

使用 PhoneGap 和 Firebase 云消息传递 (FCM) 的简单推送通知 Android 应用程序

如何通过 Firebase 云消息发送推送通知(快速入门)?

推送通知 - Firebase控制消息传递(FCM) - 无法运行应用程序(未找到默认活动)

推送中的“FCM 通道”知识了解一下

如何使用 Firebase 云消息传递和 Liferay 推送通知