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從最近列表划掉之后能收到,而且是在沒翻牆的情況下都能收到。當然當進程被完全殺死就收不到了。

Data Message則需要通過server api調用,前台后台都能收到透傳消息。

Android Push Notifications using Firebase Cloud Messaging FCM & PHP

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM