Flutter Push Notifications:无法在后台或应用关闭时接收通知
Posted
技术标签:
【中文标题】Flutter Push Notifications:无法在后台或应用关闭时接收通知【英文标题】:Flutter Push Notifications: Unable to receive notifications in background or when app is closed 【发布时间】:2020-11-23 10:14:18 【问题描述】:我正在为 android 和 ios 开发一个颤振应用程序。它有通知,所以我确实实现了firebase_messaging API。我正在通过设备 ID 向某些设备发送通知,并向topics
发送通知。
我正在测试topics
通知发送,它在 Android 中可以 100% 正常工作。我按照上面提供的链接中的指南,也实现了 iOS 设置。但是在 iOS 中,当通知被发送时,只有当它在前台时才会被应用程序接收。这意味着,只能通过onMessage
。如果应用程序处于后台或关闭状态,我看不到任何通知(我在控制台中打印它)。但是当我重新打开应用程序时,通知会被打印出来。
以下是我的通知注册码
FirebaseMessagesImpl msg = FirebaseMessagesImpl();
msg.requestPermissions();
//Get configured with firebase messaging to recieve messages
msg.getMessage().then((_)
msg.register().then((String token)
print(token);
//Register to the `topic` so we get messages sent to the topic
msg.topicRegister();
.........
FirebaseMessagesImpl
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
class FirebaseMessagesImpl
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
String serverToken =
"AAAAAAA:XXXXXXXXX-YYYYYYYY-ZZZZ-BBBBBBBB";
Future<String> register() async
String token = "";
_firebaseMessaging.getToken().then((t)
token = t;
print("ha: " + t);
);
return token;
Future<void> getMessage() async
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async
print('on message $message');
//setState(() => _message = message["notification"]["title"]);
, onResume: (Map<String, dynamic> message) async
print('on resume $message');
// setState(() => _message = message["notification"]["title"]);
, onLaunch: (Map<String, dynamic> message) async
print('on launch $message');
//setState(() => _message = message["notification"]["title"]);
);
void topicRegister()
// _firebaseMessaging.subscribeToTopic("mobile_admin");
_firebaseMessaging.subscribeToTopic("puppies");
void requestPermissions() async
await _firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound:true, badge:true, alert:true, provisional:false)
);
下面是我的Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MY APP NAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
下面是 AppDelegate.swift
import UIKit
import Flutter
import Firebase
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *)
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
正如一些人在其他 SO 答案中所建议的那样,我从 AppDelegate.swift 代码中删除了以下部分并尝试了,但同样的问题仍然存在。
if #available(iOS 10.0, *)
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
我已将苹果密钥文件上传到 Firebase 项目 cloud messaging
部分,如指南中所述。
下面是我发送通知的 JSon 代码
"notification":
"body": "body",
"title": "title"
,
"priority": "high",
"data":
"body": "body",
"title": "title",
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"id": "1",
"status": "done",
"image": "https://ibin.co/2t1lLdpfS06F.png"
,
"to": "/topics/puppies"
我的登录能力如下
我是 iOS 新手,不知道发生了什么。我想就像在 Android 中一样,当应用处于后台或关闭时,通知会自动出现在通知栏中。
更新
根据@nandish 的建议,我将AppDelegate.swift
文件更改如下
import UIKit
import Flutter
import Firebase
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, UNUserNotificationCenterDelegate
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
UNUserNotificationCenter.current().delegate = self
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
// MARK: - UNUserNotificationCenterDelegate Method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
completionHandler([.alert])
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
然后我得到了以下错误
UNUserNotificationCenter' is only available in iOS 10.0 or newer
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
更新
在前台,当发出通知时,我会收到来自应用程序的以下响应。这也只是在 iPhone 模拟器中,而不是在真实设备中。
from: /topics/puppies, status: done, id: 1, notification: body: body, title: title, e: 1, tag: topic_key_9204266xxxxxxx535, title: title, image: https://ibin.co/2t1lLdpfS06F.png, collapse_key: com.aaa.xxx, body: body, click_action: FLUTTER_NOTIFICATION_CLICK
【问题讨论】:
您可以截屏一下您添加到目标的功能吗? @Honey:抱歉回复延迟。我已经添加了截图。请检查。 @Honey:我似乎也没有收到真实设备的通知。我的测试设备是 iPhone 6。 看起来不错。有时只是取消选中并再次检查它们可能会解决它。另外,您何时取消注册设备令牌?也许您正在做一些在后台注销用户的操作 顺便说一句,您的真实设备没有收到通知是什么意思?推送通知仅发送到真实设备。模拟器无法使用 APN 创建令牌...所以只能使用真实设备进行测试 【参考方案1】:首先,如果您使用 Firebase Cloud Messaging 进行通知,Android 会在应用打开或关闭时收到通知。
但在 iOS 端,iOS 使用的是APN's (Apple Push Notification)
。
*- 您应该在真实设备上尝试。在 iOS 模拟器上,获取通知不稳定。开 *
在您的 Firebase 控制台上转到 Settings > Cloud Messaging > iOS Application Configuration
,然后从您的 Apple 开发人员面板添加您的 APN 标识密钥。你可以在this document上看到。
您还应该在通知负载中添加"content_available": true
。
这里有一个例子:
"to": "/topics/topic_name",
"content_available": true,
"notification":
"title": "TITLE TEXT",
"body": "BODY TEXT",
"content_available": true
,
"data":
"body": "BODY TEXT",
"title": "TITLE TEXT",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
【讨论】:
感谢您的回复。好吧,我只是尝试使用真实设备,然后注意到我根本没有收到任何通知。但是昨天我在真实设备中收到通知,当它在前台时。然后我使用了content_available=true
并没有好。我认为我已经正确上传了 APN,否则我根本不应该收到任何通知,不是吗?当应用程序处于前台时,我会收到模拟器通知。
好的,我明白了,其实我不知道为什么。我在我的手机上试过,当应用程序关闭时我也无法收到通知。也许问题出在 firebase 消息包上。
"content_available": true 表示它是静默通知。请删除该标签。
谢谢 Jasmit,我不知道。抱歉信息不正确。【参考方案2】:
对于后台通知,您可以尝试添加 “后台模式” 功能,方法是在目标项目的 “签名和功能”下单击 “+ 功能” " 选项卡并按照以下苹果文档中的建议启用 远程通知。
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
您还应该在 AppDelegate.swift 中添加如下内容:
class AppDelegate: FlutterAppDelegate , UNUserNotificationCenterDelegate
override func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
....
UNUserNotificationCenter.current().delegate = self
....
....
// MARK: - UNUserNotificationCenterDelegate Method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
completionHandler([.alert])
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
【讨论】:
感谢您的回复,但这给出了错误。基本上它说您的方法仅适用于 iOS 10 及更高版本。我已经用这个更新了我的问题.. 另外,我似乎没有收到真实设备的通知。我的测试设备是 iPhone 6。 您是否在调试模式下通过连接测试通知?【参考方案3】:当他们在 firebase_messaging 6.0.16 中发现问题时,我遇到了一个非常相似的问题,现在它已更新到 7.0.0
我调整了我的 info.plist 并更改了
<key>FirebaseAppDelegateProxyEnabled</key><false/>
到
<key>FirebaseAppDelegateProxyEnabled</key>
<string>false</string>
奇怪的是,我的通知在 firebase_6.0.9 中工作,因为我没有升级到较新的。
我的 appdelegate 是:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool
GeneratedPluginRegistrant.register(with: self)
//FirebaseApp.configure()
if #available(iOS 10.0, *)
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
和你的有些不同。
【讨论】:
成功了,非常感谢!!我像您一样更改 info.plist 并更改 firebase_messaging 版本 6.0.9 及其工作。在此之前我使用版本 7.0.3【参考方案4】:您是否尝试过强制转换传递给 onMessage 回调的消息数据,
data = Map<String, dynamic>.from(message['data']);
【讨论】:
以上是关于Flutter Push Notifications:无法在后台或应用关闭时接收通知的主要内容,如果未能解决你的问题,请参考以下文章
laravel-push-notification 在响应正文中返回 html 标记
重复本地通知在 react-native-push-notification 中不起作用
资料整理:基于node push server实现push notification