天天看點

HealthKit開發教程Swift版:起步

作者:Ernesto García 譯者:Mr_cyz )

HealthKit是iOS 8中的新的API,它提供了一種優雅的方式來擷取和存儲使用者的健康資料。

在本篇HealthKit教程中,你将會建立一個簡單地記錄使用者資訊的app。在此過程中,你會學到許多關于HealthKit的知識,例如:

怎麼樣向使用者請求允許來獲得HealthKit的資料

怎麼樣讀取資訊然後将其格式化展示在螢幕上

怎麼樣将資料寫回HealthKit。

準備好進行一次精彩的HealthKit之旅了嗎?繼續往下讀吧!

注意:要想完成這次教程,你應該有一個可用的iOS開發者賬号,如果沒有的話,你将無法讓HealthKit工作,也沒有通路HealthKit Store的權限。

你将建立一款簡單地應用,擷取使用HealthKit的許可,然後讀寫HealthKit的資料。這裡為你準備了一款起始項目,該起始項目中已經建立好了所有的使用者互動界面,你隻需要将注意力集中于HealthKit功能即可。

現在下載下傳這個​​初始項目​​,然後在Xcode中打開。

編譯并且運作這個工程,你會看到這款應用的内部結構:讀寫使用者鍛煉資訊(Workout)與身體資料采樣的資訊(Quantity samples)。

HealthKit開發教程Swift版:起步

接下來,你将按照如下順序完善這款應用:

擷取使用HealthKit的許可

讀取使用者的個人特征資訊(characteristic)

讀取并儲存使用者的資料采樣資訊(quantity sample)

讀取并儲存使用者的鍛煉、健身資訊(workout)

在這之前,你必須先更改這個項目的Bundle Identifier,然後選擇你的開發團隊Team。

在項目導航欄中選擇我們的項目HKTutorial,在Target欄中選擇HKTutorial。然後選擇General菜單,将Bundle Identifier改為你自己的名字或者是域名。

然後,在Team組合框中選擇與你的開發者賬号關聯的開發團隊。

HealthKit開發教程Swift版:起步

到目前為止一切順利!

為了使用HealthKit,你必須為HealthKit授權。

依然是在Target欄中,打開Capabilities菜單,将HealthKit這一部分的開關設為ON的狀态,如螢幕截圖中顯示那樣:

HealthKit開發教程Swift版:起步

等待Xcode做好相關的配置,一旦Xcode完成配置,你的授權工作就完成了。這很簡單,不是嗎?

記住,你的應用永遠不會自動擷取健康資料——你需要獲得許可。這就是接下來你要做的事情。

首先,打開HealthManager.swift,看一下,你會發現一個空的類。

在這裡你将添加你的這個工程所需要的HealthKit相關的代碼。它将是其他類與HealthKit互動的入口。一個好消息是,你已經在一些必要的控制器中有這個類的一個執行個體了,是以不需要再建立其他的執行個體了。

導入HealthKit架構,依然是在HealthManager.swift中,在頂部注釋的下面加上這一行:

HealthKit架構的核心是HKHealthStore類,是以你也需要這個類的一個執行個體,在HealthManager中加入這一行:

既然你已經建立好了HKHealthStore類的執行個體,下一步就是獲得許可使用它了。

還記得嗎?使用者是可以掌控他們的資料并決定哪一部分可以被你記錄追蹤的。這意味着你并不是去一次性請求HealthKit Store的全局許可,而是去擷取某一特定的類型的許可,是你的應用需要從Store中讀寫的那一部分。

所有目标均繼承自HKObjectType類,該類提供了友善的方法來建立子類。

你隻需要調用一個方法,傳入一個代表特定種類的請求的常量即可,下面列出了這些友善的方法,覆寫了上面提到過的每一種類别。這裡不需要在Xcode中做任何事,隻需要看一看,學習一下:

在 這些方法中使用到的辨別符必須是在HealthKit中預定義的常量,例如HKQuantityTypeIdentifierHeight是資料采樣資訊 種類中的身高測量,HKCharacteristicTypeIdentifierBloodType是個人特征種類中的血液類型。

鍛煉資訊不需要任何辨別符,因為它并沒有子類别。

現在回到編碼上來,打開HealthManager.swift,将下面這個方法添加到HealthManager中

讓我們回顧一下上面的代碼,一步一步來:

你建立了一個NSSet對象,裡面存有本篇教程中你将需要用到的從Health Stroe中讀取的所有的類型:個人特征(血液類型、性别、出生日期)、資料采樣資訊(身體品質、身高)以及鍛煉與健身的資訊。

你建立了另一個NSSet對象,裡面有你需要向Store寫入的資訊的所有類型(鍛煉與健身的資訊、BMI、能量消耗、運動距離)。

這裡你檢查HealthKit是否可用,如果不可用就傳回一條錯誤資訊。對于一個通用的app來說這是必不可少的,因為某些裝置上HealthKit可能并不可用。在本文寫作時,iPad上就無法使用HealthKit。

發出具體的請求許可。這裡調用了requestAuthorizationToShareTypes:readTypes方法并将之前定義好的讀取和寫入的種類作為參數傳了進去。

既然你的代碼知道怎麼樣去請求許可,你需要為你的app提供一種方法來回調。

我們的起始項目中已經有一個“Authorize HealthKit”按鈕來做這件事,它會在MasterViewController中調用authorizeHealthKit()方法。那裡聽起來像是一個非常好從你的app收到回報的地方。

打開MasterViewController.swift,找到authorizeHealthKit()然後将下面這一行:

替換為:

這段代碼是從authorizeHealthKit發來的請求許可的回調,在控制台上用一段資訊展示了請求結果。

編譯然後運作,在主視圖中點選“Authorize HealthKit”按鈕,你将會看到這個場景彈出:

HealthKit開發教程Swift版:起步

将所有的開關打開,然後點選Done按鈕,你将會在Xcode中看到如下資訊:

太棒了,你的應用已經成功連接配接到Store了,準備更深入到HealthKit的世界中吧!

在這一部分,你将會學習到:

怎麼樣讀取使用者的個人特征資訊

怎麼樣讀寫不同種類的資料采樣資訊

所有有趣的事都發生在ProfileViewController,在這裡你會讀到使用者的特征(生日、年齡、血液類型)并且查詢身高和體重資料。

在那之後,你将會用這些資料進行一次計算(在這裡,BMI代表Body Mass Index,身體品質指數)。并且将計算出來的資料儲存到Store中。

注意:身體品質指數(BMI)被廣泛地應用于表示身體肥胖程度,由一個人的身高和體重經過一個公式計算而來,詳情請點選​​這裡​​。

在你讀取使用者的特征資訊之前,你需要確定在HealthKit Store中是有資訊存在的,是以你需要先填充一些資料。

打開在你的裝置或者模拟器上的Health應用,選擇Health Data欄,然後在清單中選擇Me,然後點選Edit,添加生日、性别和血液類型的資訊。

随便輸入一些資訊,甚至是你耍點小聰明,填上以前狀态下的資訊或者是Kitty的資訊也沒問題。

HealthKit開發教程Swift版:起步

你下一步的任務是搭建架構然後讀入這些資訊。

傳回到Xcode,打開HealthManager.swift,将下面的方法加到HealthManager類的底部。

該方法從Store中讀入使用者的特性資訊,以一個元組的形式傳回,它的工作方式是:

調用dateOfBirthWithError()來從HKHealthStore中讀取生日,下一行進行月曆計算來确定年份。

biologicalSexWithError()來确定性别。

血液類型是從bloodTypeWithError()中讀入的。

最後,所有的資訊以元組的形式傳回。

如果你現在編譯并運作,你無法從UI上看出個人特征的資料有任何改變,因為你至今都沒有為這個應用打開Store以及共享資料的入口。

打開ProfileViewController.swift并找到updateProfileInfo()。

當你點選按鈕“Read HealthKit Data”時你需要調用這個方法,是以将下面這一行:

這段代碼調用了你剛剛建立好的readProfile()方法,然後在UI方面将文本放到了合适的Label中。

有趣的是,biologicalSexLiteral和bloodTypeLiteral并不是Healthk的方法,它們僅僅是兩個便捷方法——還記得我提過嗎?——基于血液類型和性别的數值來傳回一個字元串。

現在你的應用中,特征資訊與Store已經可以互互相動了,現在編譯然後運作你的app。

前往Profile & BMI視圖,點選“Read HealthKit Data”,你會看到tableView中得資料展示了你剛才在Health應用中輸入的資料。

HealthKit開發教程Swift版:起步

太棒了!你成功地從HealthKit Store中讀到了使用者的特征資訊。

現在你講讀取使用者的身高和體重,然後基于這些資料計算BMI數值,最後一并展示到視圖中。

要從Store中讀取特征之外的資訊你需要使用一條查詢。查詢的基類是HKQuery,這是一個抽象類,能夠實作每一種查詢目标。為了讀取身體素質資訊,你需要建立一條HKSampleQuery。

要建立一條查詢,你需要:

指明你需要查詢的資訊的種類(例如:身高或者體重)

一個可選的NSPredicate來指明查詢條件(例如起止日期),以及一個NSSortDescriptors數組,來告訴Store怎麼樣将結果排序。

一旦你有了一條查詢,就可以調用HKHealthStore的executeQuery()方法來獲得結果。

注意:如果你對Core Data熟悉,你可能會注意到一些共同點:一個HKSampleQuery非常類似于NSFetchResult來查詢實體類型,也是由你提供斷言和排序描述,然後讓對象上下文去執行查詢并獲得結果。

你需要在一個普通的方法中發起一段查詢,來擷取所有資料采樣資訊種類的最近一部分的資訊,這包括了身高和體重,因為你想展示的是最近剛剛測量得到的結果。

打開HealthManager.swift然後将下面的方法添加到HealthManager類中:

要得到最近的資訊,你建構了一段查詢,指明排序方式為按日期降序。此時最接近的應該是查詢傳回結果的第一條。

由于(大多數情況下)你隻需要第一條資訊,你使用limit來限制傳回資訊的數量為1.這相比較于傳回全部的結果然後從中舍棄而言節省了時間和資源。

讓我們深入到查詢的内部工作中去一探究竟:

這 裡使用predicateForSamplesWithStartDate(_:endDate:options)來建立了一個日期并基于該日期建立一個 謂詞。注意:這裡通過日期作為過濾條件隻是一個示範,并不是必須要用這樣的謂詞,而且這個謂詞是可以被設定為nil的。

建立排序描述符,表明傳回的結果按照開始日期降序排序。

因為你隻需要最新的資料,将limit限制為1.

建構查詢對象,傳入查詢類型、謂詞、限制以及排序描述符。當查詢完成之後,将調用completion閉包并傳回讀入的資料。

最後,執行該查詢。

現在你需要在UI中調用這個方法,打開ProfileViewController.swift将下面屬性的聲明添加到ProfileViewController中:

你将使用這兩個HKQuantitySample類型的屬性來從HealthStore中獲得身高和體重的資料。

現在,找到updateWeight方法,将下面這一行:

讓我們一段一段地分析:

首先你指明了希望通過quantityTypeForIdentifier(從HKSample中)查詢的資料采樣資訊的類型,然後将與體重類型相關聯的辨別符HKQuantityTypeIdentifierBodyMass傳入。

然後,使用這些類型作為參數來調用你剛剛在HealthManager中定義的方法,通過該方法傳回體重類型的資訊。

在completion閉包中,使用doubleValueForUnit來得到千克為機關的體重數值,然後使用NSMassFormatter将該值轉換為本地化的字元串。

在主線程中更新UI界面,展示體重資訊。HealthKit使用内部單獨的一個線程,是以,確定所有更新UI的操作都在主線程上進行是非常重要的。同時你調用了一個方法叫做updateBMI——這是包含在初始項目中的一個方法,來計算并展示BMI(身體品質指數)。

那個新的NSMassFormater是什麼?

你 會在你剛剛添加上去的代碼中發現這個新的類,盡管它不是HealthKit的一部分,但卻十分有關聯。iOS8提供了這個以及其他的格式轉換器,例如圖檔 方面的NSLengthFormatter和NSEnergyFormatter。它們将數量轉換為字元串,并把使用者所處位置也考慮在内。

當你使用它們的時候,你不需要自己本地化字元串或者配置目前位置的機關轉換。轉換器會來處理這些細節。

例如,你正在使用千克機關,即時你的系統不是公制配置的,轉換器也會自動将其轉換為合适的機關。

現在,你需要為身高做同樣的事,找到方法updateHeight(),将下面這行:

正如你所看到的,這段代碼幾乎與讀取體重時的代碼一緻,但是有兩個值得注意的不同點:

首先,身高類型是由與身高資料類型相關聯的辨別符HKQuantityTypeIdentifierHeight來建構的,以此來允許你讀取身高方面的資料。

第二,這裡使用了NSLengthFormatter來擷取對應身高數值的本地化的字元串。NSLengthFormatter本身就是用來擷取本地化的長度的字元串。

現在你将用你剛剛從HealthKit Store中讀取到的身高和體重來計算BMI(身體品質指數)并且将這些資料展示到螢幕上。打開ProfileViewController.swift并找到updateBMI()方法。

将下面這一行:

這段代碼做了什麼呢?具體來說:

使用方法doubleValueForUnits()來獲得身高和體重的double類型的資料,也是在這裡你指明你想要的機關。注意:HKUnit提供了一種方法來建構所有類型的機關,這裡你用克來轉換體重,用米來轉換身高,你必須十分小心,確定使用了一緻的機關。因為如果要求的機關與資料的類型不相比對的話,會抛出一個異常。例如,想把體重數值轉換為距離機關是不會起作用的。

通過調用calculateBMIWithWeightInKilograms()來計算BMI,這是初始項目中附帶的一個工具方法,通過身高和體重來計算BMI。

在合适的Label中展示BMI數值。因為BMI僅僅是一個數字,你不需要任何轉換器來轉換它。

注意:如果你沒有在HealthKit Store中添加一些供app讀入的資料的話,你會被絆住的。如果你還沒有做,你至少應該添加一些身高和體重的資料。

現在,編譯并運作app,前往Profile & BMI界面,點選“Read Health Data”,如果你已經在Health應用中添加了一些身高和體重的資料,那麼你會看到類似如下輸出:

HealthKit開發教程Swift版:起步

酷!你剛剛從HealthKit Stroe中讀到了你的第一份資料采樣的資訊并且使用它們計算了BMI。

在這一部分,你将學到如何将資料儲存到HealthKit Store。你的測試資料将是上一部分中你計算出來的BMI數值。

打開HealthManager.swift,添加下面的方法:

下面是這段代碼所做的事情:

使用HKQuantitySample建立一個采樣的對象,為了建立一條采樣,你需要:

一個身體素質類型的對象,例如likeHKQuantityType,使用合适的資料類型來初始化,本例中使用的是HKQuantityTypeIdentifierBodyMassIndex。

一個身體素質的對象,例如likeHKQuantity,通過傳入bmi數值和機關來初始化。本例中,由于BMI數值是一個純量的數值,沒有機關,是以你需要使用countUnit

起止日期,本例中兩者都是目前時間。

調用HKHealthStore的方法saveObject()将資料儲存到HealthKit Store

現在你将在控制器中使用該方法來儲存BMI資料,打開ProfileViewController.swift并找到saveBMI().

十分簡單——這裡調用了你剛剛建立的方法,并傳入了BMI數值和目前時間。

編譯并運作,導航到Profile視圖并點選”Read Health Data”來讀取資訊,計算BMI數值并展示結果。接下來,點選”Save BMI”來儲存計算好的數值。如果一切運作正常,你将在Xcode控制台中看到如下資訊:

做得漂亮!資料被儲存了。你可以通過Health應用确定一下資料是否真的在HealthKit Store中。打開Health應用,導航到”Health Data”欄,前往”Body Measurements”然後前往”Body Mass Index”。

HealthKit開發教程Swift版:起步

如果你看到類似如上的資訊,那你就成功了。這意味着你計算好的BMI已經在那裡,為使用者、為Health應用的檢查、以及為其他第三方應用都準備好了~

這裡是目前為止的​​示例工程​​。

! 重要!:如果你想使用上面的示例工程,在使用HealthKit之前需要進行一些設定,因為該工程綁定了一個示例用Bundle ID,你需要将其修改為你自己的Bundle ID,選擇你的開發團隊,然後将Target欄中Capabilities菜單下的HealthKit的開關由OFF變為ON。

詳見上述“開始”部分和“授權與許可”部分。

恭喜你,你已經用HealthKit完成了一些親子動手做的實驗,你現在已經知道怎麼樣擷取許可,讀取個人特征資訊、讀寫采樣資料了。

如果你想了解更多,請轉向該篇HealthKit系列教程的​​下一部分​​(​​中譯版​​),你将學到一個更複雜類型的資料的更多内容:鍛煉與健身的資訊(workout)。