この記事は Unity で(ローカル)プッシュ通知をするやり方をメモした記事です。
ローカルプッシュ通知とは、端末に通知を送る際にサーバーを使用しません。端末の中に通知予定を入れて、あとから自動的に通知を発生させることが可能です。
プッシュ通知の雰囲気は以下の Android 端末の画像でわかるかと思います。
よくあるのは、おつかいを設定して 30 分後になったら、おつかい完了の通知を発生させるようなやつです。
Unity Mobile Notifications Package をインストールする
メニューの「Package Manager」から「Mobile Notifications」をインストールします。
- Window > Package Manager > (Menu) Mobile Notifications
プロジェクト設定
Android の通知に表示されるアイコンを設定します。
- Edit > Project Settings > (Menu) Mobile Notification Settings
用意するアイコンのサイズは、次のふたつをそれぞれ Type の icon_small と icon_large に設定します。
- 48x48
- 192x192
48x48 の画像は透明部分をくりぬいた白い画像が表示されました。
設定した画像の identifier はデフォルトだと「icon_0」や「icon_1」になっていますが、このテキストの値はあとで使用するので、きちんと識別子となる名前(テキスト)を設定したほうがよいと思います。
番号をつけても、これは(正確には)連続性がないので、「Unity 開発に関する 50 の Tips 〜ベストプラクティス〜(2016 Edition)」だと Tips 68 のようになっています。やっぱり、推奨とはいかないです。
Android のアイコンアセットには公式が挙げている命名規則がありますので、「アイコン デザイン ガイドライン」をここでは利用することにします。
アイコン アセット共通の命名規約の例
表にすると、こんな感じかと。
アセットタイプ | 接頭辞 | 例 |
---|---|---|
アイコン | ic_ | ic_star.png |
ランチャー アイコン | ic_launcher | ic_launcher_calendar.png |
メニュー アイコン、アクションバー アイコン | ic_menu | ic_menu_archive.png |
ステータスバー アイコン | ic_stat_notify | ic_stat_notify_msg.png |
タブアイコン | ic_tab | ic_tab_recent.png |
ダイアログ アイコン | ic_dialog | ic_dialog_info.png |
なので、ここでは次のテキストとします。
- ic_stat_notify_small
- ic_stat_notify_large
なお、アイコンに使う画像はテクスチャーとして利用しないので「Texture Type」を「Editor GUI and Legacy GUI」にして最適化を防ぐような設定にしました。
スプリプトの実装
LocalNotification を機能を実行するためのインターフェースを用意しました。この機能は Android と iOS で別々に実装したほうがよいので、インターフェースを挟んでおいたほうが後々便利です。
using System; public interface ILocalNotification { /// <summary> /// Small Icon タイプのアイコン ID を表すテキストを取得または設定します。 /// </summary> string SmallIcon { get; set; } /// <summary> /// Large Icon タイプのアイコン ID を表すテキストを取得または設定します。 /// </summary> string LargeIcon { get; set; } void CreateChannel(string cannelId, string cannelName, string description); void CancelAll(); int Schedule(string title, string text, DateTime fireTime); int ScheduleInSeconds(string title, string text, int seconds); int ScheduleInMinutes(string title, string text, int minutes); int ScheduleInHours(string title, string text, int hours); }
Android のコードです。ここがこの記事で一番コアな部分です。
using System; using System.Collections; using System.Collections.Generic; using Unity.Notifications.Android; using UnityEngine; public class LocalNotificationForAndroid : ILocalNotification { public string ChannelId { get; set; } = "channel-id"; public string SmallIcon { get; set; } = "icon_0"; public string LargeIcon { get; set; } = "icon_1"; public void CreateChannel(string cannelId, string cannelName, string description) { ChannelId = cannelId; var cannel = new AndroidNotificationChannel { Id = ChannelId, Name = cannelName, Importance = Importance.High, Description = description, }; if (SmallIcon == "icon_0") { Debug.LogWarning($"{nameof(SmallIcon)} プロパティの値が初期値のままです。アイコンを正しく表示できない恐れがあります。"); } if (LargeIcon == "icon_1") { Debug.LogWarning($"{nameof(LargeIcon)} プロパティの値が初期値のままです。アイコンを正しく表示できない恐れがあります。"); } AndroidNotificationCenter.RegisterNotificationChannel(cannel); } public void CancelAll() { AndroidNotificationCenter.CancelAllScheduledNotifications(); AndroidNotificationCenter.CancelAllNotifications(); } public int Schedule(string title, string text, DateTime fireTime) { var notification = new AndroidNotification { Title = title, Text = text, FireTime = fireTime, }; notification.SmallIcon = SmallIcon; notification.LargeIcon = LargeIcon; return AndroidNotificationCenter.SendNotification(notification, ChannelId); } public int ScheduleInSeconds(string title, string text, int seconds) => Schedule(title, text, DateTime.Now.AddSeconds(seconds)); public int ScheduleInMinutes(string title, string text, int minutes) => Schedule(title, text, DateTime.Now.AddMinutes(minutes)); public int ScheduleInHours(string title, string text, int hours) => Schedule(title, text, DateTime.Now.AddHours(hours)); }
このクラスを使って、通知をやってみることにします。注意する点として、登録・通知をしたクラス(ここだと LocalNotificationForAndroid)のインスタンスを保持しておかないと、正しく端末に通知が発生しませんでした。なので、このクラスを singleton にするか singleton クラスのプロパティとして持つようにしてみます。
singleton クラスで保持する例
簡単な singleton パターンを適用したクラスに通知用のクラスを用意しました。ポイントは、アイコンのプロパティに設定しているテキスト値が、「アイコン アセット共通の命名規約の例」で決めた2つのテキストです。
このテキストが、通知されるアイコンと紐づいてしまいます。(テキスト以外の方法で設定をやりたいけど、仕様上やりづらい+ここだけ設定すれば変更することはもう無いので、こうしました)
using System.Collections; using System.Collections.Generic; using UnityEngine; public sealed class NotificationManager { public static NotificationManager Instance { get; } = new NotificationManager(); public ILocalNotification Notification { get; private set; } private NotificationManager() { } public void Initialize() { ILocalNotification notification = new LocalNotificationForAndroid(); notification.SmallIcon = "ic_stat_notify_small"; notification.LargeIcon = "ic_stat_notify_large"; notification.CreateChannel("sample0916", "sampleName", "sampleDescription"); Notification = notification; } }
ここで突然 ChannelID、CannelName、Description をサンプル的な値で埋めていますが、別にこのコードでも Android で動作するのを確認しています。Android の通知仕様を確認するとわかりやすいかもしれません。(おそらくこれをアダプトしてるのだと思います)
Channel ID は、チャンネル登録の関数と、スケジュール登録の関数で同じ値が利用されています。アイコンのように Unity プロジェクト内と紐づくものは無いと思います。
拡張性の観点から挙げるポイントは、以下のコードブロックです。
ILocalNotification notification = new LocalNotificationForAndroid();
下コードの感じにするだけで、切り替えることができると思います。インターフェースでメソッドを定義してあるので、通知予約のメソッドも共通化できているので便利。(それ以外は LocalNotificationForDummy とかもいいかも)
#if UNITY_ANDROID ILocalNotification notification = new LocalNotificationForAndroid(); #elif UNITY_IOS ILocalNotification notification = new LocalNotificationForiOS(); #else ILocalNotification notification = new LocalNotificationForDummy(); #endif
あと、singleton パターンはとても強力なので、設計のやり甲斐があります。NotificationManager だと他に持つ機能がないかもしれません。EnvironmentManager のようなものに統合してもいいかもしれないです。
通知をテストする(+使い方)
アプリケーションの開始直後に設定をして、あとはそのインスタンスを使いまわす感じにしてみます。なので、アプリケーションのエントリーポイントでやってみることにします。
アプリケーションのエントリーポイントは次の記事で説明しています。
こんな感じになりました。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class App { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] public static void EntryPoint() { // 初期化 var manager = NotificationManager.Instance; manager.Initialize(); // サンプル用コード manager.Notification.ScheduleInSeconds("テストのタイトル", "テストのテキストです。", 10); Debug.Log("EntryPoint Called."); } }
実行結果は、こうなります。問題なさそうですね。
サンプル
GitHub に「unity-local-notification-practice」サンプルを公開しています。
参考
- AppSeedのアプリ開発ブログ - 【Unity】アダプティブアイコンに対応する方法
- android dev - 通知チャネルを作成して管理する
- android dev - Image Asset Studio を使用してアプリアイコンを作成する
- 作者:MartinFowler
- 発売日: 2019/12/06
- メディア: Kindle版