【Flutter】flutter_local_notifications で通知を実装する①
初めに
今回は flutter_local_notifications パッケージを使ってローカル通知の実装を行いたいと思います。
通知機能が実装できればユーザーとの接触回数を増やすことができ、かつリアルタイムで情報を届けることができるため、実装が必要なサービスも多いと思います。
今回はローカル通知を表示させるまで実装を行います。
そして次の記事で通知をカスタマイズする方法についてより詳しくまとめていきたいと思います。
記事の対象者
- Flutter 学習者
- Flutter でローカル通知を実装したい方
目的
今回の目的は flutter_local_notifications でローカル通知を実装することです。なお、今回は iOS の実装を中心で行うので、ご了承ください。
最終的には以下の動画のようにボタンを押すと通知が表示されるような実装を行います。
準備
Flutter の準備
flutter_local_notificationsパッケージの最新バージョンを pubspec.yaml
に記述します。
dependencies:
flutter:
sdk: flutter
flutter_local_notifications: ^18.0.1
または
以下をターミナルで実行
flutter pub add flutter_local_notifications
Android の準備
Android Setup のドキュメントを見ながら Android 側の準備を進めていきます。
android/app/build.gradle
を以下のような設定が含まれるように変更します。
android {
defaultConfig {
multiDexEnabled true
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
}
android/build.gradle
を以下の設定が含まれるように変更します。
buildscript {
...
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
...
}
android/app/src/main/AndroidManifest.xml
に以下を追加します。
<application>
// その他の設定
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
iOS の準備
次に iOS Setup のドキュメントを見ながら iOS 側の準備を進めていきます。
ios/Runner/AppDelegate.swift
で以下の部分が含まれるように編集します。
import UIKit
import Flutter
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
+ if #available(iOS 10.0, *) {
+ UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
+ }
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
これで準備は完了です。
実装
実装は以下の手順で進めていきます。
- 定数の定義
- Serivce の実装
- Screen の実装
- main.dart の実装
定数の定義
まずは実装に必要な定数の定義を行います。
コードは以下の通りです。
class NotificationConstants {
static const String channelId = 'default_channel_id';
static const String channelName = 'Default Channel';
static const String channelDescription = 'This is the default notification channel.';
}
NotificationConstants
では Android の通知の設定に使用する定数をまとめています。
それぞれ以下のような役割で使用します。
-
channelId
: 通知を送るチャンネルのID。 Android 8.0 以上で必要 -
channelName
: 通知を送るチャンネルの名前。 Android 8.0 以上で必要 -
channelDescription
: 通知を送るチャンネルの概要の説明文
今回は使用するチャンネルは一つなので、すべてデフォルトにしています。
通知を送信するIDや名前を変更することで複数のチャンネルを管理することができます。
タイプミスしないように定数にしてまとめています。
Serivce の実装
次に Service の実装に移ります。
この記事では通知に関する以下の四つの機能を Service としてまとめていますが、どのように切り分けるかや、どのディレクトリに配置するかはそれぞれのプロジェクトごとで対応していただければと思います。
- 通知サービスの初期化
- 通知権限の取得
- 通知タップ時の処理
- 通知の表示
それぞれ上記の流れで実装していきたいと思います。
1. 通知サービスの初期化
まずは通知サービスの初期化を行います。
コードは以下の通りです。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:sample_flutter/flutter_local_notifications/const/notification_constants.dart';
class SimpleNotificationService {
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// 通知サービスの初期化
static Future<void> initialize() async {
// Android 初期設定
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
// iOS 初期設定
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
// 全体の初期設定
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse, // 未実装
onDidReceiveBackgroundNotificationResponse:
_onDidReceiveBackgroundNotificationResponse, // 未実装
);
if (Platform.isIOS) {
await _requestIOSPermissions(); // 未実装
} else if (Platform.isAndroid) {
await _requestAndroidPermissions(); // 未実装
} else {
debugPrint('通知権限のリクエストはサポートされていません');
}
}
}
「未実装」とコメントしてある部分ではエラーが出ているかと思いますが、後々実装していきます。
それぞれコードを見ていきます。
以下では FlutterLocalNotificationsPlugin
を _flutterLocalNotificationsPlugin
としてインスタンス化して保持しています。
これでこのサービス内では FlutterLocalNotificationsPlugin
に用意されているメソッドを実行できるようになります。
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
以下ではサービスの初期化を行うための initialize
メソッドと Android の初期設定を行なっています。 initialize
メソッドを用意することでサービスの外部から初期化ができるようになります。この初期化メソッドを、アプリが実行されてすぐ実行されるように後ほど設定していきます。
AndroidInitializationSettings
は名前の通り Android の初期設定です。引数には、表示する通知に使用されるアイコンを指定しています。以下のコードでは @mipmap/ic_launcher
を指定しています。これはアプリのアイコンが保存されている場所です。 ic_launcher
は android/app/src/main/res/mipmap-hdpi/ic_launcher.png
のパスで確認することができ、デフォルトでは Flutter のアイコンになっています。
// 通知サービスの初期化
static Future<void> initialize() async {
// Android 初期設定
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
以下では iOS の初期設定と全体の初期設定を行なっています。
iOS の通知の初期設定は DarwinInitializationSettings
で記述することができ、以下ではアラート、バッジ、サウンドを使用するような設定にしています。
全体の初期設定は InitializationSettings
で記述できます。
定義した Android、iOS の初期設定をそれぞれ渡すようにしています。
今回は android、iOS のみですが、macOS、linux の設定も追加できるようです。
// iOS 初期設定
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
// 全体の初期設定
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
以下では initialize
メソッドを実行して、定義した全体の初期設定である initializationSettings
を渡しています。これで初期化ができます。
なお、onDidReceiveNotificationResponse
ではアプリがフォアグラウンドの状態で通知をタップした際の処理、 onDidReceiveBackgroundNotificationResponse
ではアプリがバックグラウンドの状態で通知をタップした際の処理を指定できます。
今はまだ実装していないのでエラーになっているかと思います。
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse,
onDidReceiveBackgroundNotificationResponse:
_onDidReceiveBackgroundNotificationResponse,
);
以下ではそれぞれのプラットフォームに合わせて権限を取得するための関数を実行しています。
初期化の段階で行うことで、通知を送信する前に権限の確認を行うことができます。
次の章で実装していきます。
if (Platform.isIOS) {
await _requestIOSPermissions();
} else if (Platform.isAndroid) {
await _requestAndroidPermissions();
} else {
debugPrint('通知権限のリクエストはサポートされていません');
}
2. 通知権限の取得
次に通知の権限を取得するための処理を追加していきます。
以下のコードを追加していきます。
// iOS 通知権限のリクエスト
static Future<void> _requestIOSPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
// Android 通知権限のリクエスト
static Future<void> _requestAndroidPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
追加後の現状のコード
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:sample_flutter/flutter_local_notifications/const/notification_constants.dart';
class SimpleNotificationService {
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// 通知サービスの初期化
static Future<void> initialize() async {
// Android 初期設定
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
// iOS 初期設定
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
// 全体の初期設定
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse,
onDidReceiveBackgroundNotificationResponse:
_onDidReceiveBackgroundNotificationResponse,
);
if (Platform.isIOS) {
await _requestIOSPermissions();
} else if (Platform.isAndroid) {
await _requestAndroidPermissions();
} else {
debugPrint('通知権限のリクエストはサポートされていません');
}
}
+ // iOS 通知権限のリクエスト
+ static Future<void> _requestIOSPermissions() async {
+ await _flutterLocalNotificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ IOSFlutterLocalNotificationsPlugin>()
+ ?.requestPermissions(
+ alert: true,
+ badge: true,
+ sound: true,
+ );
+ }
+ // Android 通知権限のリクエスト
+ static Future<void> _requestAndroidPermissions() async {
+ await _flutterLocalNotificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ AndroidFlutterLocalNotificationsPlugin>()
+ ?.requestNotificationsPermission();
+ }
}
それぞれ見ていきます。
以下では iOS の通知権限のリクエストを行なっています。
resolvePlatformSpecificImplementation
に IOSFlutterLocalNotificationsPlugin
を指定して、 requestPermissions
を実行することで iOS 向けの通知権限のリクエストが実行できます。
以下ではアラート、バッジ、サウンドの許可を要求しています。
requestPermissions
の返り値は bool で、ユーザーが通知を許可したかどうかを返すようになっています。
// iOS 通知権限のリクエスト
static Future<void> _requestIOSPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
以下では Android の通知権限のリクエストを行なっています。
AndroidFlutterLocalNotificationsPlugin
を渡して、 requestNotificationsPermission
を実行することで通知に関連する権限のリクエストができます。このメソッドも iOS 側のリクエストと同様で、ユーザーが通知を許可したかどうかの bool を返すようになっています。
// Android 通知権限のリクエスト
static Future<void> _requestAndroidPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
3. 通知タップ時の処理
次に通知をタップした時の処理を実装していきます。
以下のコードを追加します。
// 通知のタップ時の処理
static void _onDidReceiveNotificationResponse(NotificationResponse response) {
debugPrint('onDidReceiveNotificationResponse: $response');
}
// バックグラウンドで通知を受け取った時の処理
static Future _onDidReceiveBackgroundNotificationResponse(
NotificationResponse response) async {
debugPrint('onDidReceiveBackgroundNotificationResponse: $response');
}
追加後の現状のコード
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:sample_flutter/flutter_local_notifications/const/notification_constants.dart';
class SimpleNotificationService {
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// 通知サービスの初期化
static Future<void> initialize() async {
// Android 初期設定
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
// iOS 初期設定
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
// 全体の初期設定
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse,
onDidReceiveBackgroundNotificationResponse:
_onDidReceiveBackgroundNotificationResponse,
);
if (Platform.isIOS) {
await _requestIOSPermissions();
} else if (Platform.isAndroid) {
await _requestAndroidPermissions();
} else {
debugPrint('通知権限のリクエストはサポートされていません');
}
}
// iOS 通知権限のリクエスト
static Future<void> _requestIOSPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
// Android 通知権限のリクエスト
static Future<void> _requestAndroidPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
+ // 通知のタップ時の処理
+ static void _onDidReceiveNotificationResponse(NotificationResponse response) {
+ debugPrint('onDidReceiveNotificationResponse: $response');
+ }
+ // バックグラウンドで通知を受け取った時の処理
+ static Future _onDidReceiveBackgroundNotificationResponse(
+ NotificationResponse response) async {
+ debugPrint('onDidReceiveBackgroundNotificationResponse: $response');
+ }
}
以下の二つのメソッドを定義していますが、この実装ではタップされたことをコンソールに出力するだけにしています。
-
_onDidReceiveNotificationResponse
アプリがフォアグラウンドの状態で通知をタップした場合の処理 -
_onDidReceiveBackgroundNotificationResponse
アプリがバックグラウンドの状態で通知をタップした場合の処理
4. 通知の表示
Service の最後の実装として通知の表示のためのメソッドを追加していきます。
以下のコードを追加します。
// 通知の送信
static Future<void> showNotification({
required int id,
required String title,
required String body,
}) async {
// Android 用のスタイル情報
const androidNotificationDetails = AndroidNotificationDetails(
NotificationConstants.channelId,
NotificationConstants.channelName,
channelDescription: NotificationConstants.channelDescription,
importance: Importance.max,
priority: Priority.high,
);
// iOS 用のスタイル情報
const iosNotificationDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
const notificationDetails = NotificationDetails(
android: androidNotificationDetails,
iOS: iosNotificationDetails,
);
await _flutterLocalNotificationsPlugin.show(
id,
title,
body,
notificationDetails,
);
}
追加後の現状のコード
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:sample_flutter/flutter_local_notifications/const/notification_constants.dart';
class SimpleNotificationService {
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// 通知サービスの初期化
static Future<void> initialize() async {
// Android 初期設定
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
// iOS 初期設定
const DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
// 全体の初期設定
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await _flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse,
onDidReceiveBackgroundNotificationResponse:
_onDidReceiveBackgroundNotificationResponse,
);
if (Platform.isIOS) {
await _requestIOSPermissions();
} else if (Platform.isAndroid) {
await _requestAndroidPermissions();
} else {
debugPrint('通知権限のリクエストはサポートされていません');
}
}
// iOS 通知権限のリクエスト
static Future<void> _requestIOSPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
// Android 通知権限のリクエスト
static Future<void> _requestAndroidPermissions() async {
await _flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
}
// 通知のタップ時の処理
static void _onDidReceiveNotificationResponse(NotificationResponse response) {
debugPrint('onDidReceiveNotificationResponse: $response');
}
// バックグラウンドで通知を受け取った時の処理
static Future _onDidReceiveBackgroundNotificationResponse(
NotificationResponse response) async {
debugPrint('onDidReceiveBackgroundNotificationResponse: $response');
}
+ // 通知の送信
+ static Future<void> showNotification({
+ required int id,
+ required String title,
+ required String body,
+ }) async {
+ // Android 用のスタイル情報
+ const androidNotificationDetails = AndroidNotificationDetails(
+ NotificationConstants.channelId,
+ NotificationConstants.channelName,
+ channelDescription: NotificationConstants.channelDescription,
+ importance: Importance.max,
+ priority: Priority.high,
+ );
+ // iOS 用のスタイル情報
+ const iosNotificationDetails = DarwinNotificationDetails(
+ presentAlert: true,
+ presentBadge: true,
+ presentSound: true,
+ );
+ const notificationDetails = NotificationDetails(
+ android: androidNotificationDetails,
+ iOS: iosNotificationDetails,
+ );
+ await _flutterLocalNotificationsPlugin.show(
+ id,
+ title,
+ body,
+ notificationDetails,
+ );
+ }
}
それぞれ詳しく見ていきます。
以下では showNotification
として以下の三つを外部から受け取れるようにしています。
-
id
: 通知に使用するID -
title
: 通知のタイトル -
body
: 通知の本文
// 通知の送信
static Future<void> showNotification({
required int id,
required String title,
required String body,
}) async {
以下では Android の通知の詳細情報を設定しています。
定数として定義したチャンネルのID、名前、概要の説明を渡しています。
importance
では通知の重要度を設定しています。importance
は none
, min
, low
, defaultImportance
, high
, max
の六つから選択できます。
priority
では通知の優先度を設定しています。priority
は min
, low
, defaultPriority
, high
, max
の五つから選択できます。
// Android 用のスタイル情報
const androidNotificationDetails = AndroidNotificationDetails(
NotificationConstants.channelId,
NotificationConstants.channelName,
channelDescription: NotificationConstants.channelDescription,
importance: Importance.max,
priority: Priority.high,
);
以下では iOS の通知の詳細情報を設定しています。
この実装ではアラート、バッジ、サウンドの設定を行なっていますが、その他にもサブタイトルや画像の添付、バッジの数字やサウンドの変更などができます。
// iOS 用のスタイル情報
const iosNotificationDetails = DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
);
以下では先程定義した Android, iOS の通知に関する詳細設定を NotificationDetails
にまとめ、 _flutterLocalNotificationsPlugin.show
に渡して通知を表示しています。
ローカル通知は show
メソッドを実行することで表示することができ、以下に指定されている ID やタイトル、本文をカスタマイズすることができます。
const notificationDetails = NotificationDetails(
android: androidNotificationDetails,
iOS: iosNotificationDetails,
);
await _flutterLocalNotificationsPlugin.show(
id,
title,
body,
notificationDetails,
);
これで通知に関する機能をまとめた Service の実装は完了です。
Screen の実装
次に Screen の実装を行います。
コードは以下の通りです。
import 'package:flutter/material.dart';
import 'package:sample_flutter/flutter_local_notifications/services/simple_notification_service.dart';
class NotificationScreen extends StatelessWidget {
const NotificationScreen({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('ホーム'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
SimpleNotificationService.showNotification(
id: 0,
title: 'Hello World !',
body: 'Happy Coding! 🚀',
);
},
child: const Text('シンプルな通知'),
),
),
);
}
}
内容としてはシンプルで、先ほど実装した SimpleNotificationService
の showNotification
を ElevatedButton
で実行しています。
ただ、通知を表示させる前に初期化の処理が必要であるため、この状態でボタンを押してもローカル通知は表示されません。初期化の処理は main.dart
で行います。
main.dart の実装
最後に main.dart
を変更します。
コードは以下の通りです。
import 'package:flutter/material.dart';
import 'package:sample_flutter/flutter_local_notifications/services/simple_notification_service.dart';
import 'package:sample_flutter/flutter_local_notifications/screens/notification_screen.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// 通知サービスの初期化
await SimpleNotificationService.initialize();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: NotificationScreen(),
);
}
}
上記の通り main
メソッドの中で SimpleNotificationService.initialize
を実行することで通知サービスが初期化され、正常に動作するようになります。
上記のコードで実行すると以下の動画のように任意のタイトルと本文の通知を送信できるかと思います。
以上です。
まとめ
最後まで読んでいただいてありがとうございました。
今回は flutter_local_notifications パッケージを使ってローカル通知を行う方法をまとめました。
冒頭でも述べた通り、通知機能が実装できればユーザーとアプリの接点を増やすことができます。しかし、あまり通知の頻度が高いと通知自体をオフにされたりイメージが悪化してしまう可能性があるため、慎重に使いたい機能でもあります。
誤っている点やもっと良い書き方があればご指摘いただければ幸いです。
参考
Discussion