WKURLSessionRefreshBackgroundTask не вызывается при попытке выполнить фоновое обновление в watchOS

Я работаю над усложнением, чтобы получить запланированные данные из веб-службы. Каждые 20-30 минут (или вручную) я планирую WKRefreshBackgroundTask для этого.

Как было предложено Apple, я хочу, чтобы ОС обрабатывала выборку этих данных через фон NSURLSession.

Это функция, которую я использую для загрузки нужных мне данных:

func scheduleURLSession()
{
    print("\nScheduling URL Session...")

    let backgroundSessionConfig:URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString)
    backgroundSessionConfig.sessionSendsLaunchEvents = true

    let backgroundSession = URLSession(configuration: backgroundSessionConfig)

    let downloadTask = backgroundSession.downloadTask(with: URL(string: "https://www.myserver.com/somedata")!)
    downloadTask.resume()
}

Несколько вещей об этом:

  1. Он вызывается, когда я его планирую. Я вижу его оператор печати в консоли.
  2. Это почти идентично примеру Apple.
  3. Я пропустил URL. Тот же URL-адрес отлично работает в приложениях iOS/watchOS, так что с ним все в порядке.

Проблема в том, что хотя я вызываю resume() для задачи и позволяю ей разбудить мое приложение после ее завершения, похоже, это тоже не работает.

Когда он завершится, он должен вернуться к обработчику WKExtensionDelegate:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>)

как WKURLSessionRefreshBackgroundTask, но это не так.

Мой код, идентичный образцу кода Apple, затем создает другой сеанс, но присоединяется к нему через идентификатор WKURLSessionRefreshBackgroundTask. Здесь устанавливается делегат для обработки загруженных данных. Проверьте код:

func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
    for task in backgroundTasks {
        switch task {

        case let backgroundTask as WKApplicationRefreshBackgroundTask:
            print("\nWatchKit - WKApplicationRefreshBackgroundTask")
            // self.updateComplicationDataArrivalTimes(backgroundTask)
            self.scheduleURLSession()
            backgroundTask.setTaskCompleted()

        case let snapshotTask as WKSnapshotRefreshBackgroundTask:
            // Snapshot tasks have a unique completion call, make sure to set your expiration date
            print("\nWatchKit - WKSnapshotRefreshBackgroundTask")
            snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)

        case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
            print("\nWatchKit - WKWatchConnectivityRefreshBackgroundTask")
            connectivityTask.setTaskCompleted()

        case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
            print("\nWatchKit - WKURLSessionRefreshBackgroundTask")
            let backgroundConfigObject = URLSessionConfiguration.background(withIdentifier: urlSessionTask.sessionIdentifier)
            let backgroundSession = URLSession(configuration: backgroundConfigObject, delegate: self, delegateQueue: nil)

            print("Rejoining session ", backgroundSession)
            urlSessionTask.setTaskCompleted()

        default:
            // make sure to complete unhandled task types
            task.setTaskCompleted()
        }
    }
}

Но опять же, кажется, что он никогда не вернется. Я не могу понять, почему это работает, несмотря на то, что код идентичен коду примера Apple для этого проекта: WatchBackgroundRefresh: использование WKRefreshBackgroundTask для обновления приложений WatchKit в фоновом режиме.

Есть ли в моем проекте какая-то настройка, которую мне не хватает? Я помещаю весь этот код в ExtensionDelegate, новое в watchOS 3. Я также соответствую WKExtensionDelegate и URLSessionDownloadDelegate.

Заранее спасибо за помощь!


person Mario A Guzman    schedule 15.12.2016    source источник
comment
Вы когда-нибудь решали это?   -  person Jens Peter    schedule 09.07.2017
comment
Это очень обременительно. Когда я сообщил об ошибке, представитель Apple сказал мне, что это работает только на физическом устройстве (а не на симуляторе). Я бы хотел, чтобы они сказали это в фактической документации для примера проекта, который они разместили на своем сайте. Кроме того, это занимает некоторое время. Вы должны фактически ждать обратного вызова, как бы долго вы его ни планировали. Кроме того, кажется, что у вас могут закончиться ежедневные выделенные фоновые рабочие задачи, потому что через некоторое время кажется, что они перестают работать до следующего дня, когда система разрешает больше фоновых рабочих задач.   -  person Mario A Guzman    schedule 09.07.2017
comment
Спасибо! Это... ну, ужасные новости. Но это также объясняет, почему я не могу заставить работать пример Apple в симуляторе. У меня нет Apple Watch, поэтому я либо покупаю их, либо отказываюсь от своего приложения :(   -  person Jens Peter    schedule 10.07.2017
comment
Да, это отстой. Я очень надеюсь, что Apple исправит это хотя бы для симулятора. Пробовали ли вы бета-версию iOS 4 и Xcode 9?   -  person Mario A Guzman    schedule 10.07.2017
comment
@MarioAGuzman У вас случайно нет рабочего фрагмента этого? Я изо всех сил пытаюсь заставить это работать (также похоже, чтение данных из API через какой-то промежуток времени), но не могу собрать все это вместе, надеюсь, вы поможете.   -  person ZassX    schedule 31.01.2018


Ответы (2)


У меня это работает! Я начал с просмотра видео/заметок WWDC'16, сравнивая их с WatchBackgroundRefresh от Apple. Затем, просматривая форумы Apple Dev, я нашел эту тему, с той же проблемой, что и мы. столкнулся. Там парень «Даниэль Фонтес» публикует свой «рецепт» того, как заставить его работать (обратите внимание, не принятый ответ!), И это в сочетании с видео сработало для меня.

Что я сделал, чтобы пример Apple заработал:

  1. Сделайте MainInterfaceController URLSessionDelegate
  2. Создайте локальную переменную: var savedTask:WKRefreshBackgroundTask?
  3. В функции handle( backgroundTasks:) сохраните WKURLSessionRefreshBackgroundTaskв локальную переменную self.savedTask = task - не делайте task.setTaskCompleted() (!!)
  4. В urlSession - didFinishDownloading: установите сохраненную задачу как завершенную: self.savedTask?.setTaskCompleted() после прочтения полученных данных.
  5. Убедитесь, что ресурс, к которому вы обращаетесь, — https://, в противном случае добавьте «Настройки безопасности транспорта приложения» в файл Info.plist.

Надеюсь, это может помочь!

пс. это работает в симуляторе (xcode 8.3.3, watchOS 3.2)

person Jens Peter    schedule 16.07.2017
comment
Отличный совет @Jens Peter!! ЭТО наконец-то проснулось! Моя ошибка заключалась в том, что я использовал другой класс для делегата. Но теперь делегаты находятся на моем ExtensionDelegate, и это работает. Но две вещи не могу решить: 1 - Постоянно получаю это сообщение, что фоновая сессия с используемым мной идентификатором уже существует. Меня это беспокоит, но все равно работает. 2 - где вы помещаете вызов invalidateAndCancel()? Я не использую его. Нужно ли мне? - person francisaugusto; 03.02.2018

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

пусть backgroundSession = URLSession (конфигурация: backgroundSessionConfig, делегат: self, delegateQueue: nil)

У меня есть подробный пример кода здесь (см. код вопроса):

WatchOS 3 WKApplicationRefreshBackgroundTask didReceiveChallenge

Надеюсь, поможет.

person CodenameDuchess    schedule 21.02.2017
comment
Я не понимаю, чем это отличается от того, что вы написали в вопросе. - person Kane Cheshire; 30.05.2017