热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何解决iOS后台应用程序取消无法解决?-HowtotroubleshootiOSbackgroundappfetchnotworking?

IamtryingtogetiOSbackgroundappfetchtoworkinmyapp.WhiletestinginXcodeitworks,when

I am trying to get iOS background app fetch to work in my app. While testing in Xcode it works, when running on the device it doesn't!

我想让iOS后台应用程序获取在我的应用程序中工作。在Xcode中进行测试时,它可以正常运行,但在设备上运行却没有!

  • My test device is running iOS 9.3.5 (my deployment target is 7.1)
  • 我的测试设备运行的是iOS 9.3.5(我的部署目标是7.1)
  • I have enabled "Background fetch" under "Background modes" under "Capabilities" on the target in Xcode
  • 我在Xcode中的目标“Capabilities”下的“Background modes”下启用了“Background fetch”

enter image description here

In application:didFinishLaunchingWithOptions I have tried various intervals with setMinimumBackgroundFetchInterval, including UIApplicationBackgroundFetchIntervalMinimum

在应用程序中:didFinishLaunchingWithOptions我用setMinimumBackgroundFetchInterval尝试了各种间隔,包括UIApplicationBackgroundFetchIntervalMinimum

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    // tell the system we want background fetch
    //[application setMinimumBackgroundFetchInterval:3600]; // 60 minutes
    [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
    //[application setMinimumBackgroundFetchInterval:1800]; // 30 minutes

    return YES;
}

I have implemented application:performFetchWithCompletionHandler

我已经实现了application:performFetchWithCompletionHandler

