将数据传递到Apple Watch应用程序

use*_*428 28 nsuserdefaults ios swift apple-watch watchkit

我正在尝试将数据从我的应用程序传递到Apple Watch应用程序中.基本上,我使用的方法与我用于创建今天小部件的方法相同,因此我通过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)")
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试将此代码放入其中willActivate(),但这似乎没有任何区别.

谁知道我哪里错了?

bri*_*ndy 25

我使用你的方法工作了.我猜你可以检查几件事:

1)设置值后是否同步默认值:

defaults?.synchronize();
NSLog("%@ ", defaults?.dictionaryRepresentation())
Run Code Online (Sandbox Code Playgroud)

2)您是否在应用和扩展程序中启用了应用组?

App Target的App Group功能 Watch Extension Target的应用程序组功能

3)在构建NSDefaults时,您是否使用了正确命名的应用程序组?例如,我使用:

NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");
Run Code Online (Sandbox Code Playgroud)

一旦完成所有设置,我运行应用程序,将值设置为默认值,然后运行扫视目标,从默认值中读取值,这似乎工作!

在此输入图像描述

  1. 仍然卡住?检查您的Apple帐户中的应用组

  • @Brindy:我跟着同样的步骤,但它不适合我.我收到零数据.任何调试帮助.. (7认同)

joh*_*ope 23

接受的答案适用于Apple watch os 1.请参阅NSUserDefaults,不使用Watch OS2处理Xcode beta

对于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")

        }
    }

}
Run Code Online (Sandbox Code Playgroud)

样本用法

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)
    }

}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

在我的iphone代码/我可以在这里调用共享数据

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

在其他地方,我有另一个用于监视数据会话的离散单例.

@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)
            })

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

请参阅示例watch os2 app

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


Wil*_* T. 18

正如@johndpope所说,共享NSUserDefaults不再适用于WatchOS2.

我发布了一个简化的解决方案,它不像john那样功能齐全,但在大多数情况下都可以完成工作.

在您的iPhone App中,请按照下列步骤操作:

选择查找要将数据推送到Apple Watch的视图控制器,并在顶部添加框架.

import WatchConnectivity
Run Code Online (Sandbox Code Playgroud)

现在,与watch建立WatchConnectivity会话并发送一些数据.

if WCSession.isSupported() { //makes sure it's 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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您跳过设置委托,这将不起作用,所以即使您从未使用它,您必须设置它并添加此扩展名:

extension MyViewController: WCSessionDelegate {

}
Run Code Online (Sandbox Code Playgroud)

现在,在您的监视应用程序中(此精确代码也适用于Glances和其他监视工具包应用程序类型),您可以添加框架:

import WatchConnectivity
Run Code Online (Sandbox Code Playgroud)

然后设置连接会话:

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

你只需要听取并处理来自iOS应用程序的消息:

extension InterfaceController: WCSessionDelegate {

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

}
Run Code Online (Sandbox Code Playgroud)

这里的所有都是它的.

注意事项:

  1. 您可以根据需要随时发送新的applicationContext,如果手表在附近并且已连接或手表应用程序正在运行,则无关紧要.这将以智能方式在后台传送数据,并且数据在手表应用程序启动时等待.
  2. 如果您的监视应用实际上处于活动状态且正在运行,则在大多数情况下它应立即收到该消息
  3. 您可以反转此代码,让手表以相同的方式向iPhone应用程序发送消息.
  4. 您的监视应用在查看时收到的applicationContext将只是您发送的最后一条消息.如果您在查看监视应用程序之前发送了20条消息,它将忽略前19条消息并处理第20条消息.
  5. 要在2个应用程序之间进行直接/硬连接或进行后台文件传输或排队消息传递,请查看WWDC视频.

  • @mohsen 这个答案已经有近 8 年历史了,我觉得在当前的 SDK 中可能有更好的方法来做到这一点。抱歉,我不知道。 (2认同)

Pau*_*and 7

应用程序和手表之间通信的另一种方式是通过虫洞:

https://github.com/mutualmobile/MMWormhole

发送:

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

id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];
Run Code Online (Sandbox Code Playgroud)

收到:

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