🔔

[OneSignal Flutter]OneSignalでPush通知をタップしたときに特定のページに遷移する

2024/04/11に公開

はじめに

自分はSupabaseのテーブル変更→OneSignalでPush通知を送る。というようにPush通知を使っているのですが、Push通知をタップしたときにFlutterで特定の動作を行うようにしたいなぁと思い実際に実装してみたのでその流れを書きます。どう考えたかも一応付け加えておきます。日本語での情報は見当たらなかったので役に立つといいなぁと思います。

書かないこと

・OneSignalの諸々とExternal IDについて
・Supabaseの諸々について
・Flutterの諸々について

バージョン

onesignal_flutter: ^5.0.3

結論

バックエンドでOneSignalに送るデータ

workers.js
// 送信する通知のデータ
  const notificationData = {
    app_id: appId, // OneSignalのアプリID
    contents: { en: ` ${likesUserName} liked your submission!`, ja: `${likesUserName}があなたの投稿をいいねしました` },
    headings: { en: "app name", ja: "アプリ名" },
    target_channel: 'push',
    include_aliases: {"externalId": [externalIds]},// External IDの配列を指定
    data:{"action": "like","imageId": imageId}, //この部分を追加する。
  };

Flutter側でのコード

on_tap_push.dart
Future<void> onTapPushNotification() async{
    OneSignal.Notifications.addClickListener((event) {
      final additionalData = event.notification.additionalData;
      //ここで特定の動作を行う。今回はDisplayPageに飛ばす。
      //additionalDataがnotificationDataにおけるdataに対応する。
      if (additionalData!["action"] == "like") {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DisplayPage(
              imageId: additionalData["imageId"],
            ),
          ),
        );
      }
      //actionによって動作を変える

    });
  }

アプリ起動時に読み込む

アプリの流れについて

1:ユーザーが特定の投稿をいいねする
2:Supabaseのテーブルが変更される
3:SupabaseのWebhooksによりCloudflare Workersで処理が行われる
4:OneSignal
5:デバイスにPush通知が届く
6:それをタップするといいねされた投稿のページに飛ぶ(Flutter)。

という流れです。詳しくは書きませんが以下のようなものを使っています。

2→3:SupabaseからCloudflare Workersに情報を移すにはSupabaseのWebhooks。
3→4→5:ユーザーの情報を管理する際にOneSignalのExternal ID。

2までは省略して、3から書きたいと思います。

3-4: Workers(バックエンド)とOneSignal

今回自分はFlutterを使っています。OneSignalには以下のパッケージがあり、ここのExampleにいいの無いかなぁということで探してみます。
https://pub.dev/packages/onesignal_flutter/example
ChatGPTにも聞くと、

OneSignal.Notifications.addClickListener((event) {
      print('NOTIFICATION CLICK LISTENER CALLED WITH EVENT: $event');
      this.setState(() {
        _debugLabelString =
            "Clicked notification: \n${event.notification.jsonRepresentation().replaceAll("\\n", "\n")}";
      });
    });

当該の部分はここでありそうだということがわかります。詳しくは以下のサイトで見られます。
https://pub.dev/documentation/onesignal_flutter/latest/onesignal_flutter/OneSignalNotifications/addClickListener.html

ここで、Flutter側で、この関数について調べてみます。
event.notificationまであるので、以下のように調べてみると候補が色々出てきて、天下り的ですが、additionalDataがそれっぽいなぁという印象です。

次にOneSignalのREST API Referenceについてみてみます。

https://documentation.onesignal.com/reference/

今回はPush通知なので、

左にある、Create Notification→Push Channel Propertiesが該当しそうですからそこを調べます。

https://documentation.onesignal.com/reference/push-channel-properties

で、先ほどのAdditional Dataがそれっぽいということで、Additionalで検索をかけると、

これが見つかります。じゃあこれを今までのPush通知に加えればいいだろうということになります。
ここまできてWorkersで実装しようということになります。

WorkersでOneSignalに送るデータは次のようにしました。

// 送信する通知のデータ
  const notificationData = {
    app_id: appId, // OneSignalのアプリID
    contents: { en: ` ${likesUserName} liked your submission!`, ja: `${likesUserName}があなたの投稿をいいねしました` },
    headings: { en: "app name", ja: "アプリ名" },
    target_channel: 'push',
    include_aliases: {"externalId": [externalIds]},// External IDの配列を指定
    data:{"action": "like","imageId": imageId}, //この部分を追加する。
  };

いままではdataの部分がなかったのですが、これを追加することとしました。
これでバックエンドは終わりです。

5~6: Flutter側での処理(クライアント)

先ほどのExampleは以下のような形です。

OneSignal.Notifications.addClickListener((event) {
      print('NOTIFICATION CLICK LISTENER CALLED WITH EVENT: $event');
      this.setState(() {
        _debugLabelString =
            "Clicked notification: \n${event.notification.jsonRepresentation().replaceAll("\\n", "\n")}";
      });
    });

これを以下のような形に変更しました。

Future<void> onTapPushNotification() async{
    OneSignal.Notifications.addClickListener((event) {
      final additionalData = event.notification.additionalData;
      //ここでDisplayPageに飛ばす
      if (additionalData!["action"] == "like") {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => DisplayPage(
              imageId: additionalData["imageId"],
            ),
          ),
        );
      }
      //actionによって動作を変える

    });
  }

アプリ起動時に読み込む

実際の動画

実際に動作させたのが以下の動画です(この動画を撮ったときはpushAndRemoveUntilを使っていたので左上に戻るボタンがありません)。

入れ替わりが早いですが、最初にちらっと見える新着の部分がホームページでそこから飛んだという形になります。

mp4→GIFでの変換は、以下のサイトを使わせていただきました。
https://rakko.tools/tools/86/

あとがき

個人的にOneSignalは使いやすいと感じているので、Push通知の動作をカスタマイズできるようになり、さらにいろんなことができるなぁと思いました。最近は使いやすいサービスが多く、個人での開発がしやすくなっているのかなぁとも思います。
自分は金欠なのであまりお金をかけられないのでそういうのは非常にありがたいです。

今はFirebaseやAWS、Azureといったてんこ盛りセットみたいなサービスを使うのが普通なのかもしれませんが、個々で必要な機能を使うといろいろコストを削減できるのかなぁと思いました。

Supabase⇔Firebase
OneSignal⇔FCM
みたいな感じでしょうか?

とりあえず、OneSignalについては日本語での情報をあまり見かけませんが、一度使ってみるのもいいのではないかと思います。

Discussion