ios - 如何将带有 transferUserInfo 的字典传输到 Apple Watch?
问题描述
我正在尝试将我的 Apple Watch 应用程序的一部分放在付费专区后面。为此,无论内容是否购买,iOS 应用都会自动创建一个具有真/假值的字典。问题是,无论我如何尝试,我都无法将其传递给 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, activationDidCompleteWith activationState: WCSessionActivationState, 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
通过调用 a 来响应 a 传递一些数据。这在调试时很有用。
更新您的按钮操作和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
}
并在您的监视扩展中监视会话(_:didReceiveMessage:replyHandler :)是否有任何传入消息。
推荐阅读
- c# - 使用 C# 在 microsoft botframework 中语音到文本
- python - 压缩两个具有相同文件名的列表中的项目?
- json - XML 和 JSON 格式的 Django REST API
- xamarin.android - 将目标 android 版本从 7.1 更改为 8.1 显示错误(xamarin)
- ios - 如何在 Swift 的数组中获取所有可用的表情符号?
- mongodb - 在 MongoEngine 中使用 __raw__ 访问 ListField/EmbeddedDocumentListField 中的项目
- javascript - 如何使用 JavaScript 检测冷门浏览器(百度)?
- python - 从烧瓶中,如何将 matplotlib 绘图图像发送到 JSON 对象?
- c# - WSDL 生成的类型不采用 COM 属性
- c - 使用结构的数组排序