Ios 静默推送通知未随UIBackgroundRefreshStatusDenied一起提供,但应用程序位于前台

Ios 静默推送通知未随UIBackgroundRefreshStatusDenied一起提供,但应用程序位于前台,ios,objective-c,Ios,Objective C,使用UIBackgroundRefreshStatusAvailable,我的应用程序会收到预期的静默推送通知,无论是在后台还是前台 此功能的名称--后台应用程序刷新--对我来说,它在禁用时不会影响前台应用程序的行为 不幸的是,我的应用程序在前台时没有收到静默推送通知,后台应用程序刷新被禁用,即uibackgroundrefreshtstatusdenied 我没有使用用户可见的推送通知,因此没有参与UNUserNotificationCenter等 是否可以在后台应用程序刷新被禁用的情况下接收

使用
UIBackgroundRefreshStatusAvailable
,我的应用程序会收到预期的静默推送通知,无论是在后台还是前台

此功能的名称--后台应用程序刷新--对我来说,它在禁用时不会影响前台应用程序的行为

不幸的是,我的应用程序在前台时没有收到静默推送通知,后台应用程序刷新被禁用,即
uibackgroundrefreshtstatusdenied

我没有使用用户可见的推送通知,因此没有参与
UNUserNotificationCenter

是否可以在后台应用程序刷新被禁用的情况下接收静默推送通知,即
uibackgroundrefreshtstatusdenied

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
}
以下是启用bg应用程序刷新时收到的示例
userInfo
didReceiveMemotentification:

{
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";
    };
};

}这是一个有趣的问题,因为它基本上解决了命名这个相当复杂的功能的问题

简言之,我恐怕答案是否定的。虽然我自己不必处理这个问题,但我已经看到许多其他人与你处于相同的地位

对我来说,将整个“静默远程通知功能”看作与应用程序处于前台或后台的关系不大,而与“远程应用程序输入”的关系更大,这会有所帮助:

如果它被激活,即您有可用的
uibackgroundRefreshStatus
,您的服务器可以无声地发送它,在这种情况下,它会对其作出反应。基本上,服务器以与用户点击类似的方式提供输入(当然是通过不同的调用函数)。不管应用程序是在前台还是后台,这种输入都会发生

如果该功能处于非活动状态,即您有
uibackgroundrefreshtstatusdenied
uibackgroundrefreshtstatusrestricted
,则整个功能将关闭。这意味着这种接收输入的方式不起作用,
application:didReceiveMemotentification:fetchCompletionHandler:
根本不被调用。无可否认,这个方法名称比state enum案例更好地反映了这个问题


两种解决方法

  • 最明显的一点是:在
    applicationIDBecomeActive:
    applicationWillResignActive:
    中注册和注销远程通知。不幸的是,这可能会变得丑陋,因为它会导致服务器不断地为用户更改令牌,但如果您想不惜任何代价避免在后台收到通知,请这样做
  • 注册一次通知,让您的逻辑处理前台和后台的通知,就像您(似乎)已经做的那样,但只需使其在后台忽略通知即可(使用
    UIApplication.shared.applicationState
    )。从技术上讲,这“浪费”了一点运行时间,因为你的应用程序可能会被唤醒,然后不会做任何有意义的事情,但我认为这并不太糟糕
  • 我自己也会选择选项2,因为我很少看到在后台收到一个无声的通知会带来伤害

    一般来说,我不会做任何依赖于启用通知的事情(后台或前台)。换言之:是的,如果我的应用程序位于前台,并且我需要对服务器上发生的事情做出反应,我恐怕需要“检查”所述服务器,即以某种形式从服务器中取出

    或者,根据具体情况,我会通知用户他们应该启用它,否则应用程序就没有多大意义了。。。嗯


    作为旁注:是的,苹果SDK在命名和解释所有不同的背景内容和通知时有点混乱。甚至应用程序状态本身(活动、非活动、背景、前景、暂停等)也比名称看起来更复杂。我认为这是历史的原因。在我们有背景模式和通知之前,人们只是轮询数据以获得类似“无声前景通知”的东西,基本上就是你想要的东西。因此,最终他们希望在应用程序不在前台时也能这样做,大声要求后台执行。苹果并不是真的想不受限制地同意这一点,通知的概念发展得如此缓慢,但由于它有点相关,术语“背景”就潜入其中(此外,我们也有背景提取…),即使它不一定有意义。
    也有人可能会说它仍然是有效的,因为它对于应用程序处于后台/挂起状态更为重要。“仅在前台时获取静默通知”的用例仍然可以通过简单的轮询来覆盖(尽管我同意这很难看),并且如果使用push,也可以在后台获取这些通知

    因此,您的解决方案是要么用用户可见的通知替换静默通知,要么轮询后端,对吗?我编辑了我的答案。在某种程度上,是的,如果我无法避免的话。如果你有一个非常依赖服务器通知应用程序的东西,而用户已经禁用了通知,那么你需要用另一种方式进行检查。不过,我想说的是,这还需要回答另一个问题,因为无论应用程序状态如何,远程通知在禁用时都不起作用。仔细想想,我有一种预感,也许你打算将通知作为与服务器进行连续消息交换的一种形式。这并不是最好的方式,因为任何通知都不能保证按时到达,过多的通知可能会导致iOS限制它们。对于聊天之类的事情,我推荐WebSockets,它从iOS 13开始就得到了很好的支持,例如,请参阅教程“您可以共享apns请求的有效负载吗?”@AhmetAYGÜN I hav