Firecase Cloud Messaging - Android項目中集成FCM

應(yīng)工作項目要求,最近在項目中集成了谷歌目前推薦的推送方式FCM。在此做一些集成過程的記錄與一些注意點的分享,寫的不好請輕噴。

原本谷歌原生的推送方式是GCM,也就是Google Cloud Messaging。截至2018年4月10日,Google已棄用GCM。GCM服務(wù)器和客戶端API已棄用,將于2019年4月11日刪除。將GCM應(yīng)用程序遷移到 Firebase 云消息傳遞(FCM),后者繼承了可靠且可擴(kuò)展的GCM基礎(chǔ)架構(gòu)以及許多新功能。
簡明的說就是FCM是GCM的升級版。

Firebase提供了很多服務(wù),包含但不限于認(rèn)證、通知、分析、AdMod、性能監(jiān)控等。這里我們只對通知進(jìn)行集成。

如果想了解原來的GCM可以在下面這個文檔中進(jìn)行查看:
https://developers.google.com/cloud-messaging/
事先聲明下,文章中除了Demo地址是在github上不需要翻墻,其他地址都需要翻墻才可以打開。

一、先來說說為什么要是使用FCM事先消息推送功能。

做Android開發(fā)的都知道,我們最煩產(chǎn)品和我們說為什么我APP殺死了推送就收不到了?為什么IOS就可以?你們能做成像IOS那樣嗎?煩不勝煩。想掄拳頭不?忍住,我們是有涵養(yǎng)的程序員,不用計較無知的PM的言語。

現(xiàn)在Android系統(tǒng)對后臺進(jìn)行的管理越來越嚴(yán)格,各種定制系統(tǒng)也對后臺進(jìn)程進(jìn)行了各種各樣的限制?;旧螦PP被殺死后,基本都收不到消息推送了。現(xiàn)在的國內(nèi)第三方推送也想了各種辦法去處理殺死進(jìn)程后收不到推送的問題,但是效果都不是很好。

為啥IOS的系統(tǒng)就能那么穩(wěn)定的接收消息推送呢?無論是App在前臺運行時的消息接收,還是App在后臺或者殺死狀態(tài)下,對離線消息的接收都十分的靠譜。因為每一個蘋果可以通過自家服務(wù)器維持一個長鏈接,每一個iOS的推送都必須和蘋果打交道,所以這個過程控制得很好。

這里就要說為啥我們要用FCM了。其實Google也有自己的一套推送服務(wù) ,就是過去的GCM,現(xiàn)在升級為FCM,境外的產(chǎn)品基本都是通過Google去實現(xiàn)的推送。Google提供的推送服務(wù)其實也可以做到IOS那樣的效果,也能做到離線消息的穩(wěn)定接收。所以如果你做得是一款海外的項目,那么你就可以選擇通過FCM來實現(xiàn)推送,高效且穩(wěn)定。國內(nèi)因為墻的存在導(dǎo)致了我們需要去選用各種第三方的推送。在這期盼哪天Google回歸大陸吧。

嘰嘰歪歪這么多現(xiàn)在開始看如何進(jìn)行FCM的集成吧。

二、FCM的集成

先提供給大家集成文檔的鏈接,以及Demo工程的github的鏈接。
集成文檔:https://firebase.google.com/docs/cloud-messaging/
官方Demo地址:https://github.com/firebase/quickstart-android
項目中有很多的Firebase提供的服務(wù)的Demo,其中messaging文件夾下就是推送的Demo工程

1.前提條件

集成FCM是有前提條件的,也就是因為這些前提條件導(dǎo)致的境內(nèi)項目無法正常的使用Google提供的服務(wù)。

  • Android系統(tǒng)必須是 Android 4.0 (Ice Cream Sandwich) 或更高版本

  • 手機(jī)安裝了Google Play 服務(wù) 15.0.0 或更高版本(導(dǎo)致境內(nèi)不可使用的根本原因)

  • Android SDK Manager 必須有Google Play services SDK(該條件貌似用AS開發(fā)時不是必要的,我本人就沒有做到這點)。想要裝的可以根據(jù)下圖指示進(jìn)行安裝。藍(lán)色選中部分就是。
    添加Google Play services SDK.png
  • AndroidStudio 1.5以上版本,最好是用最新的版本

  • 你的手機(jī)的網(wǎng)絡(luò)是翻過墻的,不然是接收不到消息推送的

