[譯]在HealthKit中用 Swift 進行睡眠分析

HenryCheng發表於2019-01-22

如今,睡眠革命逐漸成為一種時尚,跟之前相比,人們不僅好奇他們睡了多長時間,而且還通過分析一段時間內收集的資料來了解自己的睡眠趨勢。包括硬體在內的技術的進步,特別是手機移動通訊的日益發展似乎帶來了新的曙光。

HealthKit

蘋果提供了一種安全、炫酷的方式來顯示使用者的個人健康資訊,並將這些資訊保安的儲存在 Health 這個內建的應用中。你不僅可以使用 HealthKit 來 建立一個健身應用 ,該框架還允許你訪問睡眠的詳細資料。這本次教程中,我將會給大家簡要的介紹 HealthKit 這個框架,並演示如何建立一個簡單的睡眠分析的應用。

**簡介 **


HealthKit 框架提供了一個名為 HealthKit store 的結構用來儲存加密的資料。你可以使用HKHealthStore這個類來訪問這個資料庫。iPhone 和 Apple Watch 都有自己的 HealthKit 商店,他們之間的健康資料是同步的,然而,在 Apple Watch 上老的資料會被定期的清除以節省空間。並且 ,HealthKit 框架和 Health 應用在 iPad 上還無法使用。

如果你想基於健康資料建立一個 iOS 或者 watchOS 應用,HealthKit 是一個非常強大的工具。它被設計的目的就是管理廣泛地資料來源,並且根據使用者的偏好自動地合併不同來源的資料。應用程式還可以訪問每一條原始資料,並且合併他們。這些資料不僅僅為身體測量,健身或者營養,還可以用於睡眠分析。
在本文的其餘部分,我將會向你展示在 iOS 上如何利用 HealthKit 框架儲存和訪問睡眠資料。這種方法也同樣適合 watchOS 上的應用。請注意本次教程使用的是 Swift 2.0 和 Xcode 7。因此,請確保你跟隨此教程的時候使用的是 Xcode 7(或者以上)。

在此之前,下載最開始的工程 並解壓。我已經為你建立了基本功能的使用者介面。當你執行這個工程的時候,你將會看到一個定時器的 UI ,當你按下開始按鈕以後就會顯示計時。
###** 使用 HealthKit**


我們使用這個應用的目的是使用開始和停止按鈕來儲存睡眠分析資訊和復取資料。要使用 HealthKit,你必須給你的應用授權。也就是在你的應用中,按著 target -> capabilities -> 開啟HealthKit開關 這個步驟

HealthKit-allow

接下來,你需要用下面的程式碼在 ViewController 類中建立一個 HKHealthStore 的例項:

  let healthStore = HKHealthStore()

複製程式碼

隨後我們將使用 HKHealthStore 這個例項來訪問 HealthKit 商店。

如之前所說, HealthKit 授予使用者許可權來訪問他們的健康資料。所以你在獲得使用者的睡眠分析資料許可權(讀/寫)之前,你必須現請求使用者的許可。要做到這一點,首先要匯入內建的 HealthKit 框架,然後更新 viewDidLoad 裡面的方法,如下:

override func viewDidLoad() {
    super.viewDidLoad()
    
    let typestoRead = Set([
        HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
        ])
    
    let typestoShare = Set([
        HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis)!
        ])
    
    self.healthStore.requestAuthorizationToShareTypes(typestoShare, readTypes: typestoRead) { (success, error) -> Void in
        if success == false {
            NSLog(" Display not allowed")
        }
    }
}
複製程式碼

這段程式碼將提示使用者允許或拒絕請求的訪問的許可權。在閉包中,你可以對成功或者失敗進行處理,並得到最終結果。使用者沒有必要授予你的應用所有你請求的許可權。所以在你的應用中你必須妥善的處理這些錯誤。

但是出於測試的目的,你必須選擇“允許”選項來授權你的應用能訪問你裝置上的健康資料。

Health-App-Permission

###寫入睡眠分析資料


首先,我們如何復取睡眠分析資料呢?根據蘋果文件,每個睡眠分析樣品只能有一個值。為了區分使用者是在床上還是睡著了,HealthKit 用了兩個或者兩個以上的重疊時間的樣本。通過比較這些樣品的開始和結束時間,應用就可以計算出一些次要的統計資料:

  • 使用者進入睡眠所花費的時間
  • 使用者在床上的時間和實際睡眠時間的百分比
  • 使用者在床上醒來的次數
  • 使用者在床上和睡著的時間的總和
record_sleep_data

簡單地說,你按照下面的方法來儲存你的睡眠分析資料到 HealthKit 商店:

  • 1、我們需要定義兩個 NSDate 的物件用於開始時間和結束時間。
  • 2、用 HKCategoryTypeIdentifierSleepAnalysis 建立一個 HKObjectType的例項。
  • 3、我們需要建立一個新的HKCategorySample型別的物件,你通常使用一類的樣本來記錄睡眠時間,單個的樣本代表使用者在床上或者在睡覺的時間段。因此,我們將會建立一個在床上和一個睡著了的重疊時間樣本。
  • 4、最後,我們用 HKHealthStoresaveObject 方法來儲存上述例項。

