我使用FCM和Flutter本地通知来接收消息。Flutter本地通知用于在应用程序处于前台时显示通知。目前,我使用的是安卓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) }
我已经查看了链接到这里的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());
}
}
文件: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>
在调试模式下运行应用程序时似乎会出现错误。如果停止调试,将被视为强制停止或终止应用程序。
Firebase文档指出,除非再次打开应用程序,否则不会在强制停止或终止的应用程序上显示通知。
文档:在Flutter应用程序中接收消息。在页面中查找标题为Receive messages in a Flutter app
的部分。
尝试使用flutter run --release
以发布模式运行应用程序并检查