Будет ли выполняться FetchWithCompletionHandler, если приложение было завершено

Удивительно трудно найти окончательный ответ на этот вопрос; не смог найти упоминание об этом в документации Apple и не смог найти определенного да/нет после поиска прошлых вопросов.

Вопрос прост: если приложение запрашивает фоновую выборку через N раз, пользователь завершает работу приложения. Будет ли ОС по-прежнему запускать приложение в фоновом режиме для выполнения фоновой выборки?


person Gruntcakes    schedule 29.06.2017    source источник
comment
Разве это не должно быть сделано путем регистрации какого-то сервиса? Я имею в виду, что когда приложение завершается, оно должно больше не выполняться.   -  person Xorifelse    schedule 29.06.2017
comment
@Xorifelse, без обид, но ты действительно знаешь что-нибудь об iOS? В iOS нет таких вещей, как сервисы. И да, конечно, оно не выполняется после завершения, но ОС может запускать приложение при некоторых обстоятельствах. И вопрос в том, делает ли ОС это для этой ситуации, не задокументировано, делает ли это или нет.   -  person Gruntcakes    schedule 29.06.2017
comment
Немного поигрался с этим, но я использовал логику. В некотором смысле Background Fetch — это услуга. Во-вторых, я нашел это, и в обсуждении говорится: If you do not call the completion handler in time, your app is terminated. о чем +/- 30 секунд макс. Когда приложение завершается, не ожидайте, что обработчик будет вызван снова, если вы не запустите приложение.   -  person Xorifelse    schedule 29.06.2017
comment
Если вы, пользователь, завершаете свое приложение, оно не будет разбужено в фоновом режиме за исключением определенных случаев (я думаю, только приложения VoIP)   -  person dan    schedule 29.06.2017
comment
@Xorifelse Когда приложение завершается, не ожидайте, что обработчик будет вызван снова, если вы не запустите приложение. Но в документации не сказано, что * не будет вызываться снова, в нем говорится, что если вашему приложению требуется много времени для вызова обработчик завершения, ему может быть предоставлено меньше возможностей для извлечения данных в будущем. В том-то и проблема - документация не ясна, и похоже, что это не племенные знания - много противоречий.   -  person Gruntcakes    schedule 29.06.2017
comment
Возможно, этот ответ обеспечит некоторую скорость.   -  person Xorifelse    schedule 29.06.2017
comment
@Xorifelse Нет, этот вопрос - просто общий вопрос о фоновом выполнении. Этот вопрос касается очень конкретного экземпляра фонового выполнения.   -  person Gruntcakes    schedule 29.06.2017
comment
@dan в соответствии с этим будет: techotopia.com/index.php/   -  person Gruntcakes    schedule 29.06.2017
comment
@dan и я цитируем прямо из WWDC 13 Что нового в многозадачности .. как только ваше приложение запускается в фоновом режиме .. вызывается didFinishLaunching. Если ваше приложение уже было запущено, ваше приложение будет возобновлено .... Так что это прямо указывает, что оно будет запущено, если оно не было в фоновом режиме.   -  person Gruntcakes    schedule 29.06.2017
comment
Какое это имеет отношение к тому, что пользователь завершает работу вашего приложения? Я цитирую прямо из документа, который я только что связал с вами: если приложение закрывается по какой-либо причине, кроме принудительного закрытия пользователем, система запускает приложение, когда происходит одно из следующих событий: и в большинстве случаев система не перезапускается приложения после их принудительного закрытия пользователем. Единственным исключением являются приложения определения местоположения,...   -  person dan    schedule 29.06.2017
comment
@dan есть только два способа завершить работу приложения: это сделал пользователь или ОС. Видео WWDC не делает различий между ними. Дело в том, что вы не знаете окончательно, вы цитируете документацию, которая может быть устаревшей или неполной. Точно тоже не знаю, просто указываю на противоречия в источниках. Весь смысл этого вопроса выяснять однозначно. Вы на 100%, точно, за абсолютный факт, без экивоков знаете ответ или нет? Не цитируя документацию — опытный разработчик iOS знает, что документация не совсем надежна.   -  person Gruntcakes    schedule 29.06.2017
comment
Вы можете проверить это самостоятельно в своем приложении. Как опытный разработчик iOS, я бы поступил именно так, если бы не хотел доверять документации.   -  person dan    schedule 29.06.2017
comment
@dan, ты просто стал раздражительным, ты мог бы быть вежливым и просто признать, что не знал. Я пытаюсь поэкспериментировать, но, учитывая характер этой функциональности, это не то, что вы можете сделать и прийти к определенному выводу быстро или легко. Хорошего дня.   -  person Gruntcakes    schedule 29.06.2017


