Продолжая свое путешествие с watchOS, я хочу выделить различные методы, которые у нас есть для связи между устройствами iPhone и Apple Watch. В течение последних недель я глубоко погрузился в WatchConnectivity и то, как его можно использовать для обмена данными. Этот пост должен дать обзор моих выводов и помочь выбрать правильный метод для данного варианта использования.

Установка WatchConnectivity

При работе с передачей данных на часы вы будете работать с WatchConnectivity. Этот фреймворк абстрагирует большую часть базовых коммуникаций и позволяет работать с высокоуровневыми методами. Основной точкой взаимодействия является класс WCSession. Этот объект используется для создания соединения между телефоном и часами. По умолчанию он предлагает одиночный (единовременный) сеанс для текущего устройства, который, как я предполагаю, используется на протяжении всего поста. Для всех фрагментов кода в этом посте я также предполагаю, что они встроены в простой класс-оболочку. Это немного упрощает инкапсуляцию всего потока подключений в один объект.

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

final class WatchConnectivityService: NSObject {

    private let session: WCSession

    init() {
        guard WCSession.isSupported() else { fatalError() } // In a productive code, this should handled more gracefully
        self.session = WCSession.default
        self.session.delegate = self
        self.session.activate()
    }

В дополнение к проверке, полезно установить делегат на экземпляр сеанса. Делегат должен соответствовать стандарту WCSessionDelegate, который предлагает обратный вызов для наиболее важных событий во время существования сеанса. Теперь делегат можно использовать для ожидания, пока метод WCSessionDelegate.session(_:activationDidCompleteWith:error:) не сообщит об активированном состоянии сеанса. Как только мы это подтвердим, мы сможем использовать экземпляр WCSession и отправлять данные.

Варианты передачи данных WatchConnectivity

Далее мы рассмотрим различные способы отправки и получения данных при общении через WCSession. Мы также рассмотрим соответствующие методы WCSessionDelegate, которые вы можете реализовать для получения дублирующих сообщений. Все описанные ниже методы будут работать со словарем типа [String: Any]. Но будь осторожен. Несмотря на то, что значение имеет тип Any, вам разрешено отправлять только “Plist encodable types” (“кодируемые типы Plist”), то есть примитивные типы, такие как String, Integer, Double, Data, Array и т. д. Поэтому обязательно правильно кодируйте пользовательские типы перед отправкой.

Прежде чем продолжить, я хочу подчеркнуть, что следующие методы предназначены для передачи небольших объёмов данных. Они не должны использоваться для отправки полных внутренних ответов или аналогичных вашим коллегам. Apple рекомендует использовать собственные возможности URLSession на часах или телефоне для запроса данных (см. документацию Appleвидео WWDC).

ApplicationContext

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

public func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) {
    // Receive application context sent from counterpart
    // session.receivedApplicationContext is updated automatically
}

public func updateApplicationContext(with context: [String: Any]) {
    do {
        try self.session.updateApplicationContext(context)
    } catch {
        print("Updating of application context failed \(error)")
    }
}

Метод WCSession.updateApplicationContext(_:) используется для отправки обновления контрагенту. ОС попытается убедиться, что самое последнее значение достигнет аналога, как только это станет возможным. Это означает, что если вы обновляете ApplicationContext три раза, а копия недоступна, только последнее обновление будет передано, как только соединение будет восстановлено.

Затем метод WCSessionDelegate.session(_:didReceiveApplicationContext:) вызывается всякий раз, когда получен обновлённый ApplicationContext. Помимо вышеупомянутых методов, в экземпляре WCSession можно получить доступ к следующим свойствам:

  • applicationContext — представляет последний ApplicationContext, который должен быть отправлен или отправлен контрагенту;

  • receivedApplicationContext — представляет последний полученный ApplicationContext от партнёра.

Используйте эти свойства для получения необходимого ApplicationContext по запросу.

Передача информации о пользователе

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

public func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
    // Receive user info sent from counterpart
}

public func transferUserInfo(_ userInfo: [String: Any]) {
    // Use session to transfer user info
    let transferInfo = let self.session.transferUserInfo(userInfo) // returns a WCSessionUserInfoTransfer instance which you can use to monitor or cancel the sending
}

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

❗ Внимание! Этот метод не будет работать в симуляторе. Обязательно протестируйте на реальных устройствах.

Отправка сообщений

Последней возможностью общения является “send messages” (отправка сообщений). В этом случае используется тот же тип словаря, но немного особенный. Это зависит от того, на каком устройстве выполняется соответствующая активная отправка. Этот тип связи больше подходит для прямой двусторонней связи между устройствами и зависит от того, доступен партнёр или недоступен. Если контрагент недоступен, отправка завершится ошибкой, и сообщения не будут доставлены.

Ответственные методы:

public func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
        // Receiving messages sent without a reply handler
    }

public func session(
    _ session: WCSession,
    didReceiveMessage message: [String: Any],
    replyHandler: @escaping ([String: Any]) -> Void
) {
    // Receiving messages sent with a reply handler
}

public func sendMessage(_ message: [String: Any], errorHandler: ((Error) -> Void)?) {
    // Send message without reply handler
    session.sendMessage(message, errorHandler: errorHandler)
}

public func sendMessage(
    _ message: [String: Any],
    replyHandler: (([String: Any]) -> Void)?,
    errorHandler: ((Error) -> Void)?
) {
    // Send message with reply handler
    session.sendMessage(message, replyHandler: replyHandler, errorHandler: errorHandler)
}

Как вы, возможно, уже заметили, у нас есть ещё два доступных метода. Дополнительные методы используют концепцию обработчика ответов. Это настоящая двусторонняя связь. Обработчик может использоваться контрагентом для прямой реакции на полученное сообщение и непосредственного ответа. Все сообщения, отправленные этими методами, доставляются последовательно.

❗ Если вы используете sendMessage (независимо от того, используете ли вы обработчик ответа или нет) из iOS -> watchOS, приложение для часов должно быть на переднем плане, чтобы фактически получать сообщения. Если вы пойдёте наоборот, watchOS -> iOS, приложение iOS также может работать в фоновом режиме и проснётся, чтобы быть доступным.

Заключение

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

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

Увидимся в следующий раз.

Комментарии (0)