【Swift/Apple Watch】iOSが非アクティブ状態の際にwatchOSからデータを送信する方法!transferUserInfo
この記事からわかること
- SwiftでApple Watchアプリを開発する方法
- iOS側が起動していない場合にデータを送信するには?
- transferUserInfoメソッドの使い方
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.0
- watchOS:10.0
- Swift:5.9
- macOS:Sonoma 14.1
iOSが起動していない状態でwatchOSからデータを送信する
Apple Watch(watchOS)とiOSの連携アプリを開発中にiOSアプリが起動していない状態でWatch側からデータを送信したい場面になりました。流れとしては以下のような感じでiOS側が持つデータをWatchOS側からリクエストがあった時に送信するといった仕組みを実装したかったのです。
Watch側からリクエストを送信する際にsendMessage
メソッドを実行しても送信自体はされますが、iOSアプリを起動した後では受信できませんでした。ここではtransferUserInfo
メソッドを使用することで実現することができました。
sendMessageとtransferUserInfoとの違い
WatchConnectivity
フレームワークで両OS間でデータを送信する方法はいくつか存在します。
sendMessage
sendMessage
はペアリングされたアクティブなデバイスにメッセージを送信し、オプションで応答を処理するメソッドです。辞書形式でデータを送信することが可能です。
transferUserInfo
transferUserInfo
もペアリングされたデバイスに辞書形式でデータを送信できるメソッドです。しかしsendMessage
とは異なりキューにデータをスタックしていき、相手が受信可能になっていれば送信されます。
このメソッドはシミュレーターでは動作確認することができないと公式に記述されているので実機を使用してテストする必要があります。
このようなメソッドは他にもupdateApplicationContext
やtransferFile(_:metadata:)
があるようです。
違い〜まとめ〜
- sendMessage・・・辞書形式でデータを送信/相手が基本アクティブ/非アクティブなら成功しない(watchOS→iOSは別)
- transferUserInfo・・・辞書形式でデータを送信/相手がアクティブでない場合キューにスタックされていく/アクティブになったら送信
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()
}
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。