在应用程序以应用程序为前提之前,异步代码不会执行:didReceiveRemoteNotification:fetchCompletionHandler:

Jef*_*ith 11 asynchronous objective-c push-notification apple-push-notifications ios

在我们的应用程序中,我们希望下载少量数据以响应推送通知.到目前为止,推送通知工作正常,在后台启动应用程序并导致调用didReceiveRemoteNotification.

问题是,在此方法返回之后,应用程序不再获得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);
    });
}
Run Code Online (Sandbox Code Playgroud)

响应推送,应用程序在后台启动,徽章计数设置为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) {}
});
Run Code Online (Sandbox Code Playgroud)

Yos*_*bab 10

首先在此处确保启用推送通知并添加内容可用字段:

使用推送通知启动下载如果您的服务器在您的应用有新内容时向用户的设备发送推送通知,您可以要求系统在后台运行您的应用,以便它可以立即开始下载新内容.此背景模式的目的是最小化用户看到推送通知与您的应用程序能够显示关联内容之间经过的时间.应用程序通常会在用户看到通知的大致相同的时间唤醒,但仍然比您提供的时间更长.要支持此后台模式,请从Xcode项目的"功能"选项卡的"后台模式"部分启用"远程通知"选项.(您还可以通过在应用程序的Info.plist文件中包含带有远程通知值的UIBackgroundModes键来启用此支持.)对于触发下载操作的推送通知,通知的有效内容必须包含内容可用密钥及其值当该键存在时,系统会在后台唤醒应用程序(或将其启动到后台)并调用应用程序委托的应用程序:didReceiveRemoteNotification:fetchCompletionHandler:method.您对该方法的实施应下载相关内容并将其集成到您的应用中.下载任何内容时,建议您使用NSURLSession类来启动和管理下载.有关如何使用此类管理上载和下载任务的信息,请参阅URL加载系统编程指南.

接下来,有没有理由你使用"dispatch_after"延迟2秒?

有可能因为你在运行循环结束时调用"dispacth_after",iOS"认为"没有待处理的工作要做并将进程置于休眠状态,因此在调度块时没有人正在监听它.

用"dispatch_async"替换它可能会解决这个问题.

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

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

然后做你的背景工作.不要忘记在工作完成后结束任务.打电话给像 -

if (backgroundTaskId != UIBackgroundTaskInvalid) {
        [application endBackgroundTask:backgroundTaskId];
        backgroundTaskId = UIBackgroundTaskInvalid;
    }
Run Code Online (Sandbox Code Playgroud)