web-dev-qa-db-ja.com

データをApple Watchアプリに渡す

アプリからデータを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)")
    }
}
_

このコードをwillActivate()に入れてみましたが、違いはないようです。

誰が私が間違っているのか知っていますか?

27
user3746428

私はあなたの方法を使用してそれを機能させました。確認できることがいくつかあります。

1)値を設定した後、デフォルトを同期していますか:

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

2)アプリと拡張機能の両方でアプリグループを有効にしましたか?

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

3)NSDefaultsを構築するときに、正しい名前のアプリグループを使用していますか?たとえば、私は使用します:

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

すべての設定が完了したら、アプリを実行し、デフォルトで値を設定してから、デフォルトから値を読み取るglanceターゲットを実行します。

enter image description here

  1. まだ立ち往生? Appleアカウントでアプリグループを確認してください
25
brindy

受け入れられる答えはApple watch os 1に適用されます。 NSUserDefaultsがWatch OS2でXcodeベータで機能しないを参照してください

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

        }

    }

}

ウォッチos2アプリのサンプルを参照してください

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

23
johndpope

@johndpopeが言ったように、共有NSUserDefaultsはWatchOS2では動作しません。

私は、johnのようにフル機能ではないが、ほとんどの場合に仕事を成し遂げる簡素化されたソリューションを投稿しています。

iPhoneアプリで、次の手順に従います。

Apple Watch fromにデータをプッシュするView Controllerを見つけて、上部にフレームワークを追加します。

import WatchConnectivity

次に、時計との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)
        }
    }
}

デリゲートの設定をスキップするとこれは機能しないため、使用しない場合でも設定してこの拡張機能を追加する必要があります。

extension MyViewController: WCSessionDelegate {

}

今、あなたの時計アプリで(この正確なコードはGlanceや他の時計キットアプリタイプでも機能します)フレームワークを追加します:

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. 新しいapplicationContextは何度でも送信でき、時計が近くにあり接続されているか、時計アプリが実行されているかは関係ありません。これにより、インテリジェントな方法でバックグラウンドでデータが配信され、そのデータはウォッチアプリの起動時に待機します。
  2. ウォッチアプリが実際にアクティブで実行されている場合、ほとんどの場合、すぐにメッセージを受信するはずです。
  3. このコードを逆にすると、時計からiPhoneアプリに同じ方法でメッセージを送信できます。
  4. ウォッチアプリが表示されたときに受け取るapplicationContextは、最後に送信したメッセージのみです。ウォッチアプリが表示される前に20のメッセージを送信した場合、最初の19は無視され、20番目のメッセージが処理されます。
  5. 2つのアプリ間で直接/ハード接続を行う場合、またはバックグラウンドファイル転送またはキューメッセージングの場合は、 WWDCビデオ を確認してください。
18
William T.

アプリと時計の間で通信する別の方法は、ワームホールを経由することです。

https://github.com/mutualmobile/MMWormhole

送信:

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

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

受け取る:

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