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

Передача данных в приложение Apple Watch

Я пытаюсь передать данные из своего приложения в приложение Apple Watch. В основном, я использую тот же метод, что и для создания виджета Today, поэтому я передаю данные через NSUserDefaults.

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

Вот что я имею...

override init(context: AnyObject?) {
    // Initialize variables here.
    super.init(context: context)

    // Configure interface objects here.
    NSLog("%@ init", self)

    var defaults = NSUserDefaults(suiteName: "group.AffordIt")
    var totalBudgetCalculation = ""
    if (defaults!.stringForKey("totalBudgetWidget") != nil) {
            println("Worked")
        totalBudgetCalculation = defaults!.stringForKey("totalBudgetWidget")!
        initialBudgetLabel.setText("Initial: \(totalBudgetCalculation)")
    }

    var currentBudgetCalculation = ""
    if (defaults!.stringForKey("currentBudgetWidget") != nil) {
        currentBudgetCalculation = defaults!.stringForKey("currentBudgetWidget")!
        currentBudgetLabel.setText("Current: \(currentBudgetCalculation)")
    }
}

Я попытался поместить этот код в willActivate(), однако это, похоже, не имеет значения.

Кто-нибудь знает, где я ошибаюсь?

4b9b3361

Ответ 1

Это относится только к ОС 1. Ниже приведены лучшие ответы.

Я получил это с помощью вашего метода. Я думаю, есть несколько вещей, которые вы можете проверить:

1) Синхронизируете ли вы значения по умолчанию после установки значения:

defaults?.synchronize();
NSLog("%@ ", defaults?.dictionaryRepresentation())

2) Включили ли вы группу приложений как в приложении, так и в добавочном номере?

App Group capability for App Target App Group capability for Watch Extension Target

3) Используете ли вы правильно названную группу приложений при создании NSDefaults? Например, я использую:

NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");

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

enter image description here

  1. Все еще застряли? проверьте группы приложений в вашей учетной записи Apple

Ответ 2

Принятый ответ относится к Apple Watch OS 1. См. NSUserDefaults, не работающие в бета-версии Xcode с Watch OS2

Для OS2 - вам нужно будет использовать платформы WatchConnectivity и реализовать WCSessionDelegate.

import WatchConnectivity
import WatchKit

@available(iOS 9.0, *)
var alertDelegate:HomeIC? = nil

public class WatchData: NSObject,WCSessionDelegate {
    var session = WCSession.defaultSession()
   //

    class var shared: WatchData {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: WatchData? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = WatchData()
        }
        return Static.instance!
    }

    public func session(session: WCSession, didReceiveFile file: WCSessionFile){
        print(__FUNCTION__)
        print(session)

    }

    public func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
        print(__FUNCTION__)
        print(session)

        alertDelegate?.showMessage("didReceiveApplicationContext")
    }


    public func sessionReachabilityDidChange(session: WCSession){
        print(__FUNCTION__)
        print(session)
        print("reachability changed:\(session.reachable)")
        let text = session.reachable ? "reachable" : "unreachable"
        alertDelegate?.showMessage(text)
    }

    public func sessionWatchStateDidChange(session: WCSession) {
        print(__FUNCTION__)
        print(session)
        print("reachable:\(session.reachable)")
       // alertDelegate?.showMessage("sessionWatchStateDidChange")
        if !session.receivedApplicationContext.keys.isEmpty {
            alertDelegate?.showMessage(session.receivedApplicationContext.description)
        }
    }

    public func session(session: WCSession, didReceiveMessageData messageData: NSData){

        if !session.receivedApplicationContext.keys.isEmpty {
            alertDelegate?.showMessage(session.receivedApplicationContext.description)
        }
    }


    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject]){
        print(__FUNCTION__)
        if let data = message["data"] {
            alertDelegate?.showMessage(data as! String)
            return
        }
    }

    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
        print(__FUNCTION__)
        if let data = message["data"] {
            alertDelegate?.showMessage(data as! String)
            return
        }
        guard message["request"] as? String == "showAlert" else {return}

    }


    public func activate(){

        if WCSession.isSupported() {    //  it is supported
            session = WCSession.defaultSession()
            session.delegate = self
            session.activateSession()
            print("watch activating WCSession")
        } else {

            print("watch does not support WCSession")
        }

        if(!session.reachable){
            print("not reachable")
            return
        }else{
            print("watch is reachable")

        }
    }

}

Пример использования

class HomeIC: WKInterfaceController {
    // MARK: Properties


    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)

        // Initialize the 'WCSession'.
        WatchData.shared.activate()
        alertDelegate = self
    }

    internal func showMessage(msg:String){
       let defaultAction = WKAlertAction(title: msg, style: WKAlertActionStyle.Default) { () -> Void in }
       let actions = [defaultAction]
       self.presentAlertControllerWithTitle(  "Info",  message: "",  preferredStyle: WKAlertControllerStyle.Alert, actions: actions)
    }

}

enter image description here

в моем коде iphone/я могу вызвать обмен данными здесь

 if #available(iOS 9.0, *) {
        WatchData.shared.sendInbox()
    } else {
        // Fallback on earlier versions
    }

