使用 SensorKit 為獲得核准的研究計畫擷取研究級感測器資料。適用於應用程式需要設定 SensorKit entitlement、取得「研究感測器與使用資料」授權,或存取環境光、運動紀錄、裝置使用狀況、鍵盤計量、造訪地點、語音、臉部、手腕溫度、心電圖 (ECG)、光血流波 (PPG)、聲學設定或睡眠期間資料等情境。一般的運動與活動資料請導向 CoreMotion,健康紀錄與體能訓練資料則導向 HealthKit。
SensorKit
請選擇確切的 SRSensor 並確認其個別可用性。一般運動/活動功能請使用 CoreMotion,健康紀錄與體能訓練請使用 HealthKit。
目錄
概述與需求
SensorKit 能讓研究類應用程式在 iPhone 與 Apple Watch 上記錄並擷取感測器資料。此框架有以下需求:
- 經 Apple 核准的研究計畫 -- 請至 researchandcare.org 提交計畫申請。
- SensorKit entitlement -- Apple 僅會為已核准的研究計畫簽發
com.apple.developer.sensorkit.reader.allow。 - 手動佈署描述檔 (Manual provisioning profile) -- Xcode 需要啟用 SensorKit 功能的明確 App ID。
- 使用者授權 -- 系統會顯示「研究感測器與使用資料」授權頁面,供使用者按感測器逐一批准。
- 延遲擷取 -- 請圍繞規範的資料保存期來設計資料擷取時機。
應用程式最多可存取使用中感測器過去 7 天內錄製的資料。
Entitlements
將 SensorKit reader entitlement 新增至 .entitlements 檔案中。請僅列出 Apple 已為該研究計畫核准的感測器。常見的 entitlement 值包括:
<key>com.apple.developer.sensorkit.reader.allow</key>
<array>
<string>ambient-light-sensor</string>
<string>motion-accelerometer</string>
<string>device-usage</string>
<string>keyboard-metrics</string>
</array>
在為每個核准的感測器選擇確切的 entitlement 字串和 NSSensorKitUsageDetail 鍵值時,請載入Entitlement 與 Usage-Detail 目錄。請對照個別 SRSensor 頁面重新核對特殊感測器。
進行手動簽署時,請將 Code Signing Entitlements 設定為該 entitlements 檔案、Code Signing Identity 設定為 Apple Developer、Code Signing Style 設定為 Manual,並將 Provisioning Profile 設定為包含 SensorKit 能力的明確描述檔。
Info.plist 設定
需要設定以下三個鍵值:
<!-- 顯示於授權頁面的研究目的描述 -->
<key>NSSensorKitUsageDescription</key>
<string>This study monitors activity patterns for sleep research.</string>
<!-- 連結至研究計畫的隱私權政策 -->
<key>NSSensorKitPrivacyPolicyURL</key>
<string>https://example.com/privacy-policy</string>
<!-- 個別感測器的使用細節說明 -->
<key>NSSensorKitUsageDetail</key>
<dict>
<key>SRSensorUsageMotion</key>
<dict>
<key>Description</key>
<string>Measures physical activity levels during the study.</string>
<key>Required</key>
<true/>
</dict>
<key>SRSensorUsageAmbientLightSensor</key>
<dict>
<key>Description</key>
<string>Records ambient light to assess sleep environment.</string>
</dict>
</dict>
若 Required 為 true 且使用者拒絕授權該感測器,系統會提醒使用者該研究需要此感測器,並提供重新考慮的機會。
請為每個請求的感測器使用確切的 usage-detail 字典。如需對映上述運動和環境光範例以外的感測器,請載入 Entitlement 與 Usage-Detail 目錄。
授權
請針對您的研究計畫所需的感測器請求授權。系統會在首次請求時顯示「研究感測器與使用資料」授權頁面。
import SensorKit
let reader = SRSensorReader(sensor: .ambientLightSensor)
// 一次請求多個感測器的授權
SRSensorReader.requestAuthorization(
sensors: [.ambientLightSensor, .accelerometer, .keyboardMetrics]
) { error in
if let error {
print("Authorization request failed: \(error)")
}
}
初次檢查與 Delegate 狀態變更時請使用同一個狀態處理函式:
private func applyAuthorizationStatus(
_ status: SRAuthorizationStatus,
to reader: SRSensorReader
) {
switch status {
case .authorized:
reader.startRecording()
case .denied:
reader.stopRecording()
// 引導使用者至「設定」>「隱私權與安全性」>「研究感測器與使用資料」。
case .notDetermined:
break // 先請求授權。
@unknown default:
break
}
}
applyAuthorizationStatus(reader.authorizationStatus, to: reader)
func sensorReader(_ reader: SRSensorReader, didChange authorizationStatus: SRAuthorizationStatus) {
applyAuthorizationStatus(authorizationStatus, to: reader)
}
可用感測器
請載入感測器目錄,將各個 SRSensor 對映至其對應的樣本型別。請僅請求研究計畫已獲核准的感測器,並再次確認所選感測器的可用性及 usage-detail 鍵值。
SRSensorReader
SRSensorReader 是存取感測器資料的核心類別。每個實例均負責讀取單一感測器的資料。
import SensorKit
// 為單一感測器建立 reader
let lightReader = SRSensorReader(sensor: .ambientLightSensor)
let keyboardReader = SRSensorReader(sensor: .keyboardMetrics)
// 指派 delegate 以接收回呼
lightReader.delegate = self
keyboardReader.delegate = self
Reader 透過 SRSensorReaderDelegate 進行通訊。在接線完整的授權、錄製、裝置擷取與樣本擷取生命週期時,請載入Delegate 方法目錄。
錄製與擷取資料
開始與停止錄製
// 開始錄製 -- 只要有任何應用程式使用,感測器就會保持作用狀態
reader.startRecording()
// 停止錄製 -- 當沒有任何應用程式或系統程序使用時,框架即會停用感測器
reader.stopRecording()
擷取資料
建立包含時間範圍與目標裝置的 SRFetchRequest,然後傳遞給 reader:
let request = SRFetchRequest()
request.device = SRDevice.current
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 2) // 2 天前
request.to = SRAbsoluteTime.current()
reader.fetch(request)
透過 delegate 接收結果:
func sensorReader(
_ reader: SRSensorReader,
fetching request: SRFetchRequest,
didFetchResult result: SRFetchResult<AnyObject>
) -> Bool {
let timestamp = result.timestamp
switch reader.sensor {
case .ambientLightSensor:
if let sample = result.sample as? SRAmbientLightSample {
let lux = sample.lux
let chromaticity = sample.chromaticity
let placement = sample.placement
processSample(lux: lux, chromaticity: chromaticity, at: timestamp)
}
case .keyboardMetrics:
if let sample = result.sample as? SRKeyboardMetrics {
let words = sample.totalWords
let speed = sample.typingSpeed
processKeyboard(words: words, speed: speed, at: timestamp)
}
case .deviceUsageReport:
if let sample = result.sample as? SRDeviceUsageReport {
let wakes = sample.totalScreenWakes
let unlocks = sample.totalUnlocks
processUsage(wakes: wakes, unlocks: unlocks, at: timestamp)
}
default:
break
}
return true // 回傳 true 以繼續接收結果
}
func sensorReader(_ reader: SRSensorReader, didCompleteFetch request: SRFetchRequest) {
print("Fetch complete for \(reader.sensor)")
}
func sensorReader(
_ reader: SRSensorReader,
fetching request: SRFetchRequest,
failedWithError error: any Error
) {
print("Fetch failed: \(error)")
}
將 result.sample 轉型為該 reader 感測器對應的樣本結構。某些串流每個結果回傳單一物件,而錄製的運動、ECG、PPG 和環境氣壓串流則可能回傳錄製樣本的陣列。
資料保存期
SensorKit 對新錄製的資料設有 24 小時的保存期。若擷取請求的時間範圍重疊此保存期,將不會回傳任何結果。請圍繞此延遲機制來設計資料收集工作流程。
SRDevice
SRDevice 用於識別感測器樣本的硬體來源。可用來區分來自 iPhone 或 Apple Watch 的資料。
// 取得當前裝置
let currentDevice = SRDevice.current
print("Model: \(currentDevice.model)")
print("System: \(currentDevice.systemName) \(currentDevice.systemVersion)")
// 擷取感測器所有可用的裝置
reader.fetchDevices()
透過 delegate 處理擷取到的裝置:
func sensorReader(_ reader: SRSensorReader, didFetch devices: [SRDevice]) {
for device in devices {
let request = SRFetchRequest()
request.device = device
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400)
request.to = SRAbsoluteTime.current()
reader.fetch(request)
}
}
func sensorReader(_ reader: SRSensorReader, fetchDevicesDidFailWithError error: any Error) {
print("Failed to fetch devices: \(error)")
}
SRDevice 屬性
| 屬性 | 型別 | 說明 |
|---|---|---|
model |
String |
使用者自訂的裝置名稱 |
name |
String |
框架定義的裝置名稱 |
systemName |
String |
作業系統名稱 (iOS, watchOS) |
systemVersion |
String |
作業系統版本 |
productType |
String |
硬體識別碼 |
current |
SRDevice |
執行中裝置的類別屬性 |
常見錯誤
切勿:在未設定 entitlement 的情況下嘗試使用 SensorKit
在建構正式環境的 reader 之前,請先取得 Apple 的研究計畫核准、感測器特定的 entitlement 值以及對應的手動佈署描述檔。
切勿:預期能立即存取資料
請遵循資料保存期;擷取時間涵蓋保存期並不代表錄製失敗。
切勿:在擷取前忘記設定 Delegate
請在呼叫 startRecording() 或 fetch(_:) 前指派 delegate;結果與失敗訊息均透過 delegate 回呼接收。
切勿:遺漏各感測器在 Info.plist 的使用細節
請為每個請求的感測器新增確切的 Info.plist 設定 usage-detail 項目。
切勿:忽略 SRError 錯誤碼
請至少區分 .invalidEntitlement、.noAuthorization、.dataInaccessible、.fetchRequestInvalid、.promptDeclined 以及未來未知的錯誤碼。完整 switch 與回呼接線請載入 完整 Delegate 實作。
審查檢核表
- [ ] 開發前已取得 Apple 核准的研究計畫
- [ ]
com.apple.developer.sensorkit.reader.allowentitlement 僅列出需要的感測器 - [ ] 具有明確 App ID 和 SensorKit 功能的手動佈署描述檔
- [ ] Info.plist 中含有清楚研究目的的
NSSensorKitUsageDescription - [ ] Info.plist 中含有有效隱私權政策 URL 的
NSSensorKitPrivacyPolicyURL - [ ] 為每個請求的感測器提供
NSSensorKitUsageDetail條目 - [ ] 為核心與選用感測器適當設定
Required鍵值 - [ ] 錄製前已請求授權,擷取前已確認狀態
- [ ] 呼叫
startRecording()或fetch(_:)前已指派 Delegate - [ ] 擷取請求的時間範圍已考慮 24 小時保存期
<!-- truncated for translation batch; full body continues in source -->






