【Swift/Apple Watch】iOSが非アクティブ状態の際にwatchOSからデータを送信する方法!transferUserInfo

この記事からわかること

  • SwiftApple Watchアプリ開発する方法
  • iOS側が起動していない場合にデータ送信するには?
  • transferUserInfoメソッド使い方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

iOSが起動していない状態でwatchOSからデータを送信する

Apple Watch(watchOS)とiOSの連携アプリを開発中にiOSアプリが起動していない状態でWatch側からデータを送信したい場面になりました。流れとしては以下のような感じでiOS側が持つデータをWatchOS側からリクエストがあった時に送信するといった仕組みを実装したかったのです。

【Swift/Apple Watch】iOSが非アクティブ状態の際にwatchOSデータを送信する方法!transferUserInfo

Watch側からリクエストを送信する際にsendMessageメソッドを実行しても送信自体はされますが、iOSアプリを起動した後では受信できませんでした。ここではtransferUserInfoメソッドを使用することで実現することができました。

sendMessageとtransferUserInfoとの違い

WatchConnectivityフレームワークで両OS間でデータを送信する方法はいくつか存在します。

sendMessage

公式リファレンス:sendMessageメソッド

sendMessageペアリングされたアクティブなデバイスにメッセージを送信し、オプションで応答を処理するメソッドです。辞書形式でデータを送信することが可能です。

transferUserInfo

公式リファレンス:transferUserInfoメソッド

transferUserInfoペアリングされたデバイスに辞書形式でデータを送信できるメソッドです。しかしsendMessageとは異なりキューにデータをスタックしていき、相手が受信可能になっていれば送信されます。

このメソッドはシミュレーターでは動作確認することができないと公式に記述されているので実機を使用してテストする必要があります。

このようなメソッドは他にもupdateApplicationContexttransferFile(_:metadata:)があるようです。

違い〜まとめ〜

transferUserInfoメソッドの使い方

実際にtransferUserInfoを使用して「iOS側が持つデータをWatchOS側からリクエストがあった時に送信するといった仕組み」の連携アプリを実装してみます。シミュレーターでは動作確認できないので注意してください。

transferUserInfoメソッドで送られたデータにはWCSessionDelegateの以下のデリゲートメソッドから参照することができるようになります。

func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
  // transferUserInfoで送られたデータを参照
}

Watch側の実装

Watch側では正常にアプリが起動しセッションが開始されたタイミングでiOS側にデータを要求するリクエストを送信しています。

import WatchConnectivity

class iOSConnectViewModel: NSObject {
    
    var session: WCSession
    init(session: WCSession = .default) {
        self.session = session
        super.init()
        if WCSession.isSupported() {
            self.session.delegate = self
            self.session.activate()
        }
    }
    
    func request() {
        let requestDic: [String: Bool] = ["request": true]
        self.session.transferUserInfo(requestDic)
    }
}

extension iOSConnectViewModel: WCSessionDelegate {
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        if let error = error {
            print(error.localizedDescription)
        } else {
            print("セッション:アクティベート")
            request()
        }
    }
    
    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        guard let result = message["response"] as? Bool else {
            return
        }
        print(result)
    }
}

iOS側の実装

iOS側ではWatch側からリクエストを受信したらデータを送信するメソッドを実行するようにしておきます。

import WatchConnectivity

class WatchConnectViewModel: NSObject, ObservableObject {
    
    var session: WCSession
    init(session: WCSession = .default) {
        self.session = session
        super.init()
        if WCSession.isSupported() {
            self.session.delegate = self
            self.session.activate()
        }
    }
    
    func send() {
        let dataDic: [String: String] = ["response": "data"]
        self.session.sendMessage(dataDic) { error in
            print(error)
        }
    }
}
  
extension WatchConnectViewModel: WCSessionDelegate {
    
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { }
    
    func sessionDidBecomeInactive(_ session: WCSession) { }
    
    func sessionDidDeactivate(_ session: WCSession) { }
    
    func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
        guard let result = userInfo["request"] as? Bool else {
            return
        }
        if result {
            send()
        }
    }
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index