ITと筋トレの二刀流

未だゼロ刀流

ReactNative+ExpoでAndroid端末へプッシュ通知を送る その①〜Expo プッシュトークンの取得〜

f:id:tatsuyashi:20190214235559p:plain:w300

Expoを使用して開発するReactNativeアプリから各端末へプッシュ通知を送る仕組みを入れたいと思います。

私の端末はAndroidなのでまずはAndroid端末へ送れるようにしたのですが、途中試行錯誤したのでやり方を載せたいと思います。

Android向けの説明になりますが、iOSの方も途中までは参考にしていただけます。 iOSだともう少し手間なくできるかも?です。(未検証)

バージョン

[アプリケーション]

・create-react-native-app:2.0.2

・Expo CLI:2.4.0

・React Native SDK:31.0.0

後は今回の記事に関係しないので割愛。

[端末]

Xperia XZ1 (Android 9 Pie)

準備

プッシュ通知の確認は実機ベースが必須なので、GooglePlayよりExpoアプリをインストールしておいてください。

play.google.com

開発手順

プライベートなリポジトリで開発しているためソースは断片的にしか公開できませんので、簡単に開発手順をまとめます。

Expo CLIを使ってプロジェクト作れる方は飛ばしてもらってもOKです。

create-react-native-app インストール

npm install -g create-react-native-app

私と同じバージョンで始める場合は、

npm install -g create-react-native-app@2.0.2

Expo CLI インストール

npm install -g expo-cli

私と同じバージョンで始める場合は、

npm install -g expo-cli@2.4.0

React Nativeプロジェクト作成

create-react-native-app [your-project-name]

これでプロジェクトが作成されます。

アプリ起動

expo start

npm start ではなくexpoコマンドで起動します。

起動すると、localhost:19002でブラウザが自動で起動します。

↓こんな感じ

f:id:tatsuyashi:20190215003026p:plain:w500

ここに表示されるQRコードスマホ端末でExpoアプリを使ってスキャンすると、スマホ上にアプリがロードされます。(ここまでがアプリの初期セットアップ)

Push通知の手順

公式ドキュメントの内容をまとめると、

  1. Expoからプッシュトークンを取得する
  2. プッシュトークンを自分のサーバで保管する(ユーザ情報と紐付けておく)
  3. プッシュ通知を行うアクションが発生した際に、自分のサーバからExpoのプッシュ通知用のAPIをコールする(この際にプッシュトークンを使う)
  4. Expoが各端末へプッシュ通知を送る(OSのハンドリングはExpo側で行う)
  5. フォアグラウンドにあると通知が表示されないので、表示するようにハンドリングする(iOS用?)

読む限り、1でプッシュトークンが取得できれば、後はAPIを呼び出すだけのような気がします。

プッシュトークンの取得

先ほどの公式サイトにあるサンプルコードを真似てみます。

下記のコード(関数)をApp.jsに追加します。念のためtry-catchします。

import { Permissions, Notifications } from 'expo';

〜〜

async function registerForPushNotificationsAsync() {
  try {
    const { status: existingStatus } = await Permissions.getAsync(
      Permissions.NOTIFICATIONS
    );
    let finalStatus = existingStatus;

    // only ask if permissions have not already been determined, because
    // iOS won't necessarily prompt the user a second time.
    if (existingStatus !== 'granted') {
      // Android remote notification permissions are granted during the app
      // install, so this will only ask on iOS
      const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
      finalStatus = status;
    }

    // Stop here if the user did not grant permissions
    if (finalStatus !== 'granted') {
      return;
    }

    // Get the token that uniquely identifies this device
    let token = await Notifications.getExpoPushTokenAsync();

    console.log(token);
  } catch (e) {
    console.error(e);
  }
}

App.jsの初期処理で呼び出すようにします。

export default class App extends React.Component {
  
  componentDidMount() {
    registerForPushNotificationsAsync();
  }
  
  render() {
    ...
  }
}

ここまでは下記のブログを参考にさせていただいたので、これで動くと思っていました。

qiita.com

ですが!!

これでアプリを起動すると、、

Error: Couldn't get GCM token for device

なにやらエラーになりました。

どうもGCM(Google Cloud Messaging)が廃止され、FCM(Firebase Clound Messaging)へ移行しろっていう流れがあるらしいので、それに関連したエラーっぽいです。

Error: Couldn't get GCM token for device の対応

色々調べたのですが、公式ドキュメントに下記の記載があるのを見落としていました。

f:id:tatsuyashi:20190215005944p:plain:w500

要約すると、

「FCMのサーバーキーをExpoに送ってくれないとExpoからプッシュ通知できなくなったんだ。こっちのページにFirebaseプロジェクトの作り方を書いたからそれを見てFCMサーバーキーの取得してExpoに送ってくれ。」

みたいなことを言ってます。

こちらに手順が書いてあるので、その通り進めていくことにします。

Firebaseプロジェクトの作成

Firebaseプロジェクトを作成していない方はFirebaseコンソールからプロジェクトを作成します。

https://console.firebase.google.com/

[+]プロジェクトを追加 を押します。 f:id:tatsuyashi:20190215010834p:plain:w400

プロジェクト名を入力、地域/ロケーションを日本/asia-northeast1に変更してプロジェクトを作成します。

f:id:tatsuyashi:20190215011047p:plain:w400

androidパッケージの決定

※これは公式ドキュメントには書かれていません。

この後の手順でandroidパッケージが必要になります。

これはアプリの開発元やアプリ名に依存しますので、各自で決定お願いします。

com.[your company].[your app name]

みたいな感じでしょうか。

決定しましたら、app.jsonに下記の記載を追加します。

  "android": {
    "package": "[your android package]"
  }

既に "android"がある場合は、その中にpackageを追記します。

  "android": {
    "hoge": "fuga",
→"package": "[your android package]" 
  }

FirebaseへAndroidアプリの追加

Firebaseコンソール画面で[Android アプリに Firebase を追加] をクリックするとアプリの登録画面が開きます。

f:id:tatsuyashi:20190215012625p:plain:w400

ここに先ほど決定したandroidパッケージを入力して、[アプリを登録]します。

google-services.jsonのダウンロードと配置

アプリ登録が終わるとgoogle-services.json をダウンロードできるようになるのでダウンロードします。

f:id:tatsuyashi:20190215012949p:plain:w400

ダウンロードしたgoogle-services.jsonはプロジェクト直下に配置します。

/
 App.js
 app.json
 google-services.json

app.jsonに設定を追記します。

  "android": {
    ....,
    "googleServicesFile": "./google-services.json"
  }

あともう少しです。

FCMサーバーキーの取得

Firebaseコンソールで[Project Overview の右の歯車] → [プロジェクトの設定] を押します。

f:id:tatsuyashi:20190215013817p:plain:w400

[クラウドメッセージング]タブを開くとサーバーキーが表示されているので、コピーします。

f:id:tatsuyashi:20190215014029p:plain:w500

ExpoへFCMサーバーキーの登録

最後にExpoへコピーしたサーバーキーを登録します。expoコマンドを使います。

expo push:android:upload --api-key <your-token-here>

途中でExpoのアカウント登録を要求されるので登録します。 登録後メールでverifyするとアカウント作成されます。

以上で必要な手順は終わりです。

プッシュ通知のテスト

ここまで来ると先ほどアプリ起動で出ていたエラーは出なくなり、以下のようなプッシュトークンがログに出力されると思います。

ExponentPushToken[xxxxxxx]

これをExponentから全てコピーします。

プッシュ通知は本来であればExpoのAPIを使用するのですが、下記のダッシュボード画面からプッシュ通知を送ることができます。

expo.io

プッシュトークンとタイトルと本文を入力し [Send a notification]をクリックします。

f:id:tatsuyashi:20190215014923p:plain:w500

すると、

f:id:tatsuyashi:20190215015215p:plain:w400

スマホ側にプッシュ通知が届きました!

まとめ

いかがだったでしょうか?
基本的にはExpoが提供するサンプルコードでプッシュトークンは取得できるのですが、以前は起こらなかったGCMのエラーが出るようになっているので今回記載したようにFirebaseプロジェクトを作成する必要が出てきています。

この後はAWS Lambda経由で実際にExpoのAPIをコールしてみたいと思いますので、また実現できたら書こうと思います。