Ответы (3)


Ладно, снова фоновые режимы вызывают недоумение. Не обижайтесь на тех, кто пытается помочь, но это сложнее, чем кажется.

Прежде всего: Это устарело, как догадался Колбаса в комментариях. Я знаю это точно, потому что в разделе о приложениях VoIP все еще объясняется старый способ сделать это с периодически вызываемым обработчиком. Я немного исследовал это для этого ответа, поэтому предлагаю вам пойти и прочитать его. Важный урок для этого случая заключается в том, что iOS делает различие между завершением приложения пользователем или системой, а также играет роль независимо от того, был ли телефон перезагружен или нет.

Итак, чтобы подвести итог этому (и вашему вопросу), вы в основном хотите знать, является ли эта часть вышеизложенной устаревшей документации правильной дословно:

В большинстве случаев система не перезапускает приложения после их принудительного закрытия пользователем. Единственным исключением являются приложения определения местоположения, которые в iOS 8 и более поздних версиях перезапускаются после принудительного закрытия пользователем. Однако в других случаях пользователь должен запустить приложение явным образом или перезагрузить устройство, прежде чем приложение сможет быть автоматически запущено системой в фоновом режиме. Когда на устройстве включена защита паролем, система не запускает приложение в фоновом режиме до того, как пользователь впервые разблокирует устройство.

Apple: Понимание того, когда ваше приложение запускается в фоновом режиме

Я тщательно изучил остальные документы, но не нашел определенного ответа, поэтому, к сожалению, все сводится к тому, что уже предложил Дэн: протестировать. Я нутром чувствую, что документация по-прежнему верна в этом отношении (как сказано, что не так, это VoIP). Я говорю это, потому что пользовательский интерфейс в приложении «Настройки» вызывает функцию «Обновление приложения в фоновом режиме», поэтому пользователи, вероятно, должны понимать, что приложение, имеющее это разрешение, не будет обновляться, когда они выталкивают его из фона (например, кнопка «Домой» -> проведите пальцем по экрану). ). Для обычных пользователей приложения либо закрыты (вообще не в диспетчере задач), либо на переднем плане (используя их), либо в фоновом режиме (они в диспетчере задач, а другое приложение на переднем плане и/или телефон заблокирован) .


Чтобы действительно проверить это, вам нужно написать приложение и немного поносить его (я полагаю, по крайней мере, два дня) в каждом состоянии. Сначала, когда он находится в фоновом режиме (ОС должна периодически разрешать ему выборку, поскольку вы, вероятно, знаете, что это также может быть запущено в 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];
}

Это войдет в делегат приложения, и не забудьте добавить логическую настройку Application supports iTunes file sharing в plist вашего приложения. Я оставлю это на моем устройстве для разработки на некоторое время и проверю файл журнала, в конечном итоге сообщив об этом здесь. Не стесняйтесь проверить это на себе.

