我知道HealthKit仍然要求用户通过iPhone授权HealthKit权限,即使对于Watch应用程序也是如此。事实上,Apple自己的Sample Code手表上没有任何授权码。如果您在手表上打开Speedy Sloth而不打开iPhone(要求访问),该应用程序将不会开始锻炼(因为它未经授权)而没有通知。
话虽如此,我们观察开发者必须按照我的理解在Watch上实施我们自己的授权检查并弹出警报以提醒用户打开iPhone应用程序并在未经授权时进行授权。
下面的代码是我对此的实现,但是用户偶尔会报告有授权问题,例如连续启动多个锻炼时。任何人都可以在我的逻辑中看到任何缺陷吗?
import WatchKit
import Foundation
import HealthKit
class InterfaceController: WKInterfaceController {
// MARK: - Properties
private let healthStore = HKHealthStore()
private var healthKitAuthorized = false
// MARK: - Interface Controller Overrides
override func awake(withContext context: Any?) {
super.awake(withContext: context)
}
override func willActivate() {
super.willActivate()
requestAccessToHealthKit()
}
@IBAction func didTapStartButton() {
segueToWorkOutInterfaceControllerIfAuthorized()
}
private func requestAccessToHealthKit() {
let healthStore = HKHealthStore()
let healthKitTypesToWrite: Set<HKSampleType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let healthKitTypesToRead: Set<HKObjectType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
healthStore.requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
if let unwrappedError = error {
DispatchQueue.main.async {
print("Watch Healthkit Authorization Error = \(unwrappedError.localizedDescription)")
WKInterfaceDevice.current().play(.notification)
self.showAlertWith(title: "HealthKit Permission Needed", message: "Open the App on your iPhone or go to -> Settings -> Privacy -> Health -> App and turn on permissions")
}
}
if !success {
DispatchQueue.main.async {
print("Watch Healthkit Authorization was unsuccessful no error reported")
WKInterfaceDevice.current().play(.notification)
self.showAlertWith(title: "HealthKit Permission Needed", message: "Open the App on your iPhone or go to -> Settings -> Privacy -> Health -> App and turn on permissions")
}
}
DispatchQueue.main.async {
self.healthKitAuthorized = true
print("Successful HealthKit Authorization FROM INTERFACE CONTROLLER")
}
}
}
func showAlertWith(title: String, message: String){
let action1 = WKAlertAction(title: "OK", style: .default) {
WKInterfaceController.reloadRootPageControllers(withNames: ["InterfaceController"],
contexts: nil,
orientation: .vertical,
pageIndex: 0)
}
presentAlert(withTitle: title, message: message, preferredStyle: .alert, actions: [action1])
}
func segueToWorkOutInterfaceControllerIfAuthorized() {
if healthKitAuthorized {
WKInterfaceController.reloadRootPageControllers(withNames: ["WorkoutInterfaceController"],
contexts: [contextDictionary],
orientation: .vertical,
pageIndex: 0)
} else {
self.showAlertWith(title: "HealthKit Permission Needed", message: "Open your iPhone -> Settings -> Privacy -> Health -> App and turn on permissions")
}
}
}
答案 0 :(得分:0)
我决定将我的HealthKit授权流程放入我的应用程序ExtensionDelegate
而不是InterfaceController
,并且到目前为止测试似乎更可靠地工作/触发,显然更多鉴于我不需要授权,除非需要,否则我的原始代码发布效率很高。仍然会欣赏其他人对此的任何意见。
import WatchKit
import HealthKit
import WatchConnectivity
class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {
let healthStore = HKHealthStore()
var watchSession: WCSession?
let defaults = UserDefaults.standard
func applicationDidFinishLaunching() {
requestAccessToHealthKit()
}
private func requestAccessToHealthKit() {
let healthKitTypesToWrite: Set<HKSampleType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let healthKitTypesToRead: Set<HKObjectType> = [
HKObjectType.workoutType(),
HKSeriesType.workoutRoute(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .restingHeartRate)!,
HKObjectType.characteristicType(forIdentifier: .dateOfBirth)!,
HKObjectType.quantityType(forIdentifier: .bodyMass)!,
HKObjectType.quantityType(forIdentifier: .vo2Max)!,
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!]
let authorizationStatus = healthStore.authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized: print("sharing authorized")
print("sharing authorized this message is from Watch's extension delegate")
case .sharingDenied: print("sharing denied")
healthStore.requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
print("Successful HealthKit Authorization from Watch's extension Delegate")
}
default: print("not determined")
healthStore.requestAuthorization(toShare: healthKitTypesToWrite, read: healthKitTypesToRead) { (success, error) in
print("Successful HealthKit Authorization from Watch's extension Delegate")
}
}
}
}
然后在InterfaceController
@IBAction func didTapStartButton() {
let authorizationStatus = healthStore.authorizationStatus(for: HKSampleType.workoutType())
switch authorizationStatus {
case .sharingAuthorized: print("sharing authorized")
segueToWorkoutInterfaceControllerWithContext()
case .sharingDenied: print("sharing denied")
self.showAlertWith(title: "HealthKit Permission Denied", message: "Please open The App on your iPhone or go to -> Settings -> Privacy -> Health -> App and turn on all permissions")
default: print("not determined")
self.showAlertWith(title: "HealthKit Permission Not Determined", message: "Please open The App on your iPhone or go to -> Settings -> Privacy -> Health -> App and turn on all permissions")
}
}