11

在我们的应用程序中,我们希望下载少量数据以响应推送通知。到目前为止,推送通知运行正常,在后台启动应用程序并导致调用didReceiveRemoteNotification。直到应用程序在应用程序中发现时才执行异步代码:didReceiveRemoteNotification:fetchCompletionHandler:

问题是,在此方法返回后,应用程序不会再获得更多的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',并且我不会通过在应用程序切换器中向上滑动来退出应用程序。

要添加,我们使用解析使用下面的JavaScript发送此推送通知:

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

你试过这个:http://stackoverflow.com/questions/16295953/dispatch-after-is-limited-to-10-seconds? – anhtu

回答

10

先来here,并确保您启用推送通知和添加的内容可用字段:

使用推送通知启动下载 如果您的应用程序有新内容可用时,服务器将推送通知发送到用户设备,则可以让系统在后台运行您的应用程序,以便它可以开始下载新的内容马上。此背景模式的目的是尽可能减少用户看到推送通知到应用程序能够显示相关内容的时间。应用程序通常在用户看到通知的大致同一时间醒来,但仍然会给您比您可能得到的更多时间。 要支持此背景模式,请从Xcode项目中Capabilities选项卡的Background modes部分启用Remote notifications选项。 (您也可以通过在您的应用程序的Info.plist文件中包含带有远程通知值的UIBackgroundModes项来启用此支持。) 对于推送通知来触发下载操作,通知的有效内容必须包含带有内容的密钥值设置为1.当该键存在时,系统在后台唤醒应用程序(或将其启动到后台)并调用应用程序委托的应用程序: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; 
    } 
+0

使用后台任务是它! dispatch_after 2秒只是为了将问题简化为最简单的情况。实际上,我们将使用dispatch_async。但是这里的主要问题是iOS似乎认为我们在主runloop完成它的循环时完成了执行,而不是当调用完成处理程序时。通过使用后台任务,iOS为我们提供了运行时间并执行所需的异步操作。 – jsmeez

相关问题