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

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

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」區中加入

classpath 'com.google.gms:google-services:3.0.0'

成為如下所標示處:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.0.0'
        classpath 'com.google.gms:google-services:3.0.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

3. app模組層級build.gradle

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

apply plugin: 'com.google.gms.google-services'

在depencencies區中再加入

compile 'com.google.firebase:firebase-messaging:9.0.0'

成為以下標示的內容:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.google.firebase:firebase-messaging:9.0.0'
}
apply plugin: 'com.google.gms.google-services'

存檔後,請按下同步專案圖示或功能表「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方法,在方法中加入如下的程式碼:

public class MyInstanceIDService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        String token = FirebaseInstanceId.getInstance().getToken();
        Log.d("FCM", "Token:"+token);
    }
}

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

...
        <service android:name=".MyInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
    </application>
</manifest>

執行與觀察Token

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

A7013

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

相關文章:

Hank Tom

專長為程式語言、雲端服務開發,Linux系統管理, 任職:利拓科技 技術長,海林行動科技 技術總監 輔仁大學 兼任助理教授 , 為 Android高效入門>深度學習、CentOS 7建置、管理與伺服器架設實戰、Java網路程式設計、雲端網頁程式設計-Google App Engine應用實作 等書作者

This Post Has 31 Comments

  1. Avatar

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

    1. Avatar

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

      1. Avatar

        原來如此!! 多謝指教~

        不過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. Avatar

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

    1. Avatar

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

      1. Avatar

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

          1. Avatar

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

  3. Avatar

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

  4. Avatar

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

    1. Avatar

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

  5. Avatar

    您好
    我在取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. Avatar

      是的,這是因為模擬器或手機中的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. Avatar

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

        1. Avatar

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

  6. Avatar

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

    1. Avatar

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

      1. Avatar

        您好
        我實作的時候
        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. Avatar

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

          1. Avatar

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

  7. Avatar

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

    1. Avatar

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

  8. Avatar

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

    1. Avatar

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

  9. Avatar

    請問之前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. Avatar

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

  10. Avatar

    老師您好,我有買您的書,感謝您的書讓我收穫良多。
    想請教一個問題,Firebase免費方案官網上說限制100個裝置。
    他是指一個App限制100個,還是指單一個帳號呢?
    那如果超過100個後,會怎樣呢?

    1. Avatar

      你說的是”Simultaneous connections”嗎? 它時同時連接db的裝置數,是以app為主,是指同時間100個裝置連接上來。
      我沒試過,通常有稍微大一點連結需求的案子就直接使用Blaze Plan了。

      1. Avatar

        謝謝老師的回覆
        那推播功能的話就不在此限制囉?

  11. Avatar

    出現這個 是哪邊有問題
    E/FirebaseInstanceId: Token retrieval failed: RST

發佈留言

×
×

Cart