Expo+ReactNativeでプッシュ通知を活用したリマインダー機能の実装

Webサイトとアプリの大きな違いの一つはプッシュ通知です。プッシュ通知をうまく使うとユーザが離脱しにくくなります。通知は大きく2種類あります。

①ローカル通知
②リモート通知

この記事では①のローカル通知について解説します。

Expo+ReactNativeでユーザにプッシュ通知をリモートで送る

実際の動作イメージ

私が開発しているアプリでは、毎日の勉強時間を指定できる「リマインダー機能」を取り入れています。下記のように勉強する時間を入れると、

時間になると、通知が飛びます。

では実際に実装していきましょう。

必要なpackageのインストール

プッシュ通知にはexpo-notificationsを使います。

Terminal
yarn add expo-notifications

実装

ExpoのドキュメントをexpoPushTokenを取得していますが、今回の「ローカル通知」では必要ありません。expoPushTokenは「リモート通知」の時に必要になります。

setNotificationHandler

通知が飛んだ時にどのような動きにするかを決めます。細かく設定できますが、私はデフォルト通り下記で設定しています。

javascript
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true, 
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

詳細はこちらで確認ください。

権限の確認

プッシュ通知を有効にするにはユーザから許可をもらわないといけません。下記のような画面です。

ソースコード①
  const [granted, setGranted] = useState(true);
 
  useEffect(() => {
    const f = async (): Promise<void> => {
      // 現在の権限を取得
      const { status: existingStatus } = await Notifications.getPermissionsAsync();
      let finalStatus = existingStatus;  

      // grantedは「許可済み」それ以外の時は、権限をリクエストする
      if (existingStatus !== 'granted') {
        // 上の画像のメッセージが表示される
        const { status } = await Notifications.requestPermissionsAsync();
        finalStatus = status;
      }
      if (finalStatus !== 'granted') {
        // 拒否された時のフラグを取得しておく
        setGranted(false);
        return;
      }
    };

    f();
  }, []);

上記の画像の権限確認メッセージは1回しか、発火されません。ユーザーが一度拒否すると、再度requestPermissionsAsyncを発火してもメッセージは表示されません。

一度拒否した後に、プッシュ通知を有効にするには、下記画像のようにユーザに自身の端末から通知をONにする必要があります。

そのため、一番最初のrequestPermissionsAsyncを発火するタイミングは非常に大切です。みなさんも何かアプリをダウンロードした時、「通知を許可しますか?」といきなり言われたら「拒否」と押すと思います。

発火するタイミングを決めるために、色々なアプリを参考にしてみるといいでしょう。LangJournalの場合、通知メッセージを送る前に1枚下記のようが画面を挟んでおります。

スキップするを押したらrequestPermissionsAsyncを呼び出さないようにしています。1度しか発火できないメッセージは慎重に選ぶ必要があります。

拒否された時の処理

最適な場所で通知の許可メッセージを出しても拒否されるときは拒否されます。そんな場合はメッセージを出してあげるといいでしょう。先ほど載せたソースコード①のsetGrantedがfalseの時は下記のようなメッセージを出すようにしております。

リマインダーの発火

さて、最後に実際にリマインダーを発火しましょう。今回は毎日、日曜日~月曜日まで7時56分に通知を飛ばした時の実装方法です。

ソースコード②

  const scheduleNotificationAsync = useCallback(
    async (weekday: number, hour: number, minute: number) => {
      await Notifications.scheduleNotificationAsync({
        content: {
          title: '外国語日記開始時間',
          body: '今日もがんばりましょう!',
        },
        trigger: {
          weekday,
          hour,
          minute,
          repeats: true,
          channelId: 'new-emails',
        },
      });
    },
    [],
  );

  // 保存ボタンが押された時
  const onPressDone = useCallback(async () => {
    // ①まず現在設定されているスケジュールを全て削除する
    await Notifications.cancelAllScheduledNotificationsAsync();

    // 日~月まで7:56に設定する場合
    await Promise.all(
      [1, 2, 3, 4, 5, 6, 7].map(async (item) => {
        await scheduleNotificationAsync(item, 7, 56);
      }),
    );
  }, [scheduleNotificationAsync]);

実際に、実装するときは「曜日」や「時間」はユーザが設定できるようにするといいでしょう。

以上です。

Expo+ReactNativeでユーザにプッシュ通知をリモートで送る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です