Сочетание WatchConnectivity и осложнений

Я хочу, чтобы мое усложнение получало данные с iPhone через Watch Connectivity. Я использую sendMessage технологию обмена мгновенными сообщениями.

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

В моем ViewController на моем iPhone:

import UIKit
import WatchConnectivity

class ViewController: UIViewController, WCSessionDelegate {

var session: WCSession!

override func viewDidLoad() {
    super.viewDidLoad()
    if WCSession.isSupported() {
        self.session = WCSession.defaultSession()
        self.session.delegate = self
        self.session.activateSession()
    }
}

func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
    if message.count != 1 { return }

    if message["request"] != nil {
        replyHandler(["response" : "data"])
    }
}

И в моем ComplicationController

var session: WCSession!

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) {
    if complication.family != .ModularSmall {
        handler(nil)
    }

    if WCSession.isSupported() {
        self.session = WCSession.defaultSession()
        self.session.delegate = self
        self.session.activateSession()
    }

    var respondedString = "not"

    session.sendMessage(["request" : ""], replyHandler: {
        (resp) -> Void in
        respondedString = resp["response"]
    }, errorHandler: nil)

    let circularTemplate = CLKComplicationTemplateModularSmallSimpleText()
    circularTemplate.textProvider = CLKSimpleTextProvider(text: respondedString)
    let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: circularTemplate)
    handler(timelineEntry)
}

Единственное, что я вижу на своих часах, это «нет». Почему усложнение не показывает полученные данные?


person ph1psG    schedule 26.04.2016    source источник
comment
Кроме того, вы можете настроить сеанс iOS в AppDelegate вместо контроллера представления. Вы всегда хотите активировать его как можно скорее (и сделать его доступным для всего приложения).   -  person    schedule 26.04.2016


Ответы (1)


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

Код, следующий за вашим вызовом sendMessage:, будет выполнен еще до того, как ваш обработчик ответа получит ответ. Вот почему ваше усложнение показывает «нет», так как текст шаблона был установлен до того, как вы получили ответ.

Некоторое время спустя, после того как getCurrentTimelineEntryForComplication вернется, sendMessage получит ответ и вызовет обработчик ответа, который просто установит respondedString, а затем выйдет из этого блока.

Чего вам следует избегать:

Вам следует рассмотреть рекомендации Apple и не пытаться получить какие-либо данные в контроллере сложности.

Задача вашего класса источника данных — как можно быстрее предоставить ClockKit любые запрошенные данные. Реализации ваших методов источника данных должны быть минимальными. Не используйте методы источника данных для извлечения данных из сети, вычисления значений или выполнения каких-либо действий, которые могут задержать доставку этих данных. Если вам нужно получить или вычислить данные для вашего усложнения, сделайте это в своем приложении iOS или в других частях вашего расширения WatchKit и кэшируйте данные в месте, где ваш источник данных усложнения может получить к ним доступ. Единственное, что должны делать ваши методы источника данных, — это брать кэшированные данные и помещать их в формат, требуемый ClockKit.

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

Как вы можете предоставить данные для вашего осложнения?

Apple предоставляет метод Watch Connectivity transferCurrentComplicationUserInfo, который немедленно передает (словарь) информацию об осложнениях с телефона на часы.

Когда ваше приложение для iOS получает обновленные данные, предназначенные для вашего усложнения, оно может использовать платформу Watch Connectivity для немедленного обновления вашего усложнения. Метод transferCurrentComplicationUserInfo: WCSession отправляет сообщение с высоким приоритетом вашему расширению WatchKit, пробуждая его по мере необходимости для доставки данных. После получения данных расширьте или перезагрузите свою временную шкалу по мере необходимости, чтобы заставить ClockKit запросить новые данные из вашего источника данных.

На стороне часов у вас есть WCSessionDelegate дескриптор didReceiveUserInfo, и вы используете полученные данные для обновления своего усложнения:

func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) {
    if let ... { // Retrieve values from dictionary

        // Update complication
        let complicationServer = CLKComplicationServer.sharedInstance()
        guard let activeComplications = complicationServer.activeComplications else { // watchOS 2.2
            return
        }

        for complication in activeComplications {
            complicationServer.reloadTimelineForComplication(complication)
        }
    }
}

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

На GitHub есть несколько проектов, использующих этот подход.

Если вы по-прежнему предпочитаете запрашивать данные со стороны наблюдения:

Вы хотели бы переместить свой код WCSession из контроллера усложнения в расширение watch и активировать его как часть WKExtension init.

Суть в том, чтобы обработчик ответов вручную обновлял сложность после получения данных.

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

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

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

person Community    schedule 26.04.2016
comment
Еще один вопрос: когда мне нужно активировать сеанс в приложении для iPhone, чтобы он был готов принять запрос и отправить ответ. viewDidLoad кажется мне неправильным, так как его не нужно загружать... - person ph1psG; 26.04.2016
comment
В AppDelegate. Вы правы в том, что представление не будет загружено, если приложение было запущено (завершено) в фоновом режиме. Дополнительные сведения см. в этом ответе. Некоторые рекомендуют настроить менеджер WCSession вместо того, чтобы помещать весь код делегата в AppDelegate. В любом случае вам все равно следует активировать сеанс iOS как можно раньше (то есть при запуске приложения). - person ; 26.04.2016
comment
Что на самом деле является точкой входа для Усложнения, чтобы я мог активировать сеанс там? Как в моем приложении iOS в didFinishLaunchingWithOptions - person ph1psG; 26.04.2016
comment
WKExtension инициировать. Это будет охватывать фоновые запуски для обновлений сложности, а также запуски переднего плана для приложения для часов. - person ; 26.04.2016
comment
В приложении ExtensionDelegateDidFinishLaunching? - person ph1psG; 26.04.2016
comment
На часах applicationDidFinishLaunching вызывается только для запуска приложений, но приложение для часов не может запускаться в фоновом режиме. Однако расширение может запускаться независимо от приложения для часов и запускаться в фоновом режиме. Вот почему вам нужно переопределить WKExtension init() и активировать сеанс там, чтобы обрабатывать запуски как на переднем плане, так и в фоновом режиме. - person ; 26.04.2016
comment
Давайте продолжим обсуждение в чате. - person ph1psG; 26.04.2016