2.在控制臺配置項目

與很過國內(nèi)的第三方推送集成一樣,需要在平臺上添加你的項目,獲取一些初始化需要的東西。Firebase控制臺。至于注冊賬號什么的我就不說了,我直接說項目的創(chuàng)建。

登錄控制臺后可以看到這個頁面,點擊添加項目

添加項目.png

添加項目窗口
第一步.png

創(chuàng)建好項目后,點擊項目進(jìn)入到項目的控制臺頁面。
選擇應(yīng)用類型.png

看到了這三個圖標(biāo)了嗎?我們選擇Android圖標(biāo),開始對我們現(xiàn)在的Android工程進(jìn)行關(guān)聯(lián)。這里不得不說FCM還是很強(qiáng)大的,不僅僅支持Android的推送,同樣IOS和Web的推送也支持。

關(guān)聯(lián)我們的Android應(yīng)用的步驟展示
照著頁面的輸入框進(jìn)行輸入,比較無腦。至于SHA-1碼的獲取,自己去google或者找度娘吧。

第一步.png

看圖操作。
第二步.png

這里可以直接點擊下一步,第三步主要是指示你對gradle文件進(jìn)行部分配置。這些配置我會在下面統(tǒng)一講。心急的朋友也可以按照圖中所示先進(jìn)行一些配置。
第三步.png

說一個注意點
當(dāng)我們關(guān)聯(lián)好了我們的應(yīng)用后,如果對應(yīng)用信息進(jìn)行了修改,比如SHA-1碼的修改。修改后google-services.json需要重新下載,覆蓋本地的那一份。

3.添加SDK

該準(zhǔn)備的懂準(zhǔn)備好了,現(xiàn)在開添加使用的SDK,也就是配置gradle文件。

  • project的gradle
buildscript {
    dependencies {
        // 納入 google-services 插件
        classpath 'com.google.gms:google-services:4.0.1' 
    }
}

allprojects {
    repositories {
        // Google 的 Maven 代碼庫
        google() 
    }
}
  • app的gradle
dependencies {
    implementation 'com.google.firebase:firebase-core:16.0.3'
    implementation 'com.google.firebase:firebase-messaging:17.3.1'
    // 如果使用到了FirebaseInstanceIdService類,則需要加上這行
    implementation 'com.google.firebase:firebase-iid:17.0.1'
    // 如果需要在接收消息時配合FirebaseJobDispatcher進(jìn)行耗時操作,需要加上這行
    implementation 'com.google.firebase:firebase-messaging:17.3.1'
}
// 導(dǎo)入GMS插件,這個插件就是用來解析之前復(fù)制到app項目中的google-services.json文件的
apply plugin: 'com.google.gms.google-services'

這里要注意“apply plugin: 'com.google.gms.google-services'”要添加在gradle文件的末尾,否者會報錯

