React Nativeとプッシュ通知 (Android編)

React Nativeでプッシュ通知を受信する実装について調べたのでまとめておきます。

ここでは下図のような通知を送ることを想定します。

f:id:gibachan03:20200813200009p:plain:w200

環境

  • node: 14.5.0
  • yarn: 1.22.4
  • react-native 0.63.2
  • @react-native-firebase/app 8.3.0
  • @react-native-firebase/messaging 7.6.1

プッシュ通知はFirebase Cloud Messagingから送信することを前提としています。Expoは利用しません。 基本的にはこのドキュメントに従って実装すれば大丈夫です。

React Nativeプロジェクトの作成

ここでは最初にAndroidを実装し、その後でiOSに対応していきます。 それぞれのアプリのパッケージ名/バンドルIDを以下のように決めておきます。

  • Android パッケージ名: com.example.rn_push_notification.android
  • iOS バンドルID: com.example.rn-push-notification.ios

まず最初に下記のコマンドでプロジェクトを新規作成します。(--template を指定していますがそこはお好みで)

npx react-native init RNPushNotification --template react-native-template-typescript

作成されるプロジェクトのパッケージ名/バンドルIDは、デフォルトでcom.rnpushnotification のようになっているので、それらを上記に変更します。

iOSの場合は open ios/RNPushNotification.xcworkspace/ とし、Xcode上で簡単に変更できます。 一方、Androidの場合はいろいろ変更する場所があるのでこちらの記事を参考にガンバリます。

それぞれ変更した後にビルドが通るか確認しておくと安心だと思います。

Firebaseプロジェクトの準備

最初にFirebaseコンソール で新しいプロジェクトを作成します。

f:id:gibachan03:20200810203343p:plain:w300

プロジェクトにAndroidアプリを追加します。パッケージ名には先ほど設定したものを入力しておきます。

f:id:gibachan03:20200810210712p:plain:w300

その後google-services.jsonをダウンロードしておき、その他の画面に表示される指示(ネイティブ実装用の作業)はパスして大丈夫です。

Androidのセットアップ

以下の設定はドキュメントに従ってセットアップしていきます。

先ほどダウンロードしたgoogle-services.json/android/appに配置します。

そして/android/build.gradleに下記を追加し、

buildscript {
    ...
    dependencies {
        ...
        classpath 'com.google.gms:google-services:4.3.3' // これを追加
    }
}

/android/app/build.gradleに下記を追加します。

apply plugin: 'com.google.gms.google-services' // これを追加

Firebaseモジュールをインストール

コンソール上で下記のコマンドを実行します。

yarn add @react-native-firebase/app
yarn add @react-native-firebase/messaging

cd ios/ && pod install    # これはiOSのために必要

通知のトピックを購読する

通知を受信するために特定のトピックを購読します。 App.tsxを開き、簡略化のために不要なコードを削除しつつ次のように編集します。

import React, {useEffect} from 'react';
import {View, Text, StyleSheet} from 'react-native';
import messaging from '@react-native-firebase/messaging'; // これを追加する

const App = () => {
  useEffect(() => {
    // `wether`トピックを購読
    messaging()
      .subscribeToTopic('weather')
      .then(() => console.log('Subscribed to topic!'));
  }, []);

  return (
    <View style={styles.container}>
      <Text>Hello world</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default App;

これでプッシュ通知を受信できるようになりました。

次にアプリがバックグラウンドにある時に通知を受信した際に呼ばれるコールバックを設定します。 index.tsxを編集します。

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import messaging from '@react-native-firebase/messaging'; // これを追加する

// バックグラウンドで通知を受信した時のコールバック
messaging().setBackgroundMessageHandler(async (remoteMessage) => {
  `[${remoteMessage.notification?.title}]を受信しました`;
});

AppRegistry.registerComponent(appName, () => App);

プッシュ通知を送信

コンソールで下記コマンドからandroidアプリを起動します。

yarn run android

アプリをバックグランドに隠しておきます。 FirebaseコンソールにてCloud Messagingを開き、新しい通知を作成します。

下図のようにタイトルなどを入力して[次へ]進みます。

f:id:gibachan03:20200810220716p:plain:w300

送信先のターゲットとして先ほど設定したトピックを指定します。

f:id:gibachan03:20200810220403p:plain:w300

そのまま送信すると、通知を受信できます。

f:id:gibachan03:20200810220817p:plain:w300

ここまでで通知を受信するための最低限の実装ができました。

処理を追加

これだけだと寂しいので少し処理を追加します。

受信した通知をタップするとアプリが開かれますが、それを検知するためのコードを追加します。 App.tsxを編集し、下記のコールバックを追加します。(アプリがバックグラウンドで実行中か終了しているかによって分かれています)

...
const App = () => {
  const [message, setMessage] = useState('まだ通知を受信していません');

  useEffect(() => {
    // `wether`トピックを購読
    ...

    // アプリがバックグラウンドで実行中に通知をタップされたときのコールバック
    messaging().onNotificationOpenedApp((remoteMessage) => {
      setMessage(
        `[${remoteMessage.notification?.title}]によってバックグラウンドから復帰しました`,
      );
    });

    // 通知をタップしてアプリが起動されたときのコールバック
    messaging()
      .getInitialNotification()
      .then((remoteMessage) => {
        if (remoteMessage) {
          setMessage(
            `[${remoteMessage.notification?.title}]によって起動されました`,
          );
        }
      });
  }, []);

  return (
    <View style={styles.container}>
      <Text>{message}</Text>
    </View>
  );
};

f:id:gibachan03:20200813200539p:plain:w300

まとめ

Androidの場合はFCMと相性が良く、特に面倒な事なく実装できました。 次回はiOSでの実装について書く予定です。

ここまでの実装についてはGitHubに上げています。

github.com