如果应用程序已终止,将调用 performFetchWithCompletionHandler

Will performFetchWithCompletionHandler be called if the app has been terminated

要找到一个明确的答案是非常困难的;在 Apple 文档中找不到它,并且在搜索过去的问题后找不到明确的 yes/no。

问题很简单 - 如果应用程序请求在 N 次后执行后台提取,则用户终止该应用程序。 OS 是否仍会在后台启动应用程序以执行后台提取?

编辑:

https://devforums.apple.com/message/873265#873265(需要登录)

Also keep in mind that if you kill your app from the app switcher (i.e. swiping up to kill the app) then the OS will never relaunch the app regardless of push notification or background fetch. In this case the user has to manually relaunch the app once and then from that point forward the background activities will be invoked. -pmarcos

post 是 Apple 员工提供的,所以我认为我可以相信此信息是正确的。


旧答案:

根据顶级用户的回答:iOS background fetch:您的应用不会再次被唤醒。

Make sure you're not killing the app (i.e. by double tapping on the home button and swiping up on your app for force the app to terminate). If the app is killed, it will prevent background fetch from working correctly.

它被唤醒真的没有意义......它有点让用户杀死应用程序无效。

话虽如此,terminated/force 退出的应用程序可以通过不同的方式再次启动:

  • 点击通知。
  • 点击应用程序图标。
  • 使用 openUrl 从另一个应用程序打开您的应用程序。
  • 如果你使用PushKit...then your app would be launched. Imagine if had a VOIP app e.g. Skype, WhatsApp and a friend was calling you but you had have force-quit the app, you wouldn't receive calls. For more see here.
  • 通过使用来自 Apple 文档的 region monitoring or the significant-change location service. See and make sure to read this entire page 来更新位置。

  • 重新启动设备也会撤消任何通过强制退出

  • 阻止的内容

阅读 Apple 文档 here 我发现这段文字片段应该可以解释您的问题:

The techniques offered by iOS fall into three categories:

    Apps that start a short task in the foreground can ask for time to finish that task when the app moves to the background.

    **Apps that initiate downloads in the foreground can hand off management of those downloads to the system, thereby allowing the app to be suspended or terminated while the download continues.**

    Apps that need to run in the background to support specific types of tasks can declare their support for one or more background execution modes.

第二个选项就是下载数据,即使可以终止也可以委托给系统

好的,后台模式又一次引起了混乱。没有冒犯其他试图提供帮助的人,但是这比看起来要复杂

首先: This is out of date, as Sausage guessed in the comments. I know this for a fact, because the section about VoIP apps is still explaining the "old way" to do this, with a handler that gets called periodically. I investigated this a bit for ,所以我建议你去读一下。这个案例的重要教训是,iOS 区分应用程序被用户或系统终止,此外,它还在 phone 是否重新启动时发挥作用。

所以总结这个(和你的问题)你基本上想知道上面这部分过时的文档是否仍然逐字正确:

In most cases, the system does not relaunch apps after they are force quit by the user. One exception is location apps, which in iOS 8 and later are relaunched after being force quit by the user. In other cases, though, the user must launch the app explicitly or reboot the device before the app can be launched automatically into the background by the system. When password protection is enabled on the device, the system does not launch an app in the background before the user first unlocks the device.

Apple: Understanding When Your App Gets Launched into the Background

我彻底调查了其余的文档,但没有找到任何明确的答案,所以不幸的是归结为 dan 已经建议的内容:测试它。不过,我的直觉是文档在这方面仍然是正确的(正如所说,VoIP 的东西不是)。我这么说是因为设置应用程序中的 UI 调用了“后台应用程序刷新”功能,所以用户可能应该理解具有此权限的应用程序在他们将它们“推出”后台时不会刷新(即主页按钮 -> 将其滑出)。对于普通用户,应用程序要么退出(根本不在任务管理器中)、在前台(使用它们)或在后台(它们在任务管理器中,另一个应用程序在前台 and/or phone 已锁定)。


要真正对此进行测试,您必须编写一个应用程序并在每种情况下实际携带它(我假设至少两天)。首先当它在后台时(OS 应该定期让它获取,你可能知道这也可以在 Xcode 中触发)然后当它强制退出时。问题是验证它是否获取了东西。我会选择一个可以通过 iTunes 共享的日志文件。我为此输入了一些代码:

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"We're awake! Booyah!");
    
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config
                                                          delegate:nil
                                                     delegateQueue:[NSOperationQueue mainQueue]];
    NSMutableURLRequest *request = [NSMutableURLRequest new];
    request.HTTPMethod = @"GET";
    request.URL = [NSURL URLWithString:@"https://www.google.com"];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData * _Nullable data,
                                                                NSURLResponse * _Nullable response,
                                                                NSError * _Nullable error) {
                                                NSDate *now = [NSDate date];
                                                NSString *toLog = [NSString stringWithFormat:@"%@ - fetched\n",
                                                                   [now description]];
                                                [self updateTestDocumentWithString:toLog];
                                                NSLog(@"Yay, done!");
                                                completionHandler(UIBackgroundFetchResultNewData);
                                            }];
    [task resume];
}

- (void)updateTestDocumentWithString:(NSString *)toAppend {
    NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *filePath = [[docDir stringByAppendingPathComponent:@"logfile.txt"] copy];
    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        if (![[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]) {
            NSLog(@"We're effed...");
            return;
        }
    }
    NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
    if (!file) {
        NSLog(@"We're effed again...");
        return;
    }
    [file seekToEndOfFile];
    // ensure this is never nil
    [file writeData:[toAppend dataUsingEncoding:NSUTF8StringEncoding]];
    [file closeFile];
}

这将进入应用委托,并且不要忘记在应用的 plist 中添加 Application supports iTunes file sharing 布尔值设置。我将把这个 运行 留在我的开发设备上一段时间并检查日志文件,最终在这里报告。你也可以自己测试一下。