Подтвердить что ты не робот

Асинхронный код не выполняется до тех пор, пока приложение не будет включено в приложение: didReceiveRemoteNotification: fetchCompletionHandler:

В нашем приложении мы хотим загрузить небольшой объем данных в ответ на push-уведомление. До сих пор push-уведомления работали плавно, запуская приложение в фоновом режиме и вызывая вызывающую функцию didReceiveRemoteNotification.

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

Уменьшая это до простейшего случая, я все еще не могу запустить асинхронный код.

- (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);
    });
}

В ответ на push приложение запускается в фоновом режиме, а счетчик значков равен 1, но номер значка не установлен равным 9, пока приложение не будет запущено с главного экрана.

Если iOS не запускает приложение до тех пор, пока не будет вызван обработчик завершения, до 30 секунд?

В Info.plist указан фоновый режим удаленного уведомления, токовая полезная нагрузка содержит "контент-доступный": "1", и я не выхожу из приложения, перейдя в коммутатор приложений.

Чтобы добавить, мы используем Parse для отправки этого push-уведомления, используя следующий Javascript:

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

Ответ 1

Сначала возьмите здесь и убедитесь, что вы включили push-уведомление и добавили доступное содержимое:

Использование Push-уведомлений для запуска загрузки Если ваш сервер отправляет push-уведомления на пользовательское устройство, когда новый контент доступен для вашего приложения, вы можете попросить систему запустить ваше приложение в фоновом режиме, чтобы сразу начать загрузку нового контента. Цель этого фонового режима состоит в том, чтобы свести к минимуму количество времени, которое истекает между тем, когда пользователь видит push-уведомление и когда ваше приложение может отображать связанный контент. Приложения обычно пробуждаются примерно в то же время, когда пользователь видит уведомление, но это все равно дает вам больше времени, чем в противном случае. Чтобы поддержать этот фоновый режим, включите параметр "Удаленные уведомления" в разделе "Режимы фона" на вкладке "Возможности" в проекте Xcode. (Вы также можете включить эту поддержку, включив ключ UIBackgroundModes со значением удаленного уведомления в файл Info.plist ваших приложений.) Для push-уведомления для запуска операции загрузки полезная нагрузка уведомлений должна включать в себя доступный для содержимого ключ с его значением, установленным в 1. Когда этот ключ присутствует, система пробуждает приложение в фоновом режиме (или запускает его в фоновом режиме) и вызывает приложение делегатов приложения: didReceiveRemoteNotification: fetchCompletionHandler: метод. Ваша реализация этого метода должна загружать соответствующий контент и интегрировать его в ваше приложение. При загрузке любого контента рекомендуется использовать класс 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;
    }