【Flutter】FCMとSupabase Edge FunctionsでPush通知〜第2回〜
公開日2024.12.10
前回に続き、今回は、Push通知の受信までの実装を進めていきます。
改めて開発の流れの紹介
- Firebaseの設定
- Firebaseの環境分け(devとprod)
- FlutterでFirebase初期化を実装
- FCMの設定【← 第1回はここまで】
- Flutterで通知許可ダイアログを実装
- バックグラウンド・フォアグラウンド・ターミネート状態でのPush通知の受信
- Firebase Messagingでテスト送信【← 第2回はここまで】
- Supabaseインストール
- Supabase Edge Functionsの実装
- Webhookを設定
- SupabaseからFlutterアプリにPush通知を送信【← 第3回はここまで】
Flutterで通知許可ダイアログを実装
許可ダイアログを表示したい箇所に以下コードを記載します。
await ref.read(pushNotificationRepositoryProvider).requestPermission();
バックグラウンド・フォアグラウンド・ターミネートでのPush通知を実装
バックグラウンド・フォアグラウンド・ターミネート状態でのPush通知を受信する実装です。
フォアグラウンド・ターミネート通知に関しては、デフォルトのままだと通知を受信しても、通知バーに表示されないようになっています。
通知を表示するために、flutter_local_notifications
パッケージを使ってカスタム通知を表示する方法が一般的です。
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
ios/Runner/AppDelegate.swift
import UIKit
import Flutter
import flutter_local_notifications
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 以下追加
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
// ここまで
main.dart
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
logger.i('Handling a background message: ${message.messageId}');
}
class _AppInitializer extends HookConsumerWidget {
const _AppInitializer({required this.child});
final Widget child;
@override
Widget build(BuildContext context, WidgetRef ref) {
...
Future<void> init() async {
ref.read(pushNotificationRepositoryProvider).initialize(
handler: _firebaseMessagingBackgroundHandler,
);
ref.read(pushNotificationRepositoryProvider).handle();
...
}
final pushNotificationRepositoryProvider =
Provider<PushNotificationRepository>((ref) {
return PushNotificationRepository(ref);
});
class PushNotificationRepository {
PushNotificationRepository(this._ref);
final Ref _ref;
final messaging = FirebaseMessaging.instance;
final onMessaging = FirebaseMessaging.onMessage;
final spabase = Supabase.instance.client;
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
final channel = const AndroidNotificationChannel(
'fcm_channel',
'Fcm Notifications',
description: 'This channel is used for Fcm notifications.',
importance: Importance.high,
);
void initialize({
required Future<void> Function(RemoteMessage) handler,
}) {
FirebaseMessaging.onBackgroundMessage(handler);
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
void handle({VoidCallback? callbackRouter}) {
// プッシュ通知を開いた時のハンドリング
void handleMessage(RemoteMessage message) {
final callback = callbackRouter;
if (callback != null) {
callback();
}
}
// Terminatedから開いた時
messaging.getInitialMessage();
// Backgroundから開いた時
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
FirebaseMessaging.onMessage.listen((message) {
final notification = message.notification;
final android = message.notification?.android;
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
icon: '@mipmap/ic_stat',
),
),
);
}
});
}
Future<String?> getToken() async {
return messaging.getToken();
}
Future<void> requestPermission() async {
final settings = await messaging.requestPermission();
if (settings.authorizationStatus == AuthorizationStatus.authorized ||
settings.authorizationStatus == AuthorizationStatus.provisional) {
await setupFcm();
}
}
Future<void> setupFcm() async {
final fcmToken = await getToken();
if (fcmToken != null) {
logger.i('🐯 FCM TOKEN: $fcmToken');
await saveFcmToken(fcmToken);
}
messaging.onTokenRefresh.listen((newToken) async {
await saveFcmToken(newToken);
});
}
Future<void> saveFcmToken(String fcmToken) async {
// NOTE: FCM TokenをDBにセット(ご自身の環境に合わせて記載してください)
}
// 全体配信・Topicでsubscribe
void subscribeToTopic() {
messaging.subscribeToTopic('all');
}
}
これでPush通知を受信できるようになります。
Firebase Messagingでテスト送信して受信を確認
実際に、FirebaseからPush通知を送信してみます。
通知の作成から手動でテスト送信しましょう。
バックグラウンドでのPush通知の受信を確認
Androidはシミュレーター上で確認できます。
iOSは実機ビルドが必要です。
フォアグラウンド・ターミネートでのPush通知の受信を確認
今回はこれで一旦完了です。
続きは以下の記事を見てください!