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)皿哨,后者繼承了可靠且可擴展的GCM基礎(chǔ)架構(gòu)以及許多新功能。
簡明的說就是FCM是GCM的升級版纽谒。

Firebase提供了很多服務(wù)证膨,包含但不限于認證、通知鼓黔、分析央勒、AdMod、性能監(jiān)控等澳化。這里我們只對通知進行集成订歪。

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

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

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

現(xiàn)在Android系統(tǒng)對后臺進行的管理越來越嚴格,各種定制系統(tǒng)也對后臺進程進行了各種各樣的限制刀疙〔芭猓基本上APP被殺死后,基本都收不到消息推送了∏恚現(xiàn)在的國內(nèi)第三方推送也想了各種辦法去處理殺死進程后收不到推送的問題竟纳,但是效果都不是很好撵溃。

為啥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)因為墻的存在導致了我們需要去選用各種第三方的推送垃沦。在這期盼哪天Google回歸大陸吧。

嘰嘰歪歪這么多現(xià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是有前提條件的,也就是因為這些前提條件導致的境內(nèi)項目無法正常的使用Google提供的服務(wù)缎讼。

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

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

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

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

2.在控制臺配置項目

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

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

添加項目.png

添加項目窗口
第一步.png

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

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

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

第一步.png

看圖操作困鸥。
第二步.png

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

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

3.添加SDK

該準備的懂準備好了,現(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進行耗時操作撇叁,需要加上這行
    implementation 'com.google.firebase:firebase-messaging:17.3.1'
}
// 導入GMS插件,這個插件就是用來解析之前復制到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ù)陨闹。如果您希望在后臺進行除接收應(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(通知消息)僅當應(yīng)用程序位于前臺時椭蹄,才會在onMessageReceived()中接收。 當應(yīng)用程序在后臺時净赴,將顯示自動生成的通知绳矩,不會再onMessageReceived()中接收。
 * 當用戶點擊通知時玖翅,他們將返回到應(yīng)用程序翼馆。 包含通知和數(shù)據(jù)有效負載的消息將被視為通知消息。 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)用此方法猜极。
     * 當先前令牌的安全性受到損害中姜,則可能更新令牌。
     * 最初生成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)用程序維護的任何服務(wù)器端帳戶關(guān)聯(lián)起來嗜桌。
        // sendRegistrationToServer(token);
    }
}

5.清單文件注冊service

<!-- 一項繼承 FirebaseMessagingService 的服務(wù)。如果您希望在后臺進行除接收應(yīng)用通知之外的消息處理辞色,
        則必須添加此服務(wù)骨宠。要接收前臺應(yīng)用中的通知、接收數(shù)據(jù)有效負載以及發(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)用程序維護的任何服務(wù)器端帳戶關(guān)聯(lián)起來重父。
        // sendRegistrationToServer(token);
    }
    1. 可以在你想要獲取token的地方,調(diào)用API進行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è)備上恢復
用戶卸載/重新安裝應(yīng)用
用戶清除應(yīng)用數(shù)據(jù)

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

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


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

這里有個高級選項,在高級選項中脉幢,還可以對通知標題進行設(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默認會幫你自動處理消息租副。默認的處理形式就是幫你在系統(tǒng)通知欄彈出一個通知坐慰。就我寫帖子時,我還沒有找到如何自定義默認通知樣式的方法。要是有哪位大大知道怎么自定義结胀,麻煩你告訴我下赞咙。
到這里我對FCM的集成介紹也就結(jié)束了。在帖子中我沒有寫如何針對消息去進行相應(yīng)的處理糟港,這些處理其實是由業(yè)務(wù)決定的攀操,所以我也沒法寫。大家要是有什么疑問也可以在評論中問我秸抚,能回答的我會回答速和,回答不了的我們一起探討。要是有什么意見或者建議同樣可以告訴我剥汤。
Thanks颠放!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吭敢,隨后出現(xiàn)的幾起案子碰凶,更是在濱河造成了極大的恐慌,老刑警劉巖鹿驼,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欲低,死亡現(xiàn)場離奇詭異,居然都是意外死亡畜晰,警方通過查閱死者的電腦和手機砾莱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來舷蟀,“玉大人恤磷,你說我怎么就攤上這事∫耙耍” “怎么了扫步?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匈子。 經(jīng)常有香客問我河胎,道長,這世上最難降的妖魔是什么虎敦? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任游岳,我火速辦了婚禮,結(jié)果婚禮上其徙,老公的妹妹穿的比我還像新娘胚迫。我一直安慰自己,他們只是感情好唾那,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布访锻。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪期犬。 梳的紋絲不亂的頭發(fā)上河哑,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音龟虎,去河邊找鬼璃谨。 笑死,一個胖子當著我的面吹牛鲤妥,可吹牛的內(nèi)容都是我干的佳吞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼棉安,長吁一口氣:“原來是場噩夢啊……” “哼容达!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起垂券,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤花盐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后菇爪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體算芯,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年凳宙,在試婚紗的時候發(fā)現(xiàn)自己被綠了熙揍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡氏涩,死狀恐怖届囚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情是尖,我是刑警寧澤意系,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站饺汹,受9級特大地震影響蛔添,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兜辞,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一迎瞧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧逸吵,春花似錦凶硅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽压语。三九已至,卻和暖如春编检,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扰才。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工允懂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人衩匣。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓蕾总,卻偏偏與公主長得像,于是被迫代替她去往敵國和親琅捏。 傳聞我的和親對象是個殘疾皇子生百,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

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