person Gero    schedule 06.07.2017
comment
Обновление: до сих пор у моего небольшого тестового приложения не было возможности получить данные, но мне пришлось оставить тестовое устройство в офисе на некоторое время в режиме полета. :/ Я, однако, начинаю подозревать, что отладочные сборки получают очень низкий приоритет для этого, если вообще имеют (ожидая, что для отладки вы все равно вызовете событие выборки через Xcode). Попробую еще раз в понедельник. Черт, я могу частично понять, почему Apple сохраняет критерии, которые ОС использует для обеспечения конфиденциальности приложений, но было бы неплохо немного больше документации... :/ - person Gero; 07.07.2017
comment
Обновление 2: еще одно доказательство моей догадки о том, что отладочные установки из Xcode не имеют шансов performFetch...: прошло уже несколько дней, и хотя устройство находилось в режиме полета, иногда у него было достаточно времени, чтобы вызвать приложение (которое было в background, т.е. я даже не дошел до теста 2: устройство перезагрузилось...). Я по-прежнему уверен, что принудительное завершение не позволит вам получить данные, в то время как завершение через перезагрузку устройства или системную память позволит (т. е. перезапустит ваше приложение). Я собираюсь проверить форумы разработчиков, возможно, и в конце концов вернусь сюда. :/ Извините, у меня пока нет ничего определенного. - person Gero; 11.07.2017
comment
Я запутался, мой ответ был правильным или нет? Или, поскольку вы не смогли установить сборку релиза, вы не можете сказать наверняка? 2. Разве частота фоновой загрузки не связана с использованием пользователя? Я имею в виду, что вы мало использовали устройство, поэтому, возможно, оно думало, что оно ничего не должно извлекать... - person Honey; 12.07.2017
comment
@ Дорогая, нет, нет, я все еще думаю, что мы с тобой правы. Я согласен, причина, по которой я, вероятно, еще не получил ни одного вызова fetch, связана с использованием устройства (и возможно, потому что это отладочная сборка и/или очень простое тестовое приложение с практически нулевым пользовательским интерфейсом и фактическая полезность). В конце концов, Apple не раскрыла, как именно ОС определяет, когда она разрешает выборку приложения. Я установил тест на устройство для разработки, которое должно оставаться в моем офисе, поэтому на самом деле он не используется. Я мог бы попытаться исправить это и протестировать на своем личном устройстве (с лучшим тестовым приложением), но у меня мало времени для этого. - person Gero; 12.07.2017
comment
Просто в качестве предупреждения по этому (к настоящему времени уже древнему) вопросу: я сказал, что попробую это дальше, и я это сделал, но до сих пор не получил никаких выборок, даже когда приложение было просто приостановлено. На форумах разработчиков приложений я нашел это среди нескольких других подсказок, которые действительно Сборки Xcode и отладки могут сыграть роль в таких вещах. В конечном итоге я попытаюсь протестировать это в максимально приближенных к релизу условиях, но это займет у меня некоторое время и усилия. - person Gero; 09.08.2017

ИЗМЕНИТЬ:

https://devforums.apple.com/message/873265#873265 (требуется вход в систему )

Также имейте в виду, что если вы закроете свое приложение из переключателя приложений (т. е. проведите пальцем вверх, чтобы закрыть приложение), ОС никогда не перезапустит приложение, независимо от push-уведомления или фоновой выборки. В этом случае пользователь должен один раз вручную перезапустить приложение, а затем с этого момента будут запущены фоновые действия. -pmarcos

Этот пост был написан сотрудником Apple, поэтому я думаю, что могу доверять этой информации.


СТАРЫЙ ответ:

Согласно этому ответу, написанному ведущим пользователем: фоновая выборка iOS: ваше приложение не будет проснуться снова.

Убедитесь, что вы не убиваете приложение (например, дважды нажав на кнопку «Домой» и проведя пальцем вверх по приложению, чтобы принудительно закрыть приложение). Если приложение будет убито, фоновая выборка будет работать некорректно.

На самом деле нет смысла просыпаться... это как бы лишает законной силы пользователя, убивающего приложение.

С учетом сказанного существуют разные способы повторного запуска завершенного/принудительно закрытого приложения:

  • Нажатие на уведомление.
  • Нажатие на значок приложения.
  • Используйте openUrl, чтобы открыть свое приложение из другого приложения.
  • Если вы используете PushKit... ваше приложение будет запущено. Представьте, если бы у вас было приложение VOIP, например. Skype, WhatsApp и друг звонили вам, но вы принудительно закрыли приложение, вы не получали звонки. Подробнее см. здесь.
  • Местоположение обновляется с помощью мониторинга региона или значительные изменения. См. этот ответ и обязательно прочитайте вся эта страница из документов Apple.

  • Перезагрузка устройства также отменяет все, что было заблокировано с помощью принудительного выхода.

person Honey    schedule 05.07.2017

Читая документацию Apple здесь я нашел этот фрагмент текста, который должен объяснить ваш вопрос:

Методы, предлагаемые iOS, делятся на три категории:

    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.

Второй вариант как раз касается загрузки данных, которые можно делегировать системе, даже если их можно прервать.

person Oleg Danu    schedule 05.07.2017
comment
Ха! Ваш ответ прямо противоположен моему, возможно, правильный. Я думаю, мы должны все проверить и дать практический ответ... - person Honey; 05.07.2017