8

我对这个话题很头疼。我正在开发一个需要定期轮询网络服务器以检查新数据的应用程序。根据返回的信息,我希望向用户推送本地通知。

我知道这种方法与 Apple 所描述的方法略有不同,在这种方法中,远程服务器进行工作,基于 APNS 推送远程通知。但是,有很多原因我不能考虑这种方法。其中之一就是用户认证机制。出于安全原因,远程服务器不能考虑用户凭据。我所能做的就是将登录和获取核心移动到客户端(iPhone)。

我注意到 Apple 为应用程序提供了唤醒并保持打开 Socket 连接(即 VoIP 应用程序)的机会。

于是,我开始以这种方式进行调查。在 plist 中添加了所需的信息,我可以在我的 appDelegate 中使用类似的东西“唤醒”我的应用程序:

[[UIApplication sharedApplication] setKeepAliveTimeout:1200 handler:^{ 
    NSLog(@"startingKeepAliveTimeout");
    [self contentViewLog:@"startingKeepAliveTimeout"];
    MyPushOperation *op = [[MyPushOperation alloc] initWithNotificationFlag:0 andDataSource:nil];
    [queue addOperation:op];
    [op release];
}];

NSOperation,然后使用以下代码块启动后台任务:

#pragma mark SyncRequests
-(void) main {
    NSLog(@"startSyncRequest");
    [self contentViewLog:@"startSyncRequest"];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
        NSLog(@"exipiration handler triggered");
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
        [self cancel];
    }];


        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSMutableURLRequest *anURLRequest;
            NSURLResponse *outResponse;
            NSError *exitError;
            NSString *username;
            NSString *password;

            NSLog(@"FirstLogin");
            anURLRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:webserverLogin, username, password]]];
            [anURLRequest setHTTPMethod:@"GET"];
            [anURLRequest setTimeoutInterval:120.00];
            [anURLRequest setCachePolicy:NSURLRequestReloadIgnoringCacheData];

            exitError = nil;
            NSData *tmpData = [NSURLConnection sendSynchronousRequest:anURLRequest returningResponse:&outResponse error:&exitError];
            [anURLRequest setTimeoutInterval:120.00];
            if(exitError != nil) { //somethings goes wrong
                NSLog(@"somethings goes wrong");
                [app endBackgroundTask:bgTask];
                bgTask = UIBackgroundTaskInvalid;
                [self cancel];
                return;
            }

            //do some stuff with NSData and prompt the user with a UILocalNotification

            NSLog(@"AlltasksCompleted");
            [app endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
            [self cancel];
        });
    }
}

上面的代码似乎工作(有时),但许多其他它使我的应用程序崩溃,并带有以下日志信息:

Exception Type:  00000020
Exception Codes: 0x8badf00d
Highlighted Thread:  3

Application Specific Information:
DemoBackApp[5977] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0xa9da0b0> identifier: UIKitBackgroundCompletionTask process: DemoBackApp[5977] permittedBackgroundDuration: 600.000000 reason: finishTask owner pid:5977 preventSuspend  preventIdleSleep 
)}

Elapsed total CPU time (seconds): 0.010 (user 0.010, system 0.000), 100% CPU 
Elapsed application CPU time (seconds): 0.000, 0% CPU

对于那些问的人,是的。我也尝试过 Async NSURLConnection 方法。不管。即使我使用带有超时处理程序和 didFinishLoading:WithError 的异步方法,它也会崩溃。

我被困住了。任何提示都非常感谢。

4

4 回答 4

9

这是一个旧线程,但可能需要更新。

从 iOS 6 开始,这是我在此线程中讨论的 VoIP 计时器后台方法看到的行为:

  • VoIP BackgroundMode 仍被 AppStore 应用程序通过 App Review Process 严格禁止
  • 最短 KeepAlive 时间为 600 秒;小于此值的任何内容都将导致处理程序无法安装(并向 NSLog 发送警告)
  • 将 keepAlive 时间设置为明显大于 600 秒的时间通常会导致处理程序以每次/2间隔的频率被触发。奖励事实:这与 SIP REGISTER 请求一致,其中建议的重新注册间隔为 0.5*重新注册时间。
  • 当调用 keepAlive 处理程序时,我观察到以下情况:
    • 您将获得大约10 秒的“前台”执行时间,其中剩余的后台时间是无限的(由backgroundTimeRemaining返回)
    • 如果您从 keepAlive 处理程序中启动beginBackgroundTask,我观察到您会获得60 秒的后台执行时间(由backgroundTimeRemaining返回)。这与用户从您的应用程序处于活动状态到后台转换时获得的600 秒不同。我还没有找到任何延长时间的方法(不使用位置等其他技巧)

希望有帮助!

于 2013-04-18T19:16:33.480 回答
7

当您调用 时-setKeepAliveTimeout:handler:,您最多只能有 30 秒的时间来完成所有操作并暂停。您没有获得与您的应用程序首次转换到后台时相同的后台宽限期。这意味着完成长时间运行的任务,关闭事物等。

使用 VOIP 回调,您只需将需要发送的任何 ping 数据包发送到您的服务,以保持网络连接处于活动状态且不会超时。30 秒后,无论是否启动新的后台任务,如果您的应用程序仍在执行,您将被终止。

此外,请务必注意,如果您实际上不是 VOIP 应用程序,或者如果您在 VOIP 回调窗口期间执行了与保持网络连接打开无关的任何操作,您的应用程序被应用商店拒绝。当您设置任何保持活动标志(VOIP、背景音乐、导航)时,他们会对其进行非常严格的测试,以确保它在后台执行标记为执行的操作。执行任何类型的 HTTP GET 请求并等待一些大数据更新返回几乎肯定会让您的应用程序被拒绝。

编辑:正如 Patrick 在评论中所指出的,在 iOS 5 中,当前执行块的时间已从 30 秒减少到 10 秒。每当您重新链接时,最好留意这些时间您的应用程序需要新版本的 SDK,至少要快速检查文档以防更新(随着 iOS 6 的推出,这个数字可能会再次调整)。

于 2011-01-24T00:29:16.533 回答
6

只是为了更新 iOS7 的这种行为。

  • 当您的应用程序首次进入后台时,您将获得 180 秒的任务时间,如 backgroundTimeRemaining 所报告的。但是,它会在此时间用完前 5 秒停止响应,如 backgroundTimeRemaining 所报告的。
  • 当 keepAlive 任​​务触发时,backgroundTimeRemaining 是 10 秒的前台,然后是 60 秒的后台计时器,由 backgroundTimeRemaining 报告。它还会在此时间用完前 5 秒停止响应,如 backgroundTimeRemaining 所报告的。

所以在 iOS7 上你每 10 分钟可以获得 65 秒的处理时间。

于 2013-09-30T00:25:26.010 回答
3

似乎您可以通过在您被调用时捎带对有限后台任务执行的请求来组合保持活动超时处理程序。每次调用 VOIP 保持活动处理程序时,这将允许您有整整 10 分钟的时间(通常是 10-30 秒)。

仍然存在与上述相同的问题 - 因为您需要在 plist 中提交 VOIP 标志,如果您有该标志并且实际上不是 VOIP 应用程序,而是用于内部分发(企业或否则),此解决方案应该可以很好地为您提供后台时间。

在我的测试中,每次调用 VOIP 处理程序时都会重置 10 分钟有限执行计时器(无论用户从那时起是否将应用程序置于最前面),这意味着您可以在每 600 秒(10 分钟)后台一次,轮询过程可能需要长达 10 分钟才能进入睡眠状态(如果您需要,这意味着几乎持续的后台操作)。

同样,除非您能说服他们您是 VOIP,否则 App Store 并不是真正的选择。

于 2012-09-06T23:58:32.537 回答