在我的项目中,我使用Watch Connectivity
向Watch和iPhone发送消息。我可以向手机发送消息并在启动应用程序时收到一串字符串,但是在使用操作时,我收到以下错误;
错误域= WCErrorDomain代码= 7012“消息回复花了太长时间。”
以下是设置方式;
首先,手表会向手机发送消息,然后手机会发送一串字符串以WKInterfaceTable
显示。这有时适用于加载应用程序。 (我获取名为Items
的所有NSManagedObjects并使用他们的title
字符串属性存储在名为array
的{{1}}中。
但是,我在手表上有一个操作,删除数组中的所有项目并使用新数据刷新表格。
手表上的操作使用watchItems
功能将sendMessage
发送到手机以从阵列中删除,然后手机将新更新的阵列发送到手表,手表会更新表格。但是,我要么返回相同的数组,要么出错。
非常简单,所以在Swift 3和Watch OS3 / iOS 10之前,一切都运行良好;整个应用程序曾经工作过。
以下是我如何设置所有内容;
手机应用代表
item
WATCH
import WatchConnectivity
class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {
var session : WCSession!
var items = [Items]()
func loadData() {
let moc = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
let request = NSFetchRequest<Items>(entityName: "Items")
request.sortDescriptors = [NSSortDescriptor(key: "date", ascending: true)]
request.predicate = NSPredicate(format: "remove == 0", "remove")
do {
try
self.items = moc!.fetch(request)
// success ...
} catch {
// failure
print("Fetch failed")
}
}
//WATCH EXTENSION FUNCTIONS
//IOS 9.3
/** Called when the session has completed activation. If session state is WCSessionActivationStateNotActivated there will be an error with more details. */
//HAVE TO INCLUDE
@available(iOS 9.3, *)
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?){
print("iPhone WCSession activation did complete")
}
@available(iOS 9.3, *)
func sessionDidDeactivate(_ session: WCSession) {}
func sessionWatchStateDidChange(_ session: WCSession) {}
func sessionDidBecomeInactive(_ session: WCSession) {
}
//APP DELEGATE FUNCTIONS
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
//Check if session is supported and Activate
if (WCSession.isSupported()) {
session = WCSession.default()
session.delegate = self;
session.activate()
}
return true
}
}
//DID RECIEVE MESSAGE
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Swift.Void) {
loadData()
func loadItems() {
watchItems.removeAll()
for a in self.items {
watchItems.append(a.title)
}
}
var watchItems = ["1","2","3","4","5"]
let value = message["Value"] as? String
//This is called when user loads app, and takes some time when using refresh action, sometimes times out
if value == "HELLOiPhone/+@=" {
print("Hello Message Recieved")
loadItems()
//send a reply
replyHandler( [ "Items" : Items ] )
}
//Not sure if receiving but does not delete array and send back to watch
if value == "removeALL@+=-/" {
for index in self.items {
index.remove = 1
//Saves MOC
}
loadData()
loadTasksData()
//send a reply
replyHandler( [ "Items" : Items ] )
}
else {
for index in self.items {
if index.title == value {
index.remove = 1
//Saves MOC
}
}
loadData()
loadTasksData()
//send a reply
replyHandler( [ "Items" : Items ] )
}
}
答案 0 :(得分:1)
您不应该从一个目标(iOS)向第二个目标(watchOS)发送或接收自定义类对象,而应该以字典格式发送/接收数据,例如[String:Any],此字典应包含数组您的自定义对象需要简单字典中键值对中的属性。这在手表方面很容易解码。
您应该创建一个扩展WCSessionDelegate的解耦类,如下所示,这样该类不仅可以在ExtensionDelegate中使用,还可以在任何WKInterfaceController中使用。
class WatchSessionManager: NSObject, WCSessionDelegate {
static let sharedManager = WatchSessionManager()
private override init() {
super.init()
self.startSession()
}
private let session: WCSession = WCSession.default
func startSession() {
session.delegate = self
session.activate()
}
func tryWatchSendMessage(message: [String: Any], completion: (([String: Any]) -> Void)? = nil) {
print("tryWatch \(message)")
weak var weakSelf = self
if #available(iOS 9.3, *) {
if weakSelf?.session.activationState == .activated {
if weakSelf?.session.isReachable == true {
weakSelf?.session.sendMessage(message,
replyHandler: { [weak self] ( response ) in
guard let slf = self else {return}
//Get the objects from response dictionary
completion?(response)
},
errorHandler: { [weak self] ( error ) in
guard let slf = self else {return}
print ( "Error sending message: % @ " , error )
// If the message failed to send, queue it up for future transfer
slf.session.transferUserInfo(message)
})
} else {
self.session.transferUserInfo(message)
}
}else{
self.session.activate()
self.session.transferUserInfo(message)
}
} else {
// Fallback on earlier versions
if self.session.activationState == .activated {
if self.session.isReachable == true {
self.session.sendMessage(message,
replyHandler: { ( response ) in
//Get the objects from response dictionary
completion?(response)
},
errorHandler: { ( error ) in
print ( "Error sending message: % @ " , error )
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
})
} else {
self.session.transferUserInfo(message)
}
}else{
self.session.activate()
self.session.transferUserInfo(message)
}
}
}
}
现在,您可以轻松地向您的iOS应用程序发送消息,以便在任何WKInterfaceController中使用上述函数唤醒并从那里获取数据(例如来自CoreData),并且完成块将具有您所需的数据,例如
let dict: [String: Any] = ["request": "FirstLoad"]
WatchSessionManager.sharedManager.tryWatchSendMessage(message: dict,completion:{ (data) in print(data)})
你应该在iOS端使用这个WatchSessionManager并接收请求,并根据请求的密钥,你应该从核心存储/ db中获取数据,并在didreceiveMessage函数的replyHandler中以简单的键值字典模式发送自定义对象列表如下。
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
var dict: [String: Any] = [String: Any]()
replyHandler(dict) //This dict will contain your resultant array to be sent to watchApp.
}
有些时候,iOS App App(Killed状态)无法访问WatchApp,为了解决这个问题,你应该调用&#34; tryWatchSendMessage&#34;定时器内约3秒间隔。当你从watchApp获得连接时,你应该使计时器无效。
WatchConnectivity的sendMessage功能非常强大,可以唤醒您的应用。您应该以优化的方式使用它。
答案 1 :(得分:0)
我刚刚处理了我的WatchOS应用程序。当我收到“消息回复花了太长时间”时,有一种情况。
然后我将后台任务处理程序添加到我的iOS应用程序中,并开始每秒向WatchOS应用程序发送消息。消息包含UIApplication.shared.backgroundTimeRemaining
。所以我得到:45秒,44秒,......,6秒,5秒......如果计时器运行时间低于5秒,则不会向iOS应用程序发送消息,我们将收到“消息回复耗时太长”。最简单的解决方案是每次定时器低于15秒时从手表发送空白消息。 backgroundTimeRemaining
将再次更新为45秒:45,44,43,...,17,16,15,(空白留言),45,44,43,......
希望它有助于某人