如果你想用 Swift 實現上述所有,這裡有儲存在床上和睡眠中睡眠分析資料的程式碼片段。請把這些程式碼插入在ViewController類中:

func saveSleepAnalysis() {
    
    // alarmTime and endTime are NSDate objects
    if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
        
        // we create our new object we want to push in Health app
        let object = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.InBed.rawValue, startDate: self.alarmTime, endDate: self.endTime)
        
        // at the end, we save it
        healthStore.saveObject(object, withCompletion: { (success, error) -> Void in
            
            if error != nil {
                // something happened
                return
            }
            
            if success {
                print("My new data was saved in HealthKit")
                
            } else {
                // something happened again
            }
            
        })
        
        
        let object2 = HKCategorySample(type:sleepType, value: HKCategoryValueSleepAnalysis.Asleep.rawValue, startDate: self.alarmTime, endDate: self.endTime)
        
        healthStore.saveObject(object2, withCompletion: { (success, error) -> Void in
            if error != nil {
                // something happened
                return
            }
            
            if success {
                print("My new data (2) was saved in HealthKit")
            } else {
                // something happened again
            }
            
        })
        
    }
    
}
複製程式碼

當我們想把睡眠分析資料儲存到 HealthKit 的時候上述方法將會被呼叫。

###** 讀取睡眠分析資料**


要讀取睡眠分析資料,我們需要建立一個query。首先你需要用 HKCategoryTypeIdentifierSleepAnalysis 定義一個 HKObjectType型別的例項,你可能還需要一個謂詞來篩選你用開始時間和結束時間復取的資料,也就是你想要檢索的時間範圍內的 NSDate  型別的物件。你還需要建立一個 sortDescriptor 排序的檢索詞來篩選出你想要的結果。

你的檢索睡眠分析資料的程式碼應改像下面這樣:

func retrieveSleepAnalysis() {
    
    // first, we define the object type we want
    if let sleepType = HKObjectType.categoryTypeForIdentifier(HKCategoryTypeIdentifierSleepAnalysis) {
        
        // Use a sortDescriptor to get the recent data first
        let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
        
        // we create our query with a block completion to execute
        let query = HKSampleQuery(sampleType: sleepType, predicate: nil, limit: 30, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
            
            if error != nil {
                
                // something happened
                return
                
            }
            
            if let result = tmpResult {
                
                // do something with my data
                for item in result {
                    if let sample = item as? HKCategorySample {
                        let value = (sample.value == HKCategoryValueSleepAnalysis.InBed.rawValue) ? "InBed" : "Asleep"
                        print("Healthkit sleep: (sample.startDate) (sample.endDate) - value: (value)")
                    }
                }
            }
        }
        
        // finally, we execute our query
        healthStore.executeQuery(query)
    }
}
複製程式碼

這段程式碼查詢了在 HealthKit 上的所有睡眠分析資料並按降序排列。然後每天結果上都帶著是在床上的開始結束時間或者在睡覺的開始結束時間被列印出來。我已經設定了上限30用來檢索最後記錄的30哥樣本。你也可以用謂詞的方法來選擇你的自定義開始時間和結束時間。
###應用測試


對於這個 demo,我已經使用 NSTimer 來顯示你按下按鈕之後經過的時間。當開始和結束按鈕按下的時候將會建立 NSDate 的物件來儲存所經過的時間作為睡眠分析資料。在停止的方法中,你可以呼叫 saveSleepAnalysis()retrieveSleepAnalysis方法來儲存和獲得睡眠資料。

@IBAction func stop(sender: AnyObject) {
    endTime = NSDate()
    saveSleepAnalysis()
    retrieveSleepAnalysis()
    timer.invalidate()
}
複製程式碼

在你的應用程式中,你也許想要改變 NSDate 物件來選擇相關的開始和結束時間(可能不同)來儲存在床上和睡眠的的值。

一旦你做了這些改變,你可以執行這個 demo 然後開始計時。讓它執行幾分鐘,然後點選停止按鈕。然後,開啟 Health 這個應用,你就可以找到你的睡眠資料。

sleep-analysis-test

###一些關於 HealthKit 應用的建議


HealthKit 旨在提供一個公共平臺,使應用程式開發人員能夠很容易地共享和訪問使用者的資料,並避免任何可能的重複或不一致的資料。蘋果稽核指南對使用 HealthKit 有很明確的要求,如果對使用者的讀/寫許可權請求沒有明確的描述就很可能導致應用程式被拒絕。
應用如果儲存偽造或者錯誤的資料到健康應用的話也將被拒絕。這就意味著,你不能像在本次教程中睡眠分析這樣天真的以你的演算法計算不同的健康值。你應該嘗試使用內建的感測器資料讀取和操作一些引數,以避免計算錯誤。
關於完整的 Xcode 專案,你可以在 這裡 看到。

原文出處:sing Sleep Analysis in HealthKit with Swift

相關文章