异步代码不会执行,直到应用程序在 application:didReceiveRemoteNotification:fetchCompletionHandler 中出现:

Asynchronous code doesn't execute until app foregrounded in application:didReceiveRemoteNotification:fetchCompletionHandler:

在我们的应用中,我们想要下载少量数据以响应推送通知。到目前为止,推送通知工作顺利,在后台启动应用程序并调用 didReceiveRemoteNotification。

问题是,在这个方法 returns 之后,应用程序不再获得 CPU 时间,直到它再次进入前台,所以没有机会在后台异步获取该数据.

简化为最简单的情况,我仍然无法获取异步代码运行。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [application setApplicationIconBadgeNumber:1];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [application setApplicationIconBadgeNumber:9];

        completionHandler(UIBackgroundFetchResultNewData);
    });
}

为了响应推送,应用程序在后台启动并且标记计数设置为 1,但直到应用程序从主屏幕启动时标记数才设置为 9。

不应该 iOS 保留 运行 应用程序直到调用完成处理程序,最多 30 秒?

Info.plist 指定了远程通知后台模式,推送负载包含 'content-available' : '1',并且我不会通过在应用程序切换器中向上滑动来退出应用程序。

要补充一点,我们使用 Parse 通过以下 Javascript 发送此推送通知:

Parse.Push.send({
    where: installationQuery,
    data: {
        "content-available": 1,
    }
}, { success: function() {},
    error: function(error) {}
});

首先获取 here 并确保您启用了推送通知并添加了内容可用字段:

Using Push Notifications to Initiate a Download If your server sends push notifications to a user’s device when new content is available for your app, you can ask the system to run your app in the background so that it can begin downloading the new content right away. The intent of this background mode is to minimize the amount of time that elapses between when a user sees a push notification and when your app is able to able to display the associated content. Apps are typically woken up at roughly the same time that the user sees the notification but that still gives you more time than you might have otherwise. To support this background mode, enable the Remote notifications option from the Background modes section of the Capabilities tab in your Xcode project. (You can also enable this support by including the UIBackgroundModes key with the remote-notification value in your app’s Info.plist file.) For a push notification to trigger a download operation, the notification’s payload must include the content-available key with its value set to 1. When that key is present, the system wakes the app in the background (or launches it into the background) and calls the app delegate’s application:didReceiveRemoteNotification:fetchCompletionHandler: method. Your implementation of that method should download the relevant content and integrate it into your app. When downloading any content, it is recommended that you use the NSURLSession class to initiate and manage your downloads. For information about how to use this class to manage upload and download tasks, see URL Loading System Programming Guide.

接下来,您使用延迟 2 秒的 "dispatch_after" 有什么原因吗?

可能是因为您在 运行 循环结束时调用了 "dispacth_after" iOS "thinks" 没有待处理的工作要做并使进程进入睡眠状态所以当块被调度时,没有人在听它。

将其替换为 "dispatch_async" 可能会解决此问题。

最后,如果你确实需要延迟,你应该告诉 iOS 你需要一些时间在后台,就像这样 -

    UIApplication *application = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block backgroundTaskId = [application beginBackgroundTaskWithExpirationHandler:^{
    if (backgroundTaskId != UIBackgroundTaskInvalid) {
        [application endBackgroundTask:backgroundTaskId];
        backgroundTaskId = UIBackgroundTaskInvalid;
    }
}];

然后做你的后台工作。 完成工作后不要忘记结束任务。调用类似 -

if (backgroundTaskId != UIBackgroundTaskInvalid) {
        [application endBackgroundTask:backgroundTaskId];
        backgroundTaskId = UIBackgroundTaskInvalid;
    }