dca*_*mpb 5 ios swift healthkit watchos-2 watchconnectivity
我正在尝试使用 WatchConnectivity 框架将字符串从 Apple Watch 发送到 iPhone。
\n\n我启动了两个会话,一个是 WCSession,一个是 HKSession,因为我想在读取心率信息时将其从手表传输到 iPhone。(如果有更好的方法请告诉我)。
\n\n如果有帮助,我已经发布了我收到的日志消息。
\n\n2017-04-14 20:01:24.660433-0400 MoodTunes WatchKit Extension[180:16033] [WC] -[WCSession _onqueue_notifyOfMessageError:messageID:withErrorHandler:] AD8F92C9-FCAA-45B0-9B4C-0D5C95B72BEE\n errorHandler: YES with WCErrorCodeTransferTimedOut->IDSErrorTypeTimedOut-\n>IDSResponseTimedOut\nWatch send failed with error Error Domain=WCErrorDomain Code=7017 "Transfer \ntimed out." UserInfo={NSUnderlyingError=0x175a7da0 {Error \nDomain=com.apple.identityservices.error Code=23 "Timed out" UserInfo=\n{NSUnderlyingError=0x1752d4f0 {Error Domain=com.apple.ids.idssenderrordomain \nCode=12 "(null)"}, NSLocalizedDescription=Timed out}}, \nNSLocalizedDescription=Transfer timed out.} \nRun Code Online (Sandbox Code Playgroud)\n\niPhone ViewController.swift
\n\nimport HealthKit\nimport WatchKit\nimport Foundation\nimport CoreLocation\nimport WatchConnectivity\nimport UIKit\n\nclass ViewController: UIViewController, CLLocationManagerDelegate, \nWCSessionDelegate { \n\n@IBOutlet weak var timerLabel: UILabel!\n@IBOutlet weak var milesLabel: UILabel!\n@IBOutlet weak var hrLabel: UILabel!\nlet session = WCSession.default()\nstatic let sharedManager = ViewController()\nlet healthManager:HealthKitManager = HealthKitManager()\nlet healthStore = HKHealthStore()\nlet heartRateUnit = HKUnit(from: "count/min")\n\n//var anchor = HKQueryAnchor(fromValue: Int(HKAnchoredObjectQueryNoAnchor))\nvar currenQuery : HKQuery? // the current query can be nil\nvar heartRate: HKQuantitySample?\nvar zeroTime = TimeInterval()\nvar counter = 0\n\n\n\noverride func viewWillAppear(_ animated: Bool) {\n if (WCSession.isSupported()) {\n session.delegate = self\n session.activate()\n }\n getHealthKitPermission()\n}\noverride func viewDidLoad() {\n super.viewDidLoad()\n if (WCSession.isSupported()) {\n session.delegate = self\n session.activate()\n }\n getHealthKitPermission()\n}\noverride func didReceiveMemoryWarning() {\n super.didReceiveMemoryWarning()\n}\n// Function to get access to the user\'s Healthkit\nfunc getHealthKitPermission() {\n // checks if the health data is avaiable\n if HKHealthStore.isHealthDataAvailable() == true {hrLabel.text = "Good"} else {\n hrLabel.text = "not available"\n return\n }\n\n guard let quantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else {\n displayNotAllowed()\n return\n }\n let dataTypes = Set(arrayLiteral: quantityType)\n healthStore.requestAuthorization(toShare: dataTypes, read: dataTypes) { (success, error) -> Void in\n if success == false {\n self.displayNotAllowed()\n }\n }\n}\nfunc displayNotAllowed() {\n hrLabel.text = "not allowed"\n}\n\n// function crates a heartrate query for the healthstore. it returns an optional HKQuery\nfunc createHeartRateStreamingQuery(_ workoutStartDate: Date) -> HKQuery? {\n\n\n guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else { return nil }\n let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil, options: .strictEndDate )\n\n //let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])\n let predicate = NSCompoundPredicate(andPredicateWithSubpredicates:[datePredicate])\n\n\n let heartRateQuery = HKAnchoredObjectQuery(type: quantityType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in\n //guard let newAnchor = newAnchor else {return}\n //self.anchor = newAnchor\n self.updateHeartRate(sampleObjects)\n }\n\n heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in\n //self.anchor = newAnchor!\n self.updateHeartRate(samples)\n }\n return heartRateQuery\n}\n// updates the display on the UI, heartRateLabel and calls animateHeart for the heart enlargment\nfunc updateHeartRate(_ samples: [HKSample]?) {\n guard let heartRateSamples = samples as? [HKQuantitySample] else {return}\n var value = 0.0\n DispatchQueue.main.async {\n guard let sample = heartRateSamples.first else{return}\n value = sample.quantity.doubleValue(for: self.heartRateUnit)\n self.hrLabel.text = "Hello"\n //self.hrLabel.text = String(UInt16(value))\n\n }\n}\n\n // retrieve source from sample\n@available(iOS 9.3, *)\nfunc session(_: WCSession, activationDidCompleteWith: WCSessionActivationState, error: Error?) {\n\n}\n\nfunc session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {\n DispatchQueue.main.async() {\n guard let m = message["m"] as? String else { return }\n // self.label.text = m\n }\n}\nfunc sessionDidBecomeInactive(_ sesson: WCSession) -> Void {\n\n}\nfunc sessionDidDeactivate (_ session: WCSession) -> Void {\n\n}\n@IBAction func shareData(_ sender: Any) {\n if let query = createHeartRateStreamingQuery(Date()) {\n self.currenQuery = query\n healthStore.execute(query)\n\n\n}\n\n}\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这是我的苹果手表应用程序的界面控制器
\n\nInterfaceController.swift
\n\nimport WatchKit\nimport Foundation\nimport UIKit\nimport CoreLocation\nimport HealthKit\nimport WatchConnectivity\n\nclass InterfaceController: WKInterfaceController, HKWorkoutSessionDelegate, \nWCSessionDelegate {\n@IBOutlet private weak var heartRateLabel: WKInterfaceLabel!\n@IBOutlet private weak var heart: WKInterfaceImage!\n@IBOutlet private weak var startStopButton : WKInterfaceButton!\n@IBOutlet private weak var label : WKInterfaceLabel!\n\n@IBOutlet var dataLabel: WKInterfaceLabel!\n@IBOutlet private weak var deviceLabel: WKInterfaceLabel!\nlet healthStore = HKHealthStore() // Creates an instance of the healthkit store\n\n//State of the app - is the workout activated\nvar workoutActive = false\n\n// define the activity type and location\nvar hkSession : HKWorkoutSession? // ? means the session can be nil\nvar session = WCSession.default()\nlet heartRateUnit = HKUnit(from: "count/min")\n\n//var anchor = HKQueryAnchor(fromValue: Int(HKAnchoredObjectQueryNoAnchor))\nvar currenQuery : HKQuery? // the current query can be nil\n\noverride func awake(withContext context: Any?) {\n super.awake(withContext: context)\n if WCSession.isSupported() {\n session.delegate = self\n session.activate()\n }\n}\n\noverride func willActivate() {\n super.willActivate()\n\n // checks if the health data is avaiable\n guard HKHealthStore.isHealthDataAvailable() == true else {\n heartRateLabel.setText("not available")\n return\n }\n\n guard let quantityType = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else {\n displayNotAllowed()\n return\n }\n let dataTypes = Set(arrayLiteral: quantityType)\n healthStore.requestAuthorization(toShare: dataTypes, read: dataTypes) { (success, error) -> Void in\n if success == false {\n self.displayNotAllowed()\n }\n }\n}\n\nfunc session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {\n DispatchQueue.main.async() {\n guard let m = message["m"] as? String else { return }\n self.dataLabel.setText(m)\n }\n\n}\n@available(watchOSApplicationExtension 2.2, *)\nfunc session(_: WCSession, activationDidCompleteWith: WCSessionActivationState, error: Error?) {\n\n}\n\nfunc displayNotAllowed() {\n heartRateLabel.setText("not allowed")\n}\n// Function used to set the state of the workout, if it\'s still "running" then call workoutDidStart else call workoutDidEnd\nfunc workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {\n switch toState {\n case .running:\n workoutDidStart(date)\n case .ended:\n workoutDidEnd(date)\n default:\n print("Unexpected state \\(toState)")\n }\n}\n\nfunc workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {\n // Do nothing for now\n print("Workout error")\n}\n\n// function used to query the healthkitstore when the workout is active\nfunc workoutDidStart(_ date : Date) {\n if let query = createHeartRateStreamingQuery(date) {\n self.currenQuery = query\n healthStore.execute(query)\n } else {\n heartRateLabel.setText("cannot start")\n }\n}\n\nfunc workoutDidEnd(_ date : Date) {\n healthStore.stop(self.currenQuery!)\n heartRateLabel.setText("---")\n hkSession = nil\n}\n\n// MARK: - Actions\n@IBAction func startBtnTapped() {\n if (self.workoutActive) {\n //finish the current workout\n self.workoutActive = false\n self.startStopButton.setTitle("Start")\n if let workout = self.hkSession {\n healthStore.end(workout)\n }\n } else {\n //start a new workout\n self.workoutActive = true\n self.startStopButton.setTitle("Stop")\n startWorkout()\n }\n\n}\n\nfunc startWorkout() {\n\n // If we have already started the workout, then do nothing.\n if (hkSession != nil) {\n return\n }\n\n // Configure the workout session.\n let workoutConfiguration = HKWorkoutConfiguration()\n workoutConfiguration.activityType = .crossTraining\n workoutConfiguration.locationType = .indoor\n\n do {\n hkSession = try HKWorkoutSession(configuration: workoutConfiguration)\n hkSession?.delegate = self\n } catch {\n fatalError("Unable to create the workout session!")\n }\n\n healthStore.start(self.hkSession!)\n}\n\n// function crates a heartrate query for the healthstore. it returns an optional HKQuery\nfunc createHeartRateStreamingQuery(_ workoutStartDate: Date) -> HKQuery? {\n\n\n guard let quantityType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else { return nil }\n let datePredicate = HKQuery.predicateForSamples(withStart: workoutStartDate, end: nil, options: .strictEndDate )\n\n //let devicePredicate = HKQuery.predicateForObjects(from: [HKDevice.local()])\n let predicate = NSCompoundPredicate(andPredicateWithSubpredicates:[datePredicate])\n\n\n let heartRateQuery = HKAnchoredObjectQuery(type: quantityType, predicate: predicate, anchor: nil, limit: Int(HKObjectQueryNoLimit)) { (query, sampleObjects, deletedObjects, newAnchor, error) -> Void in\n //guard let newAnchor = newAnchor else {return}\n //self.anchor = newAnchor\n self.updateHeartRate(sampleObjects)\n }\n\n heartRateQuery.updateHandler = {(query, samples, deleteObjects, newAnchor, error) -> Void in\n //self.anchor = newAnchor!\n self.updateHeartRate(samples)\n }\n return heartRateQuery\n}\n// updates the display on the UI, heartRateLabel and calls animateHeart for the heart enlargment\nfunc updateHeartRate(_ samples: [HKSample]?) {\n guard let heartRateSamples = samples as? [HKQuantitySample] else {return}\n var value = 0.0\n DispatchQueue.main.async {\n guard let sample = heartRateSamples.first else{return}\n value = sample.quantity.doubleValue(for: self.heartRateUnit)\n self.heartRateLabel.setText(String(UInt16(value)))\n\n // retrieve source from sample\n let name = sample.sourceRevision.source.name\n self.updateDeviceName(name)\n self.animateHeart()\n }\n if (self.session.isReachable) {\n self.sendMessage(value: value)\n }\n\n}\n\n// function to create and send the message the iphone\nfunc sendMessage(value: Double) {\n let strValue = String(UInt16(value))\n let message = [ "m": strValue ]\n self.session.sendMessage(message, replyHandler:nil, errorHandler: { (error) -> Void in\n print("\xef\xa3\xbfWatch send failed with error \\(error)")\n })\n}\nfunc updateDeviceName(_ deviceName: String) {\n deviceLabel.setText(deviceName)\n}\n\n\nfunc animateHeart() {\n self.animate(withDuration: 0.5) {\n self.heart.setWidth(60)\n self.heart.setHeight(90)\n }\n\n let when = DispatchTime.now() + Double(Int64(0.5 * double_t(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)\n\n DispatchQueue.global(qos: .default).async {\n DispatchQueue.main.asyncAfter(deadline: when) {\n self.animate(withDuration: 0.5, animations: {\n self.heart.setWidth(50)\n self.heart.setHeight(80)\n })\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
小智 1
WCErrorCodeTransferTimedOut->IDSErrorTypeTimedOut->IDSResponseTimedOut
我通过重新启动 iPhone 和手表解决了这个错误。
| 归档时间: |
|
| 查看次数: |
1444 次 |
| 最近记录: |