Flutter - 应用程序关闭时不会出现 FCM 消息

Ari*_*iel 7 android flutter firebase-cloud-messaging flutter-local-notification

我使用 FCM 和 Flutter 本地通知来接收消息。Flutter 本地通知用于在应用程序位于前台时显示通知。目前,我使用的是 Android 12 (Poco X3 PRO)。

当我终止应用程序并从 Firebase 控制台发送消息时,以下消息将显示在 logcat 中。

2022-07-26 07:40:16.751 11370-11370/? W/GCM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000000 pkg=au.org.nrna.test.app (has extras) }
Run Code Online (Sandbox Code Playgroud)

我已经检查了此处链接的 firebase 云消息传递文档,但是没有提及终止状态下的消息处理。

同样,当应用程序位于前台时,该消息仅显示在通知托盘中。它根本不显示在屏幕上。

文件: main.dart

import 'dart:async';
import 'dart:convert';
import 'dart:isolate';

import 'package:device_preview/device_preview.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

import 'core/apps/app.dart';
import 'core/apps/device_preview_app.dart';
import 'core/bloc_observers/bloc_observer.dart';
import 'core/config_reader/config_reader.dart';
import 'core/injections/injections.dart';
import 'core/routes/app_router.gr.dart';

final appRouter = AppRouter();

void main() async {
  BlocOverrides.runZoned(
    () async {
      runZonedGuarded<Future<void>>(() async {
        initAndRunApp();
      },
          (error, stack) => FirebaseCrashlytics.instance
              .recordError(error, stack, fatal: true));
    },
    blocObserver: MyBlocObserver(),
  );
}

void onDidReceiveLocalNotification(
    int id, String? title, String? body, String? payload) {
  // display a dialog with the notification details, tap ok to go to another page

  debugPrint(
      'Notification[#$id] - Title: $title, Body: $body Payload: $payload');
}

void onSelectNotification(String? payload) {
  if (payload != null) {
    Map<String, dynamic> payloadMap = jsonDecode(payload);

    debugPrint(payloadMap.toString());
  }
}

Future _setupPushNotification() async {
  FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  const AndroidInitializationSettings androidInitializationSettings =
      AndroidInitializationSettings('launch_background');

  const IOSInitializationSettings iosInitializationSettings =
      IOSInitializationSettings(
          onDidReceiveLocalNotification: onDidReceiveLocalNotification);

  const InitializationSettings initializationSettings = InitializationSettings(
    iOS: iosInitializationSettings,
    android: androidInitializationSettings,
  );

  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
      onSelectNotification: onSelectNotification);

  final bool? result = await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          IOSFlutterLocalNotificationsPlugin>()
      ?.requestPermissions(
        alert: true,
        badge: true,
        sound: true,
      );

  var androidDetails = const AndroidNotificationDetails(
    'com.test.app.notification_channel',
    'Test Notification Channel',
    channelDescription: 'Notification Channel for Test App for Android',
    priority: Priority.high,
  );
  var iosDetails = const IOSNotificationDetails();
  var generalNotificationDetails =
      NotificationDetails(android: androidDetails, iOS: iosDetails);

  FirebaseMessaging.onBackgroundMessage(_onBackgroundMessageHandler);

  FirebaseMessaging.onMessage.listen((message) {
    debugPrint(
        'FCM NOTIFICATION[#${message.messageId}] - Data: ${message.data} Title: ${message.notification?.title} Body: ${message.notification?.body}');

    RemoteNotification? notification = message.notification;
    AndroidNotification? androidNotification = message.notification?.android;
    AppleNotification? appleNotification = message.notification?.apple;

    String? payloadJsonStr;
    if (message.data.isNotEmpty) {
      payloadJsonStr = jsonEncode(message.data);
    }

    if (notification != null && androidNotification != null) {
      flutterLocalNotificationsPlugin.show(notification.hashCode,
          notification.title, notification.body, generalNotificationDetails,
          payload: payloadJsonStr);
    }
  });
}

Future<void> _onBackgroundMessageHandler(RemoteMessage message) async {
  debugPrint(
      'Background FCM NOTIFICATION[#${message.messageId}] - Data: ${message.data} Title: ${message.notification?.title} Body: ${message.notification?.body}');
}

Future _initialiseApp() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // setup Push Notifications
  _setupPushNotification();

  // Pass all uncaught errors from the framework to Crashlytics.
  FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterFatalError;

  // GetIt configuration
  configureDependencies();
  await getIt<ConfigReader>().initialize();
}

Future initAndRunApp() async {
  await _initialiseApp();

  Isolate.current.addErrorListener(RawReceivePort((pair) async {
    final List<dynamic> errorAndStacktrace = pair;
    await FirebaseCrashlytics.instance.recordError(
      errorAndStacktrace.first,
      errorAndStacktrace.last,
      fatal: true,
    );
  }).sendPort);

  final fcmToken = await FirebaseMessaging.instance.getToken();
  debugPrint(fcmToken);

  if (!kReleaseMode && getIt<ConfigReader>().isDevicePreviewEnabled) {
    runApp(
      DevicePreview(
        enabled: !kReleaseMode,
        builder: (context) => const DevicePreviewApp(), // Wrap your app
      ),
    );
  } else {
    runApp(const MyApp());
  }
}

Run Code Online (Sandbox Code Playgroud)

文件: AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.app">
    <uses-permission android:name="android.permission.INTERNET"/>
   <application
        android:label="My App"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
</manifest>

Run Code Online (Sandbox Code Playgroud)

Ari*_*iel 17

在调试模式下运行应用程序时似乎会发生该错误。如果停止调试,将被视为强制停止或终止应用程序。

Firebase 文档指出,除非再次打开应用程序,否则通知不会在强制停止或终止的应用程序上显示。

文档:在 Flutter 应用程序中接收消息。查找Receive messages in a Flutter app页面中的标题部分。


Jay*_*ola 11

尝试使用发布模式运行您的应用程序flutter run --release并检查