Please fix the version conflict either by updating the version of the google-services plugin
(information about the latest version is available at https://bintray.com/android/android-tools/com.google.gms.google-services/) 
or updating the version of com.google.android.gms to 9.0.0.

4.編寫消息接收服務(wù)

  • 一個繼承 FirebaseMessagingService 的服務(wù)。如果您希望在后臺進(jìn)行除接收應(yīng)用通知之外的消息處理,則必須添加此服務(wù)。要在前臺應(yīng)用中接收notification或者dataMessage,同樣需要編寫此服務(wù)。這個服務(wù)的示例代碼在Demo中有。我這里簡要的貼一些主要代碼。
/**
 * FCM 消息接收服務(wù)
 * 推送分為 dataMessage(數(shù)據(jù)消息)和notification(通知消息)兩種
 * 區(qū)別在于:
 * 1.無論應(yīng)用程序位于前臺還是后臺,dataMessage(數(shù)據(jù)消息)都會在onMessageReceived()中處理。 數(shù)據(jù)消息是傳統(tǒng)上與GCM一起使用的類型。
 * 2.notification(通知消息)僅當(dāng)應(yīng)用程序位于前臺時,才會在onMessageReceived()中接收。 當(dāng)應(yīng)用程序在后臺時,將顯示自動生成的通知,不會再onMessageReceived()中接收。
 * 當(dāng)用戶點擊通知時,他們將返回到應(yīng)用程序。 包含通知和數(shù)據(jù)有效負(fù)載的消息將被視為通知消息。 Firebase控制臺始終發(fā)送通知消息。
 */
public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";
     
    /**
     * @param remoteMessage 表示從Firebase Cloud Messaging收到的消息的對象,它包含了接收到的推送的所有內(nèi)容
     */
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        Log.d(TAG, "收到推送 From: " + remoteMessage.getFrom());

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "收到推送 Message data payload: " + remoteMessage.getData());
        }

        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "收到通知 Message Notification Body: " + remoteMessage.getNotification().getBody());
        }
    }
    /**
     * 如果更新了InstanceID令牌,則調(diào)用此方法。
     * 當(dāng)先前令牌的安全性受到損害,則可能更新令牌。
     * 最初生成InstanceID令牌時也會調(diào)用此方法,因此您可以在此處檢索令牌。
     * 該回調(diào)方法可以代替Demo工程中的的MyFirebaseInstanceIDService。Demo工程中FirebaseInstanceIdService這個類也已經(jīng)被廢棄了。
     */
    @Override
    public void onNewToken(String token) {
        LogUtils.dTag(TAG, "Refreshed token: " + token);
        // 可以在這里將用戶的FCM InstanceID令牌與應(yīng)用程序維護(hù)的任何服務(wù)器端帳戶關(guān)聯(lián)起來。
        // sendRegistrationToServer(token);
    }
}

5.清單文件注冊service

<!-- 一項繼承 FirebaseMessagingService 的服務(wù)。如果您希望在后臺進(jìn)行除接收應(yīng)用通知之外的消息處理,
        則必須添加此服務(wù)。要接收前臺應(yīng)用中的通知、接收數(shù)據(jù)有效負(fù)載以及發(fā)送上行消息等,您必須繼承此服務(wù)。-->
<service android:name=".push.MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

到這里為止,經(jīng)過上面的一系列“sao操作”,就可以坐等接收消息了。下面我來介紹下怎么在控制臺發(fā)送消息

5.獲取設(shè)備注冊令牌(token/RegistionID/InstanceID)

在我們的日常開發(fā)中,這個token值一般都是需要上到自己的服務(wù)端的。這樣才能實現(xiàn)點對點的消息推送。

您的應(yīng)用初次啟動時,F(xiàn)CM SDK 會為客戶端應(yīng)用實例生成一個注冊令牌。如果您希望定位至單臺設(shè)備或創(chuàng)建設(shè)備組,則可以通過以下的3種方法去獲取token值。

  • 1.需要通過繼承 FirebaseInstanceIdService ,在對調(diào)方法中來獲取此令牌。不過在最新的SDK中,F(xiàn)irebaseInstanceIdService已經(jīng)被棄用。
    我這里還是貼一下示例代碼
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
//        sendRegistrationToServer(refreshedToken);
    }
}
  • 2.可以在繼承FirebaseMessagingService 類的onNewToken(String token)方法中得到新得token。其實也就是消息處理服務(wù)中的一個方法。
    @Override
    public void onNewToken(String token) {
        LogUtils.dTag(TAG, "Refreshed token: " + token);
        // 可以在這里將用戶的FCM InstanceID令牌與應(yīng)用程序維護(hù)的任何服務(wù)器端帳戶關(guān)聯(lián)起來。
        // sendRegistrationToServer(token);
    }
    1. 可以在你想要獲取token的地方,調(diào)用API進(jìn)行token的獲取
private void getPushToken() {
        FirebaseInstanceId.getInstance().getInstanceId()
                .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
                    @Override
                    public void onComplete(@NonNull Task<InstanceIdResult> task) {
                        if (!task.isSuccessful()) {
                            Log.e(TAG, "獲取token失敗:", task.getException());
                            return;
                        }
                        // 獲取新的token
                        String token = task.getResult().getToken();
                        // 將token上傳給服務(wù)端
                        registerDevice(token);
                    }
                });
    }

注冊令牌可能會在發(fā)生下列情況時更改:
應(yīng)用刪除實例 ID
應(yīng)用在新設(shè)備上恢復(fù)
用戶卸載/重新安裝應(yīng)用
用戶清除應(yīng)用數(shù)據(jù)

四、控制臺發(fā)送消息

下面是在控制臺發(fā)送消息的信息錄入頁面:


通知消息信息錄入頁面.png

這里有個高級選項,在高級選項中,還可以對通知標(biāo)題進(jìn)行設(shè)置,或者設(shè)置自定義數(shù)據(jù)。


image.png

五、關(guān)于FCM消息類型

在消息處理服務(wù)的代碼實例中,類備注上寫了,消息類型分為兩種。

  • 通知消息,有時被視為“顯示消息”。此類消息由 FCM SDK 自動處理。
  • 數(shù)據(jù)消息,由客戶端應(yīng)用處理。
    想要更深入的了解消息類型的話可以查看官方文檔,FCM消息類型

六、FCM使用的坑

  • App 在運行的時候,推送如果有 Notification ,一般也是我們自己去控制的,所以最終它點擊后的效果,我們是可以通過 PendingIntent 做部分定制的。

但是如果是在 App 沒有運行的情況下,就完全歸 FCM 服務(wù)幫你完成這一系列的操作,它點擊后的效果,只能將你的 App 調(diào)起,并且把你需要的參數(shù)傳遞到你的 SplashActivity(Action 為 android.intent.action.MAIN 的 Activity) 上。

public class SplashActivity extends AppCompatActivity {

    @Override 
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (getIntent().getExtras() != null) {
            for (String s : getIntent().getExtras().keySet()) {
                Log.d("SplashActivity ", s + "--" + getIntent().getExtras().get(s)); 
            // 在官網(wǎng)的發(fā)送notification 使用高級選項可以自定義 鍵值對,最終會在getIntent().getExtras()中獲取到
            }
            Intent intent = new Intent(this, MessageActivity.class);
            startActivity(intent);
        }
    }
}

所以我們就需要考慮兩種情況下,數(shù)據(jù)的傳遞已經(jīng)響應(yīng),這個是需要根據(jù)業(yè)務(wù)來討論的,空聊是沒有意義的。

  • 如果App在后臺,F(xiàn)CM的SDK默認(rèn)會幫你自動處理消息。默認(rèn)的處理形式就是幫你在系統(tǒng)通知欄彈出一個通知。就我寫帖子時,我還沒有找到如何自定義默認(rèn)通知樣式的方法。要是有哪位大大知道怎么自定義,麻煩你告訴我下。
到這里我對FCM的集成介紹也就結(jié)束了。在帖子中我沒有寫如何針對消息去進(jìn)行相應(yīng)的處理,這些處理其實是由業(yè)務(wù)決定的,所以我也沒法寫。大家要是有什么疑問也可以在評論中問我,能回答的我會回答,回答不了的我們一起探討。要是有什么意見或者建議同樣可以告訴我。
Thanks!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 有人問佛法,交代一二,佛法里邊的傻白甜也老多了,所以仙人一般不與人論佛法,都論的是毛線,達(dá)不到仙人的水準(zhǔn)!
    縱情嬉戲天地間閱讀 198評論 0 0
  • 1、微信零錢無法規(guī)避體現(xiàn)手續(xù)費。 2、word2013目錄制作。 插入目錄-設(shè)置級別;修改樣式(1意為一級目錄樣式...
    行走的螞蟻yqb閱讀 243評論 0 0
  • 在函數(shù)執(zhí)行的時候,this總是指向調(diào)用該函數(shù)的對象。要判斷this的指向,其實就是判斷this所在的函數(shù)屬于誰。 ...
    zhangjingbibibi閱讀 230評論 0 0

友情鏈接更多精彩內(nèi)容