如何解决如何将带有 transferUserInfo 的字典传输到 Apple Watch? 更新初始答案
我正在尝试将我的 Apple Watch 应用程序的一部分置于付费墙后面。为此,iOS 应用程序会自动创建一个带有 true/false 值的字典,无论内容是购买还是非购买。问题是,无论我怎么尝试,我都无法将它传递给 Watch。
这是我的 iOS ViewController:
import WatchConnectivity
class ViewController: UIViewController,WCSessionDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
//The dictionary to be passed to the Watch
var dictionaryToPass = ["product1": 0,"product2": 0]
//This will run,if the connection is successfully completed.
//BUG: After '.activate()'-ing the session,this function successfully runs in the '.activated' state.
func session(_ session: WCSession,activationDidCompleteWith activationState: WCSessionActivationState,error: Error?) {
print("WCSession - activationDidCompleteWith:",activationState,"and error code:",error as Any)
switch activationState {
case .activated:
print("WCSession - activationDidCompleteWith .activated")
//session.transferUserInfo(dictionaryToPass)
case .inactive:
print("WCSession - activationDidCompleteWith .inactive")
case .notActivated:
print("WCSession - activationDidCompleteWith .notActivated")
default:
print("WCSession - activationDidCompleteWith: something other ")
break
}
}
func sessionDidBecomeInactive(_ session: WCSession) {
print("WCSession - sessionDidBecomeInactive")
}
func sessionDidDeactivate(_ session: WCSession) {
print("WCSession - sessionDidDeactivate")
}
//Pushing the button on the iOS storyboard will attempt iOS-watchOS connection.
@IBAction func tuiButton(_ sender: UIButton) {
let session = WCSession.default
if session.isReachable {
session.transferUserInfo(dictionaryToPass)
} else if WCSession.isSupported() {
session.delegate = self
session.activate()
}
}
@IBAction func sendmButton(_ sender: UIButton) {
let session = WCSession.default
if session.isReachable {
session.sendMessage(dictionaryToPass,replyHandler: { reply in
print(reply)
},errorHandler: nil)
} else if WCSession.isSupported() {
session.delegate = self
session.activate()
}
}
}
这就是我在 watchOS 的接口控制器上所拥有的:
import WatchConnectivity
class InterfaceController: WKInterfaceController,WCSessionDelegate {
//The text label on the Watch Storyboard. Helps with debugging.
@IBOutlet weak var helloLabel: WKInterfaceLabel!
func session(_ session: WCSession,error: Error?) {
print("watchOS - activationDidCompleteWith:",activationState)
}
//Whatever arrives,it will get printed to the console as well as the 'helloLabel' will be changed to help the debugging progress.
//BUG: This is the part,that never gets run,even tough the WCSession activated successfully.
func session(_ session: WCSession,didReceiveUserInfo userInfo: [String : Any] = [:]) {
print("watchOS - didReceiveUserInfo",userInfo)
helloLabel.setText("didReceiveUserInfo")
}
func session(_ session: WCSession,didReceiveMessage message: [String : Any]) {
print("watchOS - didReceiveMessage",message)
helloLabel.setText("didReceiveMessage")
}
func session(_ session: WCSession,didReceiveMessage message: [String : Any],replyHandler: @escaping ([String : Any]) -> Void) {
replyHandler(["does it work?": "yes sir"])
print("watchOS - didReceiveMessage",message)
helloLabel.setText("didReceiveMessage")
}
//Setting the Interface Controller as WCSession Delegate
private var session: WCSession = .default
override func awake(withContext context: Any?) {
session.delegate = self
session.activate()
}
//Activating the session on the watchOS side as well.
override func willActivate() {
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}
}
解决方法
更新
在查看您的代码后,我注意到两个主要问题:
- 您没有将
InterfaceController
设置为WCSession
委托。需要从两端激活连接。
class InterfaceController: WKInterfaceController,WCSessionDelegate {
private var session: WCSession = .default
override func awake(withContext context: Any?) {
session.delegate = self
session.activate()
}
}
- 为了能够接收来自对方设备的消息,您需要实现 session(_:didReceiveMessage:replyHandler:) 方法。将这些方法添加到您的
InterfaceController
:
func session(_ session: WCSession,didReceiveMessage message: [String : Any]) {
print("watchOS - didReceiveMessage",message)
}
func session(_ session: WCSession,didReceiveMessage message: [String : Any],replyHandler: @escaping ([String : Any]) -> Void) {
replyHandler(["does it work?": "yes sir"])
print("watchOS - didReceiveMessage",message)
}
如您所见,我还实现了第二个函数,通过调用它传递一些数据来响应 replyHandler
。这在调试时很有用。
更新您的按钮操作和 sendMessage
调用。如果设备已经可以访问,则无需重新激活连接,还可以传递回复句柄以确保手表返回数据。
@IBAction func button(_ sender: UIButton) {
if session.isReachable {
session.sendMessage(watchInAppPurchases,replyHandler: { reply in
print(reply)
},errorHandler: nil)
} else if WCSession.isSupported() {
session.delegate = self
session.activate()
}
}
初始答案
不要在调用 activate()
后直接尝试同步数据,因为不能保证已经建立连接。文档明确指出:
此方法异步执行并在完成时调用委托对象的 session(_:activationDidCompleteWith:error:) 方法。
既然您确实将 self
设置为委托,请尝试将 transferUserInfo
调用移至 session(_:activationDidCompleteWith:error:)
实现。
func session(
_ session: WCSession,activationDidCompleteWith activationState: WCSessionActivationState,error: Error?
) {
switch activationState {
case .activated:
session.transferUserInfo(watchInAppPurchases)
default:
// handle other states
break
}
}
此外,在使用 Swift 时,请确保避免对属性、函数等使用 CapitalizedCamelCase
名称。仅对类型使用此表示法。我已将上面代码示例中的原始 WatchInAppPurchases
转换为 watchInAppPurchases
。
如果您对 transferUserInfo
的调用仍然无效,请尝试改为调用 sendMessage(_:replyHandler:errorHandler:)
switch activationState {
case .activated:
session.sendMessage(watchInAppPurchases,replyHandler: nil,errorHandler: nil)
default:
// handle other states
break
}
并监控您手表扩展程序中的 session(_:didReceiveMessage:replyHandler:) 是否有任何传入消息。
,原来是 watchOS 模拟器出了问题。很可惜苹果的一个。
在 Apple 论坛上进一步阅读: https://developer.apple.com/forums/thread/127460
如果其他人有同样的想法,我建议在物理设备上运行代码,它在那里完美运行。如果 Google 结果中的任何人正在寻找最终的工作代码,则可以在 here 中找到该代码。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。