Firebase雲端訊息-Android專案導入環境建置與Instance ID

作者 | 2016-06-24

Firebase Cloud Messaging

2016年的Google IO開發者大會上,Google發表了新版的Firebase,其中最具亮點的一項新功能就是「Firebase Cloud Messaging」雲端訊息,簡稱FCM,更令人感到興奮的是,FCM是為了要取代服務已久的Google Cloud Messaging,GCM,成為未來Google雲端訊息的新平台。

FCM擁有GCM沒有的網頁主控介面,它是基於GCM所開發出的擴充功能,原本使用GCM的APP也能夠快速導入原GCM雲端專案,並在修改APP後即能支援新的FCM。我們在上一篇文章中所產生的APP專案FireChat,即是一個導入GCM一半功能的專案,由此開始,將開始使用FCM,開發一個具有雲端訊息功能的APP。

本文章使用軟體版本:

Android Studio 2.1.2, Android 6.0

JDK 1.8.0

專案環境準備

在Android Studio中新增一個新專案Chatroom,如圖:

A7002

最低Android版本請選擇4.1,如下:

A7003

再選擇建立空白活動(Empty Activity)即可,專案建立完成後,請點擊最右方顯示Gradle視窗,再連擊以執行「Chatroom/Chatroom/Tasks/android/signingReport」,如下圖:

A7007

執行完成後,在下方輸出執行結果中,請先複製SHA1的指紋碼,如下:

A7008

Firebase專案建立與申請

到Firebase首頁(http://firebase.google.com),建立雲端專案,如下圖:

A7004

新增一個Firebase雲端專案Chatroom,位置設定為Taiwan(台灣)後,建立專案,如下圖:

A7006

在專案總覽頁面,點擊開始導入到Android,如下圖:

A7009

填入剛才建立Android專案所設定的package名稱,如「com.litto.chatroom」,再將複製好的指紋碼點在下方,完成後按下「ADD APP」加入Android APP,如下圖:

A7010

上一步驟會自動產生「google-services.json」,先存取在本機中,請先複製該檔案,並完成Firebase專案的步驟。

Android專案的設定

1. 加入google-services.json檔

回到Android Studio中,將左方專案區切換至「Project」後,再展開app資料夾,貼上剛才複製的「google-services.json」檔,如下圖:

A7014

2. 專案層級build.gradle

將專案區切換回「Android」後,開啟「Gradle Scripts」下的「build.gradle(Project: Chatroom)」,在「dependencies」區中加入

成為如下所標示處:

3. app模組層級build.gradle

再開啟「Gradle Scripts」下的「build.gradle(Module: app)」,在檔案的最尾端加入

在depencencies區中再加入

成為以下標示的內容:

存檔後,請按下同步專案圖示或功能表「Tools/Android/Sync Project with Gradle Files」。

2016/7/17 added

有朋友反應執行時出現com.google.firebase.auth.FirebaseAuth is not linked. Skipping initialization,或是Firebase API initialization failure的錯誤。經查應該是sdk中使用的版本比較新,而Firebase訊息類別庫不相容,請將上一步驟的版本改為9.0.2後(如下),Sync Project後再試看看。
compile ‘com.google.firebase:firebase-messaging:9.0.2’

取得Instance ID API的Token

當Android裝置開機並連上網路時,會自動向Google雲端註冊並取得每個裝置的實例ID,稱為「Instance ID」,使用的是InstanceID API標準規範,有關Instance ID再另找時間詳述,依此標準可取得裝置的辨識符記,稱為「Token」,如下圖紅色箭頭。

FCM-1

當取得Token後,並不保證它永遠是可用的,有時會因為一些安全機制或APP的Instance ID被強制刪除後,會重新發送新的Token。在實作時,設計一個繼承「FirebaseInstanceIdService」的新類別,由類別名稱很容易可以猜到它的用途,使用它可透過Firebase所設計的機制取得Instance ID,再由這個ID取得配發的Token。

請在Android專案中的app/java/套件名稱目錄下,新增一個類別(File/New/Class),取一個讓自己容易辨識的類別名稱,如「MyInstanceIDService」,請手動加入繼承FirebaseInstanceIdService類別宣告後,再按下Ctrl+O覆寫onTokenRefresh方法,在方法中加入如下的程式碼:

因為父類別FirebaseInstanceIdService是一個服務元件(Service),因此必須在AndroidManifest.xml中註冊本類別,如下:

執行與觀察Token

在APP執行後收到Instance ID後會自動執行我們所加入的MyInstanceIDService內的onTokenRefresh方法,並印出如上的log訊息,此步驟代表我們的APP能夠與Google雲端註冊裝置,成功回傳Instance ID,並由Instance ID API中取得Token符記,如下圖:

A7013

取得Token是實作雲端訊息的第一步,之後會依不同需求,設計不同的架構或功能,例如,將Token傳遞至伺服器端儲存後,可實作聊天室APP,若能結合帳號、群組、好友關係,就能再實作出如LINE、WhatsApp這類有朋友關係的即時訊息需求的APP。

相關文章:

使用Facebook直接回應

27 thoughts on “Firebase雲端訊息-Android專案導入環境建置與Instance ID

  1. Rein

    請問FCM 如何傳遞圖片 (自訂icon 或是 大圖)。若還不支援,FCM 與GCM可以並用嗎?

    回覆
    1. Hank Tom 文章作者

      GCM, FCM都不直接傳圖,而是將圖的URL資訊傳入APP後,再由APP自行去取圖回來成為Bitmap物件。
      並用倒沒試過,依其設計來看是可以的。

      回覆
      1. Rein

        原來如此!! 多謝指教~

        不過GCM原本的做法,在GCMIntentService, onMessage(Context context, Intent intent )
        可以從Intent 取出 getString(“image”)
        再將String 以Bitmap decodeImage的方式,轉成bitmap,達到推播傳圖的功能,以此來變更notification icon.

        不過按照您的建議,推播(FCM or GCM)將url傳入app後,再以可能是glide SDK或httpurlconnection SDK的方式將圖片取回app,在發出notification。這看起來比較能夠降低網路流量,對 GCM伺服器負擔較小。

        多謝您的提示~

        回覆
  2. Eric

    您好,不好意思有些問題想要請教您:
    “當Android裝置開機並連上網路時,會自動向Google雲端註冊並取得每個裝置的實例ID”
    這部分我有點不太懂意思
    因為我最後執行程式的時候
    我在console那邊找不到我的Token符記
    不知道是不是與這部分有關

    回覆
    1. Hank Tom 文章作者

      InstanceID API是透過手機中的Google Play Services完成的,有Instance ID才會取得到Token,而APP需要有正確的google-services.json檔才能與Google Play Services溝通,所以,也可能是申請的設定檔有誤,或手機上的Google Play Services版本等問題。

      回覆
      1. Eric

        謝謝您撥冗解答我的問題
        不好意思想再請教您一下
        那假如是手機上Google Play Services版本問題的話
        該如何做才能解決呢

        回覆
          1. Eric

            我知道了
            謝謝您的解答,麻煩您了:)

  3. Ryan

    您好
    好奇Instance ID是何原理產生的
    似乎不是透過IMEI
    謝謝

    回覆
  4. Jam

    請問一下我照著上面的步驟做了
    為何會產生”com.google.firebase.auth.FirebaseAuth is not linked. Skipping initialization” 的訊息呢?
    我用Genymotion模擬器會不會有影響

    回覆
    1. Hank Tom 文章作者

      可能是sdk中的google play services版本是新的,可能是最近更新,而firebase:messaging要配合用9.0.2,請參考文章中加註的方式後,試看看。
      btw, 應該是與Genymotion無關。

      回覆
  5. J.R Smith

    您好
    我在取Token的時候
    發生了這個錯誤
    Bad activity token: android.os.BinderProxy@2fdb5c4
    java.lang.ClassCastException: android.os.BinderProxy cannot be cast to com.android.server.am.ActivityRecord$Token

    請問這是跟開發環境的版本有關的錯誤嗎
    也有看到有人說這是android某些版本的bug
    因為上網找沒有找到確切的解決辦法
    想在此請教您
    謝謝:)

    回覆
    1. Hank Tom 文章作者

      是的,這是因為模擬器或手機中的Google Play Services版本與 build.gradle中的dependencies區塊中
      compile ‘com.google.firebase:firebase-messaging:9.0.0’ 的類別版本對不起來。
      由於Firebase最近更新版本很快,目前到9.2.1了,如果你的模擬器是最近才更新的,可以試著將上一行換成:
      9.0.2或9.2.1等版本試看看。
      等過一陣子應該就不會這麼亂了。

      回覆
      1. J.R Smith

        您好
        謝謝您的回答
        我把版本換過了
        但是錯誤訊息變成這樣
        E/CommitToConfigurationOperation: Malformed snapshot token (size):

        回覆
        1. Hank Tom 文章作者

          可以提供較詳細的資料嗎? 如LogCat上下文、所有的Exception Trace Stack,出錯的程式碼所在處。有build.gradle會比較好找問題。

          回覆
  6. Paul

    請問一下
    firebase版本如果現在出到9.2.1的話
    我的手機上的google play服務版本是9.4.52
    執行的時候版本好像對不起來
    導致程式沒辦法順利執行
    這樣也是版本上的bug嗎

    回覆
    1. Hank Tom 文章作者

      若是版本不對的問題時,LogCat會有特定的訊息,確切的訊息我忘了,要看到完整的訊息才能判斷。

      回覆
      1. Paul

        您好
        我實作的時候
        log跑出了以下這些紅色訊息

        E/NetdConnector: Error handling ‘613 IfaceClass idle (null)’: java.lang.NumberFormatException: Invalid int: “(null)”

        E/GoogleTagManager: Invalid macro: _gtm.loadEventEnabled

        E/GooglePlayServicesUtil: The Google Play services resources were not found. Check your project configuration to ensure that the resources are included.

        E/GoogleTagManager: Invalid macro: _gtm.loadEventEnabled

        不知道這些是不是跟版本的問題有關

        回覆
        1. Hank Tom 文章作者

          上述的”The Google Play services …” 是Google的bug,可以忽略它,其他的看不出問題。
          請問app執行有終止嗎? 是正常執行,但LogCat出現錯誤?
          如果是練習的專案,可以放到Github上,我再去clone下來看看。

          回覆
          1. Paul

            您好
            謝謝您的幫忙
            之前app不會終止
            但我試了改幾次版本後已經解決問題了
            謝謝您幫了我許多

  7. Sam

    您好
    不好意思
    想請問您該如何將取到的Token回傳給伺服器端儲存

    回覆
    1. Hank Tom 文章作者

      有很多種方法,寫一個Server端的HTTP程式,用PHP、ASP、ROR或JSP等,再從Android端寫HTTP網路連線程式送過去後台儲存。

      回覆
  8. Tang

    不好意思
    想請教一下
    我想要將使用者手機的token回傳給伺服器端的資料庫儲存
    請問我該如何做呢

    回覆
    1. Hank Tom 文章作者

      有很多種方法,寫一個Server端的HTTP程式,用PHP、ASP、ROR或JSP等,再從Android端寫HTTP網路連線程式送過去後台儲存。

      回覆
  9. yatin

    請問之前GCM 後端會因某事件成立送推播 會另寫隻程式,改成FCM也有這嗎?!

    //準備對GCM Server發出Http post
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(“https://android.googleapis.com/gcm/send”);
    //HttpWebRequest request = (HttpWebRequest)WebRequest.Create(“https://fcm.googleapis.com/fcm/send”);
    request.Method = “POST”;
    request.ContentType = “application/json;charset=utf-8;”;
    request.Headers.Add(string.Format(“Authorization: key={0}”, API_Key));
    request.Timeout = 20000;

    回覆
    1. Hank Tom 文章作者

      GCM後端的事件是需要自行實作的,例如Listener Servlet或其他監控程式,事件符合後再自行設計推播功能。
      但FCM目前推出的Functions,是一個能傾聽Firebase Database內的資料,並實作出自動推播的功能(還有其他很多應用),使用Node.js開發後再佈署,非常的方便。
      https://firebase.google.com/docs/functions/

      回覆

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *