【編者按】本文做者爲 Matthew Maher,文章手把手地介紹瞭如何藉助 HealthKit 創建簡單的健身應用,包含諸多代碼實例。本文系國內 ITOM 管理平臺 OneAPM 編譯呈現。html
根據新聞報導,健康與健美在今時今日的重要程度比已往任什麼時候候都高。提及來有點好笑,彷佛就在幾天以前,筆者就見到過相似的新聞。或許,這是當人逐漸變老以後揮之不去的感受吧——渴望保持健康以及健美的感受。無論怎麼說,健康與健美是一個重要話題。技術的進步,尤爲是移動應用與硬件世界的不斷提升,正爲這個彷佛日益成長的話題帶來全新的契機。ios
HealthKit 是蘋果公司推出的一款移動應用平臺,旨在爲重要、可追蹤的健康數據與注重健康、熱衷鍛鍊的科技消費者搭起橋樑。這很酷。用戶能夠輕鬆地追蹤一段時間內可測量的健身與健康數據。除了瞭解自身的健康數據,看到圖表中喜人的增加曲線也的確鼓舞人心。git
正如人們想象的那樣,在管理健康信息時安全是很是重要的考慮因素。HealthKit 直截了當地將全部 HealthKit 信息的絕對控制權置於用戶的手中。用戶能夠受權或拒絕任何應用對其健康數據發出的讀取請求。github
做爲開發者,咱們須要徵求許可才能從/向 HealthKit 讀取/寫入數據。實際上,咱們須要明確地聲明打算讀取或改變的數據。此外,任何使用 HealthKit 的應用都必須包含隱私政策,這樣一來,用戶才能對其信息的處理感到更加放心。編程
##關於 OneHourWalker 在本文中,咱們將打造一個有趣的小應用,它會從 HealthKit 讀取數據,也會向其寫入新數據。來見一見 OneHourWalker 吧。swift
OneHourWalker 是一款追蹤使用者在一個小時內行走或跑步之距離的健身應用。用戶能夠將距離與 HealthKit 分享,以後就能在健康應用中讀取之。我知道,一個小時聽起來有點過於樂觀了(至少筆者本人可能沒法堅持下去)。所以,用戶也能夠提前停止計數,並分享距離。數組
額,到目前爲止,彷佛 OneHourWalker 只會向 HealthKit 寫入數據。咱們須要讀取什麼數據呢?安全
好問題!在步行鍛鍊時,我喜歡選擇鄉間或林間小路。經常,我會遇到樹枝低垂的區域。而我是一條身高 193cm 的漢子,這真的讓我很苦惱。解決辦法是:從 HealthKit 讀取用戶的身高數據,將之打印爲應用的一個標籤。這個標籤能夠做爲對用戶的善意提醒,這樣,他們就能避免在步行時被樹枝打到。性能優化
首先,點此下載 OneHourWalker 的初始項目。先試着跑起來,找找應用運行的感受。計數器與地點追蹤功能已經在運行了,因此咱們只需專一於 HealthKit 實現。注意,當到達 60 分鐘時間點時,計算器與追蹤都會中止。網絡
##啓用 HealthKit 首先,在咱們的應用中啓用 HealthKit。在項目導航中,點擊 OneHourWalker,以後點擊 Targets 下面的 OneHourWalker,以後選擇屏幕頂部的 Capabilities 選項。
查看 Capabilities 列表的底部,啓用 HealthKit
。這一簡單的操做會將 HealthKit 權限添加到 App ID,將 HealthKit 鍵添加到 info plist 文件,將 HealthKit 權限添加到受權文件,而且與 HealthKit.framework
相鏈接。就是這麼簡單。
##開始編程 接下來,跳轉到 TimerViewController.swift
,開始將 HealthKit 引入 OneHourWalker。首先,建立一個 HealthKitManager 實例。
import UIKit import CoreLocation import HealthKit class TimerViewController: UIViewController, CLLocationManagerDelegate { @IBOutlet weak var timerLabel: UILabel! @IBOutlet weak var milesLabel: UILabel! @IBOutlet weak var heightLabel: UILabel! var zeroTime = NSTimeInterval() var timer : NSTimer = NSTimer() let locationManager = CLLocationManager() var startLocation: CLLocation! var lastLocation: CLLocation! var distanceTraveled = 0.0 let healthManager:HealthKitManager = HealthKitManager()
全部 HealthKit 工做都會在 HealthKitManager.swift
中進行。它會包含重要的方法,咱們很快就會談到。
正如在前文介紹部分所述,咱們須要取得用戶的許可,才能讀取並修改他們的健康數據。在 viewDidLoad()
中,咱們就得這麼作。
override func viewDidLoad() { super.viewDidLoad() locationManager.requestWhenInUseAuthorization() if CLLocationManager.locationServicesEnabled(){ locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest } else { print("Need to Enable Location") } // We cannot access the user's HealthKit data without specific permission. getHealthKitPermission() }
getHealthKitPermission()
方法會調用 manager 的 authorizeHealthKit()
方法。若是一切順利,咱們便能調用setHeight()
方法。不過,咱們很快會在後文中談到此方法。
func getHealthKitPermission() { // Seek authorization in HealthKitManager.swift. healthManager.authorizeHealthKit { (authorized, error) -> Void in if authorized { // Get and set the user's height. self.setHeight() } else { if error != nil { print(error) } print("Permission denied.") } } }
在 HealthKitManager.swift 中,咱們會建立 authorizeHealthKit() 方法。然而,除此以外,咱們須要建立 HealthKit 存儲,用於鏈接應用與 HealthKit 的數據。
let healthKitStore: HKHealthStore = HKHealthStore() func authorizeHealthKit(completion: ((success: Bool, error: NSError!) -> Void)!) { // State the health data type(s) we want to read from HealthKit. let healthDataToRead = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight)!) // State the health data type(s) we want to write from HealthKit. let healthDataToWrite = Set(arrayLiteral: HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)!) // Just in case OneHourWalker makes its way to an iPad... if !HKHealthStore.isHealthDataAvailable() { print("Can't access HealthKit.") } // Request authorization to read and/or write the specific data. healthKitStore.requestAuthorizationToShareTypes(healthDataToWrite, readTypes: healthDataToRead) { (success, error) -> Void in if( completion != nil ) { completion(success:success, error:error) } } }
在請求獲取用戶健康數據的受權時,咱們須要明確指定打算讀取以及修改的信息。對本例而言,咱們須要讀取用戶的身高,從而幫助他們躲避有危險的低垂枝丫。咱們但願 HealthKit 能提供一個能夠轉化爲可理解的身高的 HKObject 量。此外,咱們還要得到修改 HKObject 量的許可,以記錄用戶的行走及跑步距離。
在處理好 OneHourWalker 與 iPad 通訊的可能性後,咱們作出官方請求。
在 HealthKitManager.swift
中,建立從 HealthKit 讀取用戶身高數據的 getHeight()
方法。
func getHeight(sampleType: HKSampleType , completion: ((HKSample!, NSError!) -> Void)!) { // Predicate for the height query let distantPastHeight = NSDate.distantPast() as NSDate let currentDate = NSDate() let lastHeightPredicate = HKQuery.predicateForSamplesWithStartDate(distantPastHeight, endDate: currentDate, options: .None) // Get the single most recent height let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false) // Query HealthKit for the last Height entry. let heightQuery = HKSampleQuery(sampleType: sampleType, predicate: lastHeightPredicate, limit: 1, sortDescriptors: [sortDescriptor]) { (sampleQuery, results, error ) -> Void in if let queryError = error { completion(nil, queryError) return } // Set the first HKQuantitySample in results as the most recent height. let lastHeight = results!.first if completion != nil { completion(lastHeight, nil) } } // Time to execute the query. self.healthKitStore.executeQuery(heightQuery) }
查詢身高數據的第一步是建立一個斷言以定義時間參數。咱們是在請求一段時間內的全部身高數據——與當前日期相距甚遠的一個過去的日期。顯然,這會返回一個數組。然而,咱們只想要最近期的身高,所以,咱們請求數據時可讓最新的數據排在數組的最前頭。
在構建這一查詢時,咱們會把數組的長度限制爲1。在考慮好出現錯誤的可能性後,咱們會將結果中的首個也即惟一一個數組項目分配給 lastHeight。接下來,完善 getHeight() 方法。最後,針對用戶的健康數據執行查詢。
回到 TimerViewController.swift
,在 app 真正投入使用以前,假設用戶受權了適當的許可,則 setHeight()
方法會被 getHealthKitPermission()
調用。
var height: HKQuantitySample?
首先,咱們須要爲 HKQuantitySample 實例聲明一個身高變量。
func setHeight() { // Create the HKSample for Height. let heightSample = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierHeight) // Call HealthKitManager's getSample() method to get the user's height. self.healthManager.getHeight(heightSample!, completion: { (userHeight, error) -> Void in if( error != nil ) { print("Error: \(error.localizedDescription)") return } var heightString = "" self.height = userHeight as? HKQuantitySample // The height is formatted to the user's locale. if let meters = self.height?.quantity.doubleValueForUnit(HKUnit.meterUnit()) { let formatHeight = NSLengthFormatter() formatHeight.forPersonHeightUse = true heightString = formatHeight.stringFromMeters(meters) } // Set the label to reflect the user's height. dispatch_async(dispatch_get_main_queue(), { () -> Void in self.heightLabel.text = heightString }) }) }
在 share()
方法之上,咱們會建立 setHeight()
方法。咱們請求的身高數據樣本以 HKQuantity
返回,標識符 HKQuantityTypeIdentifierHeight
知道這一對象。
接下來,調用在 manager 中建立的 getHeight()
方法。有了身高樣本,咱們還須要將之翻譯爲恰當的字符串以展現在標籤中。與往常同樣,考慮全部可能的錯誤狀況是很重要的。
到此,用戶就能夠打開 app,查看他們的身高(若是他的健康應用中記錄着身高數據),開啓計時器,追蹤他跑步或行走的距離了。接下來,咱們要處理將距離數據寫入健康應用的過程,這樣,用戶才能在同一個應用中保存其全部的健身數據。
在用戶結束外出鍛鍊以後,無論有沒有到60分鐘,他可能會使用 Share(分享)按鈕將其辛苦賺得的運動距離發送到健康應用。因此,在 share() 方法中,咱們須要調用 HealthKitManager.swift
的 saveDistance()
方法來實現這一過程。在這個方法中,咱們會發送運動距離以及取得該距離的日期。這樣,用戶便能在次日爭取更好的成績。
@IBAction func share(sender: AnyObject) { healthManager.saveDistance(distanceTraveled, date: NSDate()) }
接下來,回到 manager,咱們要在此處建立 saveDistance()
方法。首先,咱們要讓 HealthKit 知道咱們打算寫入一個表明步行及跑步距離的量。以後,將度量單位設置爲英里,並賦值官方的樣本量。HealthKit 的 saveObject()
方法會將此數據寫入用戶的健康數據。
func saveDistance(distanceRecorded: Double, date: NSDate ) { // Set the quantity type to the running/walking distance. let distanceType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning) // Set the unit of measurement to miles. let distanceQuantity = HKQuantity(unit: HKUnit.mileUnit(), doubleValue: distanceRecorded) // Set the official Quantity Sample. let distance = HKQuantitySample(type: distanceType!, quantity: distanceQuantity, startDate: date, endDate: date) // Save the distance quantity sample to the HealthKit Store. healthKitStore.saveObject(distance, withCompletion: { (success, error) -> Void in if( error != nil ) { print(error) } else { print("The distance has been recorded! Better go check!") } }) }
跳轉到健康應用,所記錄的數據會出如今 Walking + Running Distance(行走+跑步距離)一行(若是已經啓用)。此外,依照下面的路徑,咱們能夠看到詳細的樣本數據:Health Data tab(健康數據選項卡) > Fitness(健身) > Walking + Running Distance(行走+跑步距離) > Show All Data(顯示全部數據)。咱們的數據就在此列表中。輕擊一個單元,咱們的圖標(目前還未設置)就會與距離一同出現。再次點擊此單元,就能看到完整的細節數據。
藉助 OneHourWalker,咱們便能爲全世界 iOS 用戶的身體健康貢獻一份力量。然而,這只是一個開始。在使用 HealthKit 讀取並修改健康數據的道路上,還有很是多的可能性。
固然,對用戶而言,擁有這些可追蹤數據的好處不少。人們能夠輕鬆地按照日期、星期進行比較,從而激勵本身朝着目標努力。不過,真正的偉大之處在於,開發者能夠提供全新的,富有創造力的有趣方法來獲取數據。
歡迎你們對 HealthKit 應用進行測試。點擊此處查看 OneHourWalker 的最終版本。
本文系 OneAPM 工程師編譯整理。OneAPM Mobile Insight 以真實用戶體驗爲度量標準進行 Crash 分析,監控網絡請求及網絡錯誤,提高用戶留存。訪問 OneAPM 官方網站感覺更多應用性能優化體驗,想閱讀更多技術文章,請訪問 OneAPM 官方技術博客。
本文轉自 OneAPM 官方博客