通知機能は多くのアプリで使われている機能です。本記事では、特定の時刻になるとメッセージを通知する機能の実装方法を説明します。
目次
本記事の想定読者
- Flutterでアプリを開発している人
実装方法
実装方法は以下の通りです。
パッケージをインストール
flutter_local_notification、timezoneそしてshared_preferencesのパッケージをインストールします。flutter_local_notificationは、ユーザーにメッセージを通知するパッケージですが、timezoneを追加する事で、特定の時刻に通知する事が可能になります。shared_preferencesは通知の有効/無効の設定を保存する為にインストールします。
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
# (...)
flutter_local_notifications: ^16.1.0
timezone: ^0.9.2
shared_preferences: ^2.2.2
flutter pub get
android/app/build.gradleの編集
android/app/build.gradleに以下の行を追記します。
// android/app/build.gradle
android {
compileSdkVersion 33
ndkVersion flutter.ndkVersion
defaultConfig {
multiDexEnabled true // added
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true // added
sourceCompatibility JavaVersion.VERSION_1_8 // added
targetCompatibility JavaVersion.VERSION_1_8 // added
}
// (...)
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' // added
}
通知の許可をリクエストする
アプリを初回起動した時に通知の許可をリクエストするよう実装します。
// lib/main.dart
class _MyAppState extends State<MyApp> {
void initState() {
_requestPermissions(); // added
}
// added below
Future<void> _requestPermissions() async {
if (Platform.isIOS || Platform.isMacOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
MacOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
} else if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final bool? grantedNotificationPermission =
await androidImplementation?.requestNotificationsPermission();
setState(() {
_notificationsEnabled = grantedNotificationPermission ?? false;
});
}
}
通知のクラスを作成する
次に通知するためのクラスを作成します。各メソッドはスタティックメソッドで実装します。クラスのインスタンス化は不要で、直接メソッドにアクセスする事ができます。
// lib/model/local_notifications.dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
class LocalNotifications {
static final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
static final onClickNotification = BehaviorSubject<String>();
// on tap on any notification
static void onNotificationTap(NotificationResponse notificationResponse) {
onClickNotification.add(notificationResponse.payload!);
}
// the function to notify the favorite meigen every 8am.
static tz.TZDateTime _nextInstanceOf8AM() {
tz.initializeTimeZones();
tz.setLocalLocation(
tz.getLocation('Asia/Tokyo'), // very important to add the timezone
);
final tz.TZDateTime now = tz.TZDateTime.now(tz.local);
tz.TZDateTime scheduledDate =
tz.TZDateTime(tz.local, now.year, now.month, now.day, 8, 00);
if (scheduledDate.isBefore(now)) {
scheduledDate = scheduledDate.add(const Duration(days: 1));
}
return scheduledDate;
}
// initialize the local_notification
static Future init() async {
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
onDidReceiveLocalNotification: (id, title, body, payload) => null,
);
final LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(defaultActionName: 'Open notification');
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
linux: initializationSettingsLinux);
_flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: onNotificationTap,
onDidReceiveBackgroundNotificationResponse: onNotificationTap);
}
// the method to notify at the scheduled date and time
static Future showScheduleNotification({
required String title,
required String body,
required String payload,
}) async {
tz.initializeTimeZones();
await _flutterLocalNotificationsPlugin.zonedSchedule(
2,
title,
body,
// tz.TZDateTime.now(tz.local).add(const Duration(seconds: 5)),
_nextInstanceOf8AM(),
const NotificationDetails(
android: AndroidNotificationDetails(
'channel 3', 'your channel name',
channelDescription: 'daily scheduled notification',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker')),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
matchDateTimeComponents: DateTimeComponents.time,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
payload: payload);
}
// close all the notifications available
static Future cancelAll() async {
await _flutterLocalNotificationsPlugin.cancelAll();
}
}
タイムゾーンの設定は不可欠です。タイムゾーンの設定がないと通知する事はできません。
tz.setLocalLocation(
tz.getLocation('Asia/Tokyo'), // very important to add the timezone
);
クラスを実装する
作成したLocalNotificationsをmain.dartに実装します。Switchウィジェットを使い、trueであればLocalNotifications.showScheduleNotificationを実行し、falseであればLocalNotifications.cancelAll()を実行します。
// lib/main.dart
return Scaffold(
(中略)
body: Consumer<Favorites>(
builder: (context, value2, child) {
return Container(
padding: EdgeInsets.only(left: 20),
child: Row(
children: [
Text("毎日8時にお気に入りの名言を通知する"),
Switch(
value: switchValue,
onChanged: (value) {
setState(() {
switchValue = value;
saveSwitchState(value);
if (value) {
LocalNotifications.showScheduleNotification(
title: "今日の名言",
body: value2.randomFav.message.toString(),
payload: "This is schedule data"
);
} else {
LocalNotifications.cancelAll();
}
}
);
},
),
],),
);}
),
);
以上が通知機能を実装する方法になります。まだ通知のアイコンなど足りていない箇所ありますが、追々アップデートしようと思います。
開発環境
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.13.5, on Microsoft Windows [Version 10.0.19045.3448], locale ja-JP)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.1.4)
[√] Android Studio (version 2021.1)
[!] Android Studio (version 4.1)
X Unable to determine bundled Java version.
[!] Android Studio (version 4.2)
X Unable to determine bundled Java version.
[√] VS Code (version 1.82.3)
[√] Connected device (3 available)
[√] Network resources