swift WatchConnectivity работает в фоновом режиме - ApplicationContext не работает все время

Я хочу знать, как лучше отправить (с iPhone) сообщение на часы (в фоновом режиме). В настоящее время я использую:

session.update(applicationContext: package, completion: nil)

для отправки сообщений в Watch и

 func didReceivedApplicationContext(applicationContext:[String : Any])

получать сообщения в Watch. Проблема в том, что, как сказано в документации, «Система будет передавать контент в подходящее время», и я не могу контролировать эти «подходящее время».

В это время я проверяю в классе iPhone состояние Watch. Если часы находятся в фоновом режиме, я отправляю данные с помощью updateApplicationcontext (что не очень хорошо), иначе, если часы находятся на переднем плане, я отправляю данные с помощью sendMessage.

Код:

 if session.isWatchReachable()
    {
        session.send(message: package, completion: nil)
    }
    else
    {
        session.update(applicationContext: package, completion: nil)
    }

Так есть ли лучший способ передачи данных в фоновом режиме?


person Community    schedule 10.08.2017    source источник


Ответы (1)


Что ж, вам придется выбирать между фоновой передачей и немедленной отправкой данных. Используя структуру WatchConnectivity, невозможно запланировать передачу данных в определенный момент времени.

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

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

Обходной путь заключается в использовании updateApplicationContext для передачи данных в фоновом режиме, а в классе ExtensionDelegate приложения Watch используйте метод applicationDidBecomeActive(), чтобы проверить, произошла ли передача данных в фоновом режиме, и, если этого не произошло, используйте функцию sendMessage для запроса данных. немедленно из другого приложения и отправить обратно запрошенные данные в качестве ответа.

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

func applicationDidBecomeActive(){
    if !haveReceivedData {  //Bool value that should be updated to true once data is received from the phone
        session.sendMessage(["Requesting data":True], replyHandler: {
            //parse the data, update the UI
        }, errorHandler: { error in
                    print("Error requesting data",error)
                })
    }
}

А в приложении для iPhone вы делаете следующее:

func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        if let isRequestingData = message["Requesting data"] as? Bool, isRequestingData == true {
            replyHandler(["Requested data":data])
        }
    }
person Dávid Pásztor    schedule 10.08.2017
comment
Как я могу запросить данные с помощью sendMessage, если я отправляю данные с помощью updateApplicationContext? - person ; 10.08.2017
comment
Кстати, в это время я проверяю в классе iPhone состояние Watch. Если часы находятся в фоновом режиме, я отправляю данные с помощью updateApplicationcontext (что не очень хорошо), иначе, если часы находятся на переднем плане, я отправляю данные с помощью sendMessage. - person ; 10.08.2017
comment
Будет ли иметь какое-либо значение, если я перемещу этот код (объясненный выше) в класс ExtensionDelegate applicationDidBecomeActive? - person ; 10.08.2017
comment
Для вашего первого комментария: вы отправляете новый запрос от Дозора с помощью sendMessage в applicationDidBecomeActive и отправляете данные, которые вы уже отправили ранее, но не получили с телефона с помощью updateApplicationContext в ответе функции sendMessage. - person Dávid Pásztor; 10.08.2017
comment
Что касается вашего последнего комментария: если вы переместите всю функцию в applicationDidBecomeActive, вам вообще не нужно будет использовать updateApplicationContext, поскольку в этом случае вы будете отправлять данные только тогда, когда приложение Watch будет активным. Однако имейте в виду, что даже с sendMessage отправка данных может занять пару секунд, поэтому пользователь может не сразу увидеть обновленный интерфейс. - person Dávid Pásztor; 10.08.2017
comment
и отправить данные, которые вы уже отправили ранее, но не получили с телефона с помощью updateApplicationContext Как я могу отправить данные с часов на iPhone, если я не получил данные с iPhone? - person ; 10.08.2017
comment
Вы не отправляете данные с часов на телефон. Вы отправляете запрос, используя sendMessage, отправляя бессмысленный словарь в качестве userInfo из часов. В функции func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) вы отправляете данные обратно в часы, используя функцию replyHandler. - person Dávid Pásztor; 10.08.2017
comment
Проверьте мой обновленный ответ, я добавил упрощенный пример. - person Dávid Pásztor; 10.08.2017
comment
Итак, вы говорите мне, в случае, если сообщение не было получено на Watch, отправить запрос с Watch на iPhone, чтобы уведомить, что сообщение не было отправлено, и снова отправить данные с iPhone на Watch? Но как я могу проверить, что сообщение не было отправлено? - person ; 10.08.2017
comment
Да, это то, что вы должны сделать. Вы можете настроить наблюдатель свойств для переменных, которые необходимо обновить, используя данные из телефона, и если их значение не изменится, запросите данные. - person Dávid Pásztor; 10.08.2017
comment
А нужно сделать этот запрос в applicationDidBecomeActive? Если часы находятся в фоновом режиме, они не будут активны, поэтому запрос не будет отправлен. - person ; 10.08.2017
comment
Если вы хотите получать данные, как только ваше приложение станет активным, да. - person Dávid Pásztor; 10.08.2017
comment
О, но возможно, что мое приложение для часов будет много работать в фоновом режиме, я не могу дождаться, чтобы стать активным. - person ; 10.08.2017
comment
Тогда, как я сказал вам в своем ответе, невозможно гарантировать время, когда ваши данные будут отправлены. В любом случае, для чего вам нужны данные, когда ваше приложение Watch работает в фоновом режиме? - person Dávid Pásztor; 10.08.2017
comment
Мне нужно получить вибрацию в фоновом режиме, когда я отправляю запрос с iPhone (это приложение для обнаружения препятствий, и когда оно обнаруживает препятствие, часы должны вибрировать, чтобы уведомить водителя). Водителю пришлось бы в основном все время смотреть приложение в фоновом режиме. - person ; 10.08.2017
comment
К сожалению, из-за такого поведения вы не можете использовать WatchConnectivity фреймворк в данный момент. Вы можете отправлять мгновенные сообщения только на переднем плане. Вы должны либо обнаружить препятствия на самом Watch, либо найти совершенно другой подход, который вообще не использует структуру WatchConnectivity. - person Dávid Pásztor; 10.08.2017
comment
Тем не менее, я попытаюсь сделать комбинацию updateApplicationcontext и transferCurrentComplicationUserInfo (на последнем у меня максимальное количество запросов 50: |). - person ; 11.08.2017
comment
Почему бы вам объединить эти два? Оба работают только в фоновом режиме, и вы не можете контролировать, когда они отправляют информацию. Более того, transferCurrentComplicationUserInfo следует использовать только для передачи Complication данных, и его можно вызывать только ограниченное количество раз... Насколько я понял, вы даже не используете Complication, так зачем вам вызывать функцию для обновления ее данных? - person Dávid Pásztor; 11.08.2017
comment
Когда сообщение не отправляется с ApplicationContext, я попытаюсь отправить его с помощью transferCurrentComplicationUserInfo (который точно передается, но имеет максимум 50 запросов в день). Объединив эти 2, я получу число больше 50. Но, конечно, после этого я не могу гарантировать, что сообщение будет получено. Это проблема, с которой я сталкиваюсь. Я могу использовать transferCurrentComplicationUserInfo, даже если я не использую усложнение, но я должен его включить. - person ; 11.08.2017
comment
Это звучит как злоупотребление ресурсами Apple Watch. Я бы предпочел найти не такую ​​хакерскую альтернативу или просто отказаться от идеи сделать это приложение для часов. Apple действительно ограничивает то, что вы можете и что вы не можете делать на часах, и иногда стоит отказаться от идеи, если это невозможно с текущими ресурсами WatchKit. - person Dávid Pásztor; 11.08.2017
comment
Мой наставник реализовал эту идею. Я не могу сказать ему бросить это приложение. - person ; 11.08.2017