Android
Firebase
AWS-SNS
FCM
awssns

Android 開発初心者が SNS + Firebase でPush通知をとりあえず送って見ようとした時に躓いたこと

基本はAndroid端末で、FCM経由でAWSSNSを受け取るまでをなぞった時の奮闘記です。感謝。
バージョンは、 Android 7.0、 API 24。

Push 通知はエミュレータでできるか心配だったけど、この記事の範囲内では問題なかった。

読んでて疑問だったこと (解決はしてない)

  1. Android package nameにSNSをアプリのパッケージ名を入力する

SNS 関係なさそう

  1. push Platform NotificationでGoogle Cloud Messaging(GCM)を選択する
  2. API Keyにコピーした「Legacy server key」を貼り付け、Create platform applicationをクリックする

なんで Legacy なんやろ... なんで GCM なんやろ...

build すると xml でエラー出ちゃう

サンプルなどにある、下記の XML を Manifest.xml に追加するとビルド時にエラーが出ちゃってとっても困った。

<service android:name=".MyFirebaseMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

結論としては、自分は階層を間違えていて、正解は application の中の層に書く。

 <manifest ... >
     <application ... >

......

+        <service android:name=".MyFirebaseMessagingService">
+            <intent-filter>
+                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
+            </intent-filter>
+        </service>
     </application>

     <uses-permission android:name="android.permission.INTERNET" />
 </manifest>

まあ考えれば当たり前なんですけど、手探りで作業して全体像がボヤーっとしてると間違えたままになっちゃったりとか、ありません?

ちなみに端折ったんでしけど、 service はトークン取得のためにもう一個書いている。

エミュレータでFirebase の token 取れない

何やらエラーが出るので、 firebase のトークン取得を下記のように書いていたら、 token is null だった。

        String token = FirebaseInstanceId.getInstance().getToken();
        if (token == null) {
            Log.d(TAG, "token is null.");
        } else {
            sendRegistrationToServer(token);
        }

エミュレータがインターネッツに繋がってない場合があるので、再起動すると治った
https://stackoverflow.com/questions/37517860/how-to-handle-firebaseinstanceid-getinstance-gettoken-null

適当なところで onTokenRefresh を呼び出してもエラーで落ちる

onRefreshToken がどのタイミングで呼ばれるかよく分からなかっため、起動時に通過する Activityから強制的に呼び出してみました。エラーが出たので } catch (Exception ex) { したら、 ex.getMessage() には何も入ってなかったんですが、 ex.getClass() すると NetworkOnMainThreadException が出てきました。これはなんか聞いたことがあったなと思って調べたら、「メインスレッドで HTTP 通信するな」っていうやつです。つまるところ、自分の場合は「適当なところで」というのが適当すぎて不適切でした。

public class MyFirebaseSnsRegistrationService extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        MyFirebaseInstanceIdService service = new MyFirebaseInstanceIdService();
        service.onTokenRefresh();
        return "";
    }
}

こんな非同期クラスを書いて、これを Activity から呼び出してやると、SNS への同期が完了しました。

メッセージの受け取りはまだ実装していないのですが、 SNS のコンソールからテストメッセージを送信してみたところ、無事ログには FCM からのメッセージの受信が出ました。流れは理解できたような気がします。