在我们的应用中,我们希望下载少量数据以响应推送通知。到目前为止,推送通知工作正常,在后台启动应用程序并导致调用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);
});
}
响应推送,应用程序在后台启动,徽章计数设置为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) {}
});
答案 0 :(得分:10)
首先选择here并确保启用推送通知并添加内容可用字段:
使用推送通知启动下载 如果您的服务器在您的应用有新内容时向用户的设备发送推送通知,您可以要求系统在后台运行您的应用,以便它可以立即开始下载新内容。此背景模式的目的是最小化用户看到推送通知与您的应用程序能够显示关联内容之间经过的时间。应用程序通常会在用户看到通知的大致相同的时间唤醒,但仍然比您提供的时间更长。 要支持此后台模式,请从Xcode项目的“功能”选项卡的“后台模式”部分启用“远程通知”选项。 (您还可以通过在应用程序的Info.plist文件中包含带有远程通知值的UIBackgroundModes键来启用此支持。) 对于触发下载操作的推送通知,通知的有效负载必须包含内容可用密钥,其值设置为1.当存在该密钥时,系统会在后台唤醒应用程序(或将其启动到后台)并且调用app delegate的应用程序: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;
}
}];
然后做你的背景工作。 不要忘记在工作完成后结束任务。打电话给 -
if (backgroundTaskId != UIBackgroundTaskInvalid) {
[application endBackgroundTask:backgroundTaskId];
backgroundTaskId = UIBackgroundTaskInvalid;
}