А где-то еще у меня есть еще один отдельный синглтон для сеанса просмотра данных.

@available(iOS 9.0, *)
public class WatchData: NSObject,WCSessionDelegate {
    var session = WCSession.defaultSession()
    var  payload:String = ""



    class var shared: WatchData {
        struct Static {
            static var onceToken: dispatch_once_t = 0
            static var instance: WatchData? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = WatchData()
        }
        return Static.instance!
    }


    public func sessionReachabilityDidChange(session: WCSession){
        print(__FUNCTION__)
        print(session)
        print("reachability changed:\(session.reachable)")
        if (session.reachable){

        }

    }


    public func sessionWatchStateDidChange(session: WCSession) {
        print(__FUNCTION__)
        print(session)
        print("reachable:\(session.reachable)")
    }

    public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
        print(__FUNCTION__)
        guard message["request"] as? String == "showAlert" else {return}
        guard let m = message["m"] as? String else { return }
        print("msg:",m)
    }


    public func sendInbox(){



        if (!session.reachable){
            if WCSession.isSupported() {    //  it is supported
                session = WCSession.defaultSession()
                session.delegate = self
                session.activateSession()
                print("iphone activating WCSession")
            } else {
                print("iphone does not support WCSession")
            }
            session.activateSession()
        }

        if(session.paired){
            if(session.watchAppInstalled){
                print("paired | watchAppInstalled")
            }
        }else{
           print("not paired | or no watchAppInstalled")
        }


        if(!session.reachable){
            print("not reachable")
            return
        }else{

            /*let transfer:WCSessionUserInfoTransfer =  (session.transferUserInfo(["data" : "Test2"]) as WCSessionUserInfoTransfer?)!
            if(transfer.transferring){
                print("-> iphone")
            }else{
                print("!-> iphone")
            }*/

            session.sendMessage(["data" :"test"],
                replyHandler: { reply in
                },
                errorHandler: { error in
                      print(error)
            })

        }

    }

}

См. пример приложения watch os2

https://github.com/shu223/watchOS-2-Sampler/tree/20eeebeed66764d0814603e97d3aca5933236299

Ответ 3

Как сказал @johndpope, общие NSUserDefaults больше не работают на WatchOS2.

Я публикую упрощенное решение, которое не так полно, как Джон, но в большинстве случаев выполнит свою работу.

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

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

import WatchConnectivity

Теперь установите сеанс WatchConnectivity с часами и отправьте некоторые данные.

if WCSession.isSupported() { //makes sure it not an iPad or iPod
    let watchSession = WCSession.defaultSession()
    watchSession.delegate = self
    watchSession.activateSession()
    if watchSession.paired && watchSession.watchAppInstalled {
        do {
            try watchSession.updateApplicationContext(["foo": "bar"])
        } catch let error as NSError {
            print(error.description)
        }
    }
}

Обратите внимание, это НЕ будет работать, если вы пропустите настройку делегата, поэтому даже если вы никогда не используете его, вы должны установить его и добавить это расширение:

extension MyViewController: WCSessionDelegate {

}

Теперь в приложении для часов (этот точный код работает и для Glances, и для других типов приложений для часов) вы добавляете фреймворк:

import WatchConnectivity

Затем вы настраиваете сеанс связи:

override func awakeWithContext(context: AnyObject?) {
    super.awakeWithContext(context)
    let watchSession = WCSession.defaultSession()
    watchSession.delegate = self
    watchSession.activateSession()
}

и вы просто слушаете и обрабатываете сообщения из приложения iOS:

extension InterfaceController: WCSessionDelegate {

    func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
        print("\(applicationContext)")
        dispatch_async(dispatch_get_main_queue(), {
            //update UI here
        })
    }

}

Это все, что нужно сделать.

Примечания:

  1. Вы можете отправить новое приложение контекста так часто, как вам нравится, и это не имеет значения, находятся ли часы рядом и подключены ли часы приложение работает. Это доставляет данные в фоновом режиме в интеллектуальный способ, и эти данные сидят там, ожидая, когда приложение Watch запущено.
  2. Если ваше приложение для часов действительно активно и работает, оно должно получить сообщение сразу в большинстве случаев.
  3. Вы можете отменить этот код, чтобы часы отправляли сообщения Приложение для iPhone таким же образом.
  4. applicationContext, который ваше приложение для часов получает при просмотре, будет ТОЛЬКО последним отправленным вами сообщением. Если вы отправили 20 сообщений до того, как приложение просмотра будет просмотрено, оно проигнорирует первые 19 и обработает 20-е.
  5. Чтобы установить прямое/жесткое соединение между двумя приложениями, фоновую передачу файлов или обмен сообщениями в очереди, посмотрите WWDC-видео.

Ответ 4

Другим способом общения между приложением и часами является червоточина:

https://github.com/mutualmobile/MMWormhole

Send:

[self.wormhole passMessageObject:@{@"titleString" : title} 
                  identifier:@"messageIdentifier"];

id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];

Recieve:

[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier" 
listener:^(id messageObject) {
// Do Something
}];