[Flutter]Android用のPush通知を実装する

広告Flutter
2024年2月4日2024年4月11日

Firebase Cloud Messaging(以下FCM)を利用して、FlutterのAndroidアプリでプッシュ通知を受け取る機能を実装していきます。
アプリの状態がForeground・Backgroundで通知が表示されるようにします。

環境
  • Flutter 3.16.5
  • firebase_core: ^2.25.3
  • firebase_messaging: ^14.7.14
  • flutter_local_notifications: ^16.3.2
  • Android実機で検証

Firebaseの事前準備

公式を参考にアプリにFirebaseを追加して初期化します。 https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios

  • Firebase プロジェクトを作成する
  • Firebase プロジェクトに Android アプリを追加する
  • Flutterアプリで Firebase を初期化する

通知の設定

FCMプラグインをインストールする

flutter pub add firebase_messaging
pubspec.yaml
dependencies:
  firebase_messaging: ^14.7.14

FCMのトークンを取得する

main.dartに importします。

main.dart
import 'package:firebase_messaging/firebase_messaging.dart';

端末のトークンを取得する処理を追加します。

main.dart
void main() async {
	WidgetsFlutterBinding.ensureInitialized();
	
	await Firebase.initializeApp(
		options: DefaultFirebaseOptions.currentPlatform,
	);
	// --> 追加
	final fcmToken = await FirebaseMessaging.instance.getToken();
	debugPrint('FCM Token: $fcmToken');
	// <-- ここまで追加
	
	runApp(const MyApp());
}

アプリを起動し、コンソールに出力されるトークンを取得します。 

I/flutter ( 8665): FCM Token: fj0wJtdDSsqBRAKuhjjnfd:APA96*********m2CFapQxU2etz3Q6*********3GT2_mW3IbF6S_AL9CcWLzkxqGyJHI0o6*********8axj1tcv5GHzJpZxYFzYN4WzPwB2ZuN4F8m_sR6*********

プッシュ通知権限リクエスト

Android13 から Android でもプッシュ通知権限の要求が必要になりました。

Android で Firebase Cloud Messaging クライアント アプリを設定する

google.comgoogle.com

AndroidManifest.xmlにPOST_NOTIFICATIONS権限設定を追加します。

AndroidManifest.xml
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

権限リクエスト処理を追加します。

main.dart
void main() async {
  ・・・
  FirebaseMessaging.instance.requestPermission();

アプリを起動すると通知権限のリクエストが表示されます。
初回に許可しなかった場合、変更するには設定画面から許可する必要があります。

Android 通知権限リクエスト
Android 通知権限リクエスト

通知を受信する

アプリがBackground時にプッシュ通知を受け取る

Firebaseのコンソールから通知を送信します。

FirebaseのメニューからCloud Messagingを選択し、「最初のキャンペーンを作成」から通知の作成画面を開きます。 通知のタイトル・通知テキストを入力し、右側「デバイスのプレビュー」の「テストメッセージを送信」ボタンを押下します。

FCM 通知作成
FCM 通知作成

取得したトークンを追加・選択し、「テスト」ボタンを押下します。

FCM トークン入力
FCM トークン入力

アプリをBackgroundにした状態で送信するとプッシュ通知が届きます。

Android端末 通知表示
Android端末 通知表示

アプリがForegroundにある場合は別の設定が必要になります。

アプリがForeground時にプッシュ通知を受け取り表示する

アプリがForeground時にリモート通知で受けとったメッセージを通知表示します。 ローカル通知の機能を利用します。

Flutterプロジェクトにflutter_local_notificationパッケージをインストールします。

flutter pub add flutter_local_notifications
pubspec.yaml
dependencies:
	flutter_local_notifications: ^16.3.2

main.dartにインポートします。

main.dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

ローカル通知の処理を追加します。

main.dart
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
 
const AndroidNotificationChannel channel = AndroidNotificationChannel(
	'channel_id', // id
	'channel title', // title
	description: 'This channel is used for Info notifications.', // description
	importance: Importance.high,
);

メッセージを受信する処理を追加します。

main.dart
void main() async {
 ・・・
  // Foregroundでのメッセージ受信時の処理
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    print('Foregroundでメッセージを受信しました message: ${message.notification!.body}');
 
    RemoteNotification? notification = message.notification;
 
    if (notification != null) {
      flutterLocalNotificationsPlugin.show(
        notification.hashCode,
        notification.title,
        notification.body,
        NotificationDetails(
          android: AndroidNotificationDetails(
            channel.id,
            channel.name,
            channelDescription: channel.description,
            importance: Importance.high,
            icon: '@mipmap/ic_launcher',
          ),
        ),
      );
    }
  });

つまづいたところ

Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference メッセージ

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference, null, java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Integer.intValue()' on a null object reference

AndroidNotificationDetailsでiconを指定していない状態で発生しました。

FlutterLocalNotificationsPluginのinitializeでアイコンを設定するか NotificationDetailsで個別にアイコンを指定することで解消しました。

FlutterLocalNotificationsPluginの場合

void main() async {
	・・・
  await flutterLocalNotificationsPlugin.initialize(
    const InitializationSettings(
        android: AndroidInitializationSettings('@mipmap/ic_launcher')),
  );

NotificationDetailsの場合

	NotificationDetails(
	  android: AndroidNotificationDetails(
		channel.id,
		channel.name,
		channelDescription: channel.description,
		importance: Importance.high,
		icon: '@mipmap/ic_launcher',  // <-- アイコン指定
	  ),
	),

Foreground時に通知が表示されない

無効なアイコン名を指定していたことが原因でした。

icon: 'launch_background', 

有効なアイコンに変更し、表示されるようになりました。(環境に合わせてください)

icon: '@mipmap/ic_launcher', 

参考

アプリの状態について

Flutter アプリでメッセージを受信する  |  Firebase Cloud Messaging

google.comgoogle.com

App Icons

アプリアイコンを作成する  |  Android Studio  |  Android Developers

Compose でマテリアル アイコンを呼び出すか、Image Asset Studio を使用して、マテリアル アイコン、カスタム画像、テキスト文字列から独自のアプリアイコンを生成します。android.comandroid.com
アプリアイコンを作成する  |  Android Studio  |  Android Developers