void (^fetchCompletionHandler)(UIBackgroundFetchResult);
NSDate *fetchStart;

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    fetchCompletiOnHandler= completionHandler;

    fetchStart = [NSDate date];

    [[NSUserDefaults standardUserDefaults] setObject:fetchStart forKey:kLastCheckedContentDate];
    [[NSUserDefaults standardUserDefaults] synchronize];

    [FeedParser parseFeedAtUrl:url withDelegate:self];
}

 -(void)onParserFinished
{
    DDLogVerbose(@"AppDelegate/onParserFinished");

    UIBackgroundFetchResult result = UIBackgroundFetchResultNoData;

    NSDate *fetchEnd = [NSDate date];
    NSTimeInterval timeElapsed = [fetchEnd timeIntervalSinceDate:fetchStart];
    DDLogVerbose(@"Background Fetch Duration: %f seconds", timeElapsed);
    if ([self.mostRecentContentDate compare:item.date] <0) {
        DDLogVerbose(@"got new content: %@", item.date);
        self.mostRecentCOntentDate= item.date;
        [self scheduleNotificationWithItem:item];
        result = UIBackgroundFetchResultNewData;
    }
    else {
        DDLogVerbose(@"no new content.");
        UILocalNotification* localNotification = [[UILocalNotification alloc] init];
        localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:60];
        localNotification.alertBody = [NSString stringWithFormat:@"Checked for new posts in %f seconds", timeElapsed];
        localNotification.timeZOne= [NSTimeZone defaultTimeZone];
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    }

    fetchCompletionHandler(result);
}
  • I have (successfully!) tested with the simulator and device using Xcode's Debug/SimulateBackgroundFetch

    我已经(使用Xcode的Debug / SimulateBackgroundFetch)对模拟器和设备进行了测试(成功!)

  • I have successfully tested with a new scheme as shown in another SO answer (https://stackoverflow.com/a/29923802/519030)

    我已经成功测试了一个新方案,如另一个SO答案所示(https://stackoverflow.com/a/29923802/519030)

  • My tests show code executing in the performFetch method in about 0.3 seconds (so it's not taking a long time)
  • 我的测试显示在大约0.3秒内在performFetch方法中执行的代码(所以它不需要很长时间)
  • I have verified that the device has background refresh enabled within settings.
  • 我已验证设备在设置中启用了后台刷新。
  • Of course, I've looked at the other SO questions hoping someone else experienced the same thing. :)
  • 当然,我已经看过其他SO问题,希望其他人经历同样的事情。 :)

When running on the device and not connected to Xcode, my code is not executing. I've opened the app, closed the app (not killed the app!), waited hours and days. I have tried logging in the fetch handers, and also written code to send local notifications.

在设备上运行但未连接到Xcode时,我的代码没有执行。我打开了应用程序,关闭了应用程序(没有杀死应用程序!),等待了几个小时和几天。我已经尝试登录fetch handers,还编写了代码来发送本地通知。

I once successfully saw my local notifications test on the device, and in fact iOS seemed to trigger the fetch three times, each about about fifteen minutes apart, but then it never occurred again.

我曾经成功地在设备上看到了我的本地通知测试,事实上iOS似乎触发了三次获取,每次大约相隔大约十五分钟,但之后它再也没有发生过。

I know the algorithm used to determine how frequently to allow the background fetch to occur is a mystery, but I would expect it to run at least occasionally within a span of days.

我知道用于确定允许背景提取发生频率的算法是一个谜,但我希望它能在一段时间内偶尔运行。

I am at a loss for what else to test, or how to troubleshoot why it seems to work in the simulator but not on the device.

我无法测试其他什么,或者如何解决为什么它似乎在模拟器中工作但不在设备上工作。

Appreciate any advice!

感谢任何建议!

2 个解决方案

#1


20  

Your problem is that you are returning from performFetchWithCompletionHandler before you call the completion handler, since the network fetch operation is occurring the in the background and you call the completion handler in your delegate method. Since iOS thinks you aren't playing by the rules it will deny your ability to use background fetch.

您的问题是您在调用完成处理程序之前从performFetchWithCompletionHandler返回,因为网络提取操作正在后台进行,您在委托方法中调用完成处理程序。由于iOS认为您不遵守规则,因此它将拒绝您使用后台获取的能力。

To fix the problem you need to call beginBackgroundTaskWithExpirationHandler and then end that task after you have called the completion handler.

要解决此问题,您需要调用beginBackgroundTaskWithExpirationHandler,然后在调用完成处理程序后结束该任务。

Something like:

就像是:

UIBackgroundTaskIdentifier backgroundTask

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    fetchCompletiOnHandler= completionHandler;

    fetchStart = [NSDate date];

    self.backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:self.backgroundUpdateTask];
        self.backgroundTask = UIBackgroundTaskInvalid;
    }];

    [[NSUserDefaults standardUserDefaults] setObject:fetchStart forKey:kLastCheckedContentDate];

    [FeedParser parseFeedAtUrl:url withDelegate:self];
}

-(void)onParserFinished
{
    DDLogVerbose(@"AppDelegate/onParserFinished");

    UIBackgroundFetchResult result = UIBackgroundFetchResultNoData;

    NSDate *fetchEnd = [NSDate date];
    NSTimeInterval timeElapsed = [fetchEnd timeIntervalSinceDate:fetchStart];
    DDLogVerbose(@"Background Fetch Duration: %f seconds", timeElapsed);
    if ([self.mostRecentContentDate compare:item.date] <0) {
        DDLogVerbose(@"got new content: %@", item.date);
        self.mostRecentCOntentDate= item.date;
        [self scheduleNotificationWithItem:item];
        result = UIBackgroundFetchResultNewData;
    }
    else {
        DDLogVerbose(@"no new content.");
        UILocalNotification* localNotification = [[UILocalNotification alloc] init];
        localNotification.alertBody = [NSString stringWithFormat:@"Checked for new posts in %f seconds", timeElapsed];
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
    }
    fetchCompletionHandler(result);
    [[UIApplication sharedApplication] application endBackgroundTask:self.backgroundUpdateTask];
    self.backgroundTask = UIBackgroundTaskInvalid;
}

My test app using this approach has been executing a fetch every 15 minutes initially, but it becomes less frequent over time. Without the background task it exhibited the same issue you are seeing.

我使用这种方法的测试应用程序最初每15分钟执行一次获取,但随着时间的推移它会变得不那么频繁。如果没有后台任务,它会显示您遇到的相同问题。

I found that setting the background fetch interval to something other than UIApplicationBackgroundFetchIntervalMinimum also helps. My test app is running with a background fetch interval of 3600 (one hour) and has been reliably triggering for several days now; even after a phone restart and not running the app again. The actual trigger interval is 2-3 hours however.

我发现将背景提取间隔设置为UIApplicationBackgroundFetchIntervalMinimum以外的其他内容也有帮助。我的测试应用程序正在以3600(一小时)的后台获取间隔运行,并且已经可靠地触发了几天;即使手机重启后又没有再运行应用程序。但实际的触发间隔是2-3小时。

My sample app is here

我的示例应用就在这里

#2


10  

In order to implement background fetch there are three things you must do:

为了实现后台提取,您必须做三件事:

  • Check the box Background fetch in the Background Modes of your app’s Capabilities.
  • 选中应用功能的后台模式中的背景提取框。
  • Use setMinimumBackgroundFetchInterval(_:) to set a time interval appropriate for your app.
  • 使用setMinimumBackgroundFetchInterval(_ :)设置适合您的应用程序的时间间隔。
  • Implement application(_:performFetchWithCompletionHandler:) in your app delegate to handle the background fetch.
  • 在您的app委托中实现应用程序(_:performFetchWithCompletionHandler :)以处理后台提取。

Background Fetch Frequency

背景提取频率

How frequent our application can perform Background Fetch is determined by the system and it depends on:

我们的应用程序执行背景提取的频率由系统决定,它取决于:

  • Whether network connectivity is available at that particular time
  • 网络连接是否在该特定时间可用
  • Whether the device is awake i.e. running
  • 设备是否清醒即运行
  • How much time and data your application has consumed in the previous Background Fetch
  • 您的应用程序在之前的Background Fetch中消耗了多少时间和数据

In other words, your application is entirely at the mercy of the system to schedule background fetch for you. In addition, each time your application uses background fetch, it has at most 30 seconds to complete the process.

换句话说,您的应用程序完全受制于为您安排后台获取的系统。此外,每次应用程序使用后台提取时,最多只需30秒即可完成此过程。

Include in your AppDelegate (change the below code to your fetching needs)

包含在AppDelegate中(将以下代码更改为您的提取需求)

-(void) application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    NSLog(@"Background fetch started...");

    //---do background fetch here---
    // You have up to 30 seconds to perform the fetch

    BOOL downloadSuccessful = YES;

    if (downloadSuccessful) {
        //---set the flag that data is successfully downloaded---
        completionHandler(UIBackgroundFetchResultNewData);
    } else {
        //---set the flag that download is not successful---
        completionHandler(UIBackgroundFetchResultFailed);
    }

    NSLog(@"Background fetch completed...");
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
    return YES;
}

To check if Background Refresh is enabled for your app use the below code:

要检查您的应用是否启用了后台刷新,请使用以下代码:

UIBackgroundRefreshStatus status = [[UIApplication sharedApplication] backgroundRefreshStatus];
switch (status) {
    case UIBackgroundRefreshStatusAvailable:
    // We can do background fetch! Let's do this!
    break;
    case UIBackgroundRefreshStatusDenied:
    // The user has background fetch turned off. Too bad.
    break;
    case UIBackgroundRefreshStatusRestricted:
    // Parental Controls, Enterprise Restrictions, Old Phones, Oh my!
    break;
}

推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • 在本教程中,我们将看到如何使用FLASK制作第一个用于机器学习模型的RESTAPI。我们将从创建机器学习模型开始。然后,我们将看到使用Flask创建AP ... [详细]
  • 定义函数functionf(){}调用函数f();可变函数functionf(){}$f1f;$f1();匿名函数$ffunction($ ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
author-avatar
眼泪--保持微笑_572_205
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有