UIBackgroundRefreshStatusDenied 未发送静默推送通知,但应用程序在前台
Posted
技术标签:
【中文标题】UIBackgroundRefreshStatusDenied 未发送静默推送通知,但应用程序在前台【英文标题】:Silent push notification not delivered with UIBackgroundRefreshStatusDenied but app in foreground 【发布时间】:2020-05-06 13:21:19 【问题描述】:使用UIBackgroundRefreshStatusAvailable
,我的应用程序按预期接收静默推送通知,无论是在后台还是前台。
此功能的名称 -- Background App Refresh -- 向我表明它在禁用时不会影响 Foreground 应用程序的行为。
不幸的是,我的应用在前台中没有收到静默推送通知,后台应用刷新被禁用,即UIBackgroundRefreshStatusDenied
。
我没有使用用户可见的推送通知,因此UNUserNotificationCenter
等没有参与。
是否可以在禁用后台应用刷新的情况下接收静默推送通知,即UIBackgroundRefreshStatusDenied
?
Objective-C,Xcode 11.3.1,部署目标 ios 10.3。安装了 iOS 12.4.5 的 iPhone 6。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
[application registerForRemoteNotifications];
return YES;
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
// not called when app in foreground but bg app refresh turned off
这是一个示例userInfo
dict,didReceiveRemoteNotification
在启用 bg 应用刷新时收到:
aps =
"content-available" = 1;
;
ck =
ce = 2;
cid = "iCloud.de.udo-thiel.DiskBench";
ckuserid = "_56bd97c2eb1e52d09756163efaab6b02";
nid = "e70e4a8d-d77b-4315-8b3e-d9de229cf083";
qry =
dbs = 2;
fo = 2;
rid = "Res-iPad 2-16";
sid = "public-results2";
zid = "_defaultZone";
zoid = "_defaultOwner";
;
;
【问题讨论】:
能分享一下apns请求的payload吗? @AhmetAYGÜN 我添加了一个示例userInfo
,这就是您要的吗?
【参考方案1】:
这是一个有趣的问题,因为它基本上解决了命名这个相当复杂的功能的问题。
简而言之,恐怕答案是否定的。虽然我自己不需要处理这个问题,但我目睹了许多其他人与你处于相同的位置。
对我来说,将整个“静默远程通知功能”视为与应用程序处于前台或后台的关系较小,而与“远程应用程序输入”的关系更大:
如果它被激活,即你有UIBackgroundRefreshStatusAvailable
,你的服务器可以静默地发送它,在这种情况下,消息对它做出反应。基本上,服务器以与用户点击类似的方式提供输入(尽管显然是通过不同的调用函数)。不管应用程序是在前台还是后台,这个输入发生。
如果该功能处于非活动状态,即您有UIBackgroundRefreshStatusDenied
或UIBackgroundRefreshStatusRestricted
,则整个功能都将关闭。这意味着这种接收输入的方式不起作用,application:didReceiveRemoteNotification:fetchCompletionHandler:
根本不会被调用。诚然,此方法名称比状态枚举案例更能反映问题。
两种解决方法:
-
最明显的一个:在
applicationDidBecomeActive:
和applicationWillResignActive:
中注册和注销远程通知。不幸的是,这可能会变得很难看,因为它会导致您的服务器为用户不断更改令牌,但如果您想不惜一切代价避免在后台收到通知,请采用这种方式。
注册一次通知,确实让您的逻辑处理前台和后台的通知,就像您(似乎)已经做的那样,但只需让它在后台时忽略通知(使用UIApplication.shared.applicationState
)。从技术上讲,这会“浪费”一些运行时间,因为您的应用可能会被唤醒,然后没有做任何有意义的事情,但我认为这还不错。
我自己会选择选项 2,因为我很少看到在后台收到无提示通知会很痛苦的情况。
通常我不会做任何依赖于启用通知的事情(后台或前台)。换一种说法:是的,如果我的应用程序在前台并且我需要对服务器上发生的事情做出反应,恐怕我需要“检查”所述服务器,即以某种形式从中提取。
或者我会根据情况通知用户他们应该启用它,否则应用程序将没有多大意义......嗯......
附带说明:是的,Apple SDK 在命名和解释所有不同的背景事物和通知方面有点混乱。甚至应用程序状态本身(活动、非活动、后台、前台、暂停......)也比名称看起来更复杂。我认为其原因本质上是历史性的。在我们完全没有后台模式和通知之前,人们只是轮询数据以获得“无声前台通知”之类的东西,基本上就是你想要的东西。所以最终他们希望在应用程序不在前台时也能做到这一点,大声要求后台执行。 Apple 并不想无限制地授予这一点,所以通知概念发展缓慢,但由于它有点相关,“背景”一词潜入其中(此外,我们也有背景获取......),甚至如果它不一定有意义。 人们也可能会争辩说它仍然是有效的,因为它对于应用程序处于后台/暂停时更为重要。 “在前台获得静默通知仅”的用例仍然可以通过简单的轮询来覆盖(尽管我同意这很丑陋),如果你使用推送它不会伤害 也让那些在后台。
【讨论】:
所以您的解决方案是用用户可见的通知替换静默通知,或者轮询后端,对吗? 我编辑了我的答案。在某种程度上,是的,如果我无法避免的话。如果您的某些东西极度依赖服务器通知应用程序某事并且用户禁用了通知,则您需要以另一种方式检查。不过,我会说,这将引起另一个问题,因为无论应用程序处于何种状态,远程通知在禁用时都不起作用。 考虑到这一点,我预感到您可能打算使用通知作为与服务器进行持续消息交换的一种形式。这不是最好的方法,因为任何通知都不能保证准时到达,而且太多可能会导致 iOS 限制它们。对于聊天之类的事情,我推荐 WebSockets,它从 iOS 13 开始就得到很好的支持,例如教程 here以上是关于UIBackgroundRefreshStatusDenied 未发送静默推送通知,但应用程序在前台的主要内容,如果未能解决你的问题,请参考以下文章