sensorkit について
sensorkitは、SensorKitを使うAppleの研究アプリ開発者向けガイドです。センサーごとの承認と設定、記録、遅延を伴うデータ取得を扱います。
主な機能
- 01研究承認とセンサーアクセスの設定
- 02SRSensorReaderによるデータ記録
- 03期間とデバイスを指定したデータ取得
- 04デバイス情報とデリゲートコールバックの処理
- 05データ保持期間への対応
活用シーン
- 01承認済み研究でのセンサー読み取り設定
- 02iPhoneまたはApple Watchからのサンプル収集
- 03取得遅延を考慮したデータ収集の設計
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill sensorkitインストール後、Claude Code で/sensorkitを入力して読み込まれたか確認します。
同梱ファイルevals/evals.jsonreferences/sensorkit-patterns.md
詳細
SensorKit
正確な SRSensor を選択し、個別に利用可能か確認してください。一般的なモーション/アクティビティ機能には
CoreMotion を、健康記録やワークアウトには HealthKit を使用します。
Contents
- 概要と要件
- エンタイトルメント
- Info.plist の設定
- 認証
- 利用可能なセンサー
- SRSensorReader
- データの記録と取得
- SRDevice
- よくある間違い
- レビュー用チェックリスト
- 参考資料
概要と要件
SensorKit を使うと、研究用アプリで iPhone と Apple Watch のセンサーデータを記録、取得できます。このフレームワークには、次の要件があります。
- Apple が承認した研究調査 -- researchandcare.org から提案を提出します。
- SensorKit エンタイトルメント -- Apple は、承認された研究調査に限り
com.apple.developer.sensorkit.reader.allowを付与します。 - 手動プロビジョニングプロファイル -- Xcode では、SensorKit 機能を有効にした明示的な App ID が必要です。
- ユーザー認証 -- システムが「研究用センサーと使用データ」シートを表示し、ユーザーはセンサーごとに承認します。
- 遅延取得 -- 正式なデータ保持期間を考慮して、取得のタイミングを設計します。
アプリは、アクティブなセンサーについて、過去に記録されたデータを最大 7 日分取得できます。
エンタイトルメント
.entitlements ファイルに SensorKit リーダーのエンタイトルメントを追加します。Apple が研究調査用に承認したセンサーのみを記載してください。一般的なエンタイトルメント値は次のとおりです。
<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>
承認された各センサーの正確なエンタイトルメント文字列と NSSensorKitUsageDetail キーを選ぶ際は、エンタイトルメントと使用詳細のカタログを確認してください。特殊なセンサーについては、個別の SRSensor ページで再確認してください。
手動署名では、Code Signing Entitlements をエンタイトルメントファイルに、Code Signing Identity を Apple Developer に、Code Signing Style を Manual に設定します。また、SensorKit 機能を持つ明示的なプロファイルをプロビジョニングプロファイルに設定してください。
Info.plist の設定
次の 3 つのキーが必要です。
<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 で、ユーザーがそのセンサーへのアクセスを拒否した場合、システムは研究調査にそのセンサーが必要であることをユーザーに警告し、考え直す機会を提示します。
要求するセンサーごとに、正確な使用詳細の辞書を使用してください。上記のモーションと環境光の例以外のセンサーを対応付ける際は、エンタイトルメントと使用詳細のカタログを確認してください。
認証
研究調査に必要なセンサーの認証をリクエストします。初回のリクエスト時に、システムが「研究用センサーと使用データ」シートを表示します。
import SensorKit
let reader = SRSensorReader(sensor: .ambientLightSensor)
// Request authorization for multiple sensors at once
SRSensorReader.requestAuthorization(
sensors: [.ambientLightSensor, .accelerometer, .keyboardMetrics]
) { error in
if let error {
print("Authorization request failed: \(error)")
}
}
初回の確認とデリゲートの変更には、同じステータスハンドラーを使用します。
private func applyAuthorizationStatus(
_ status: SRAuthorizationStatus,
to reader: SRSensorReader
) {
switch status {
case .authorized:
reader.startRecording()
case .denied:
reader.stopRecording()
// Direct the user to Settings > Privacy > Research Sensor & Usage Data.
case .notDetermined:
break // Request authorization first.
@unknown default:
break
}
}
applyAuthorizationStatus(reader.authorizationStatus, to: reader)
func sensorReader(_ reader: SRSensorReader, didChange authorizationStatus: SRAuthorizationStatus) {
applyAuthorizationStatus(authorizationStatus, to: reader)
}
利用可能なセンサー
各 SRSensor とそのサンプル型を対応付けるには、センサーカタログを確認してください。研究調査で承認されたセンサーのみをリクエストし、選択したセンサーが利用可能か、使用詳細キーが正しいかを再確認してください。
SRSensorReader
SRSensorReader は、センサーデータにアクセスするための中心的なクラスです。各インスタンスは 1 つのセンサーから読み取ります。
import SensorKit
// Create a reader for one sensor
let lightReader = SRSensorReader(sensor: .ambientLightSensor)
let keyboardReader = SRSensorReader(sensor: .keyboardMetrics)
// Assign delegate to receive callbacks
lightReader.delegate = self
keyboardReader.delegate = self
リーダーは SRSensorReaderDelegate を介して通信します。認証、記録、デバイス取得、サンプル取得のライフサイクル全体を実装する際は、デリゲートメソッドカタログを確認してください。
データの記録と取得
記録の開始と停止
// Begin recording -- sensor stays active as long as any app has a stake
reader.startRecording()
// Stop recording -- framework deactivates the sensor when
// no app or system process is using it
reader.stopRecording()
データの取得
時間範囲と対象デバイスを指定して SRFetchRequest を作成し、リーダーに渡します。
let request = SRFetchRequest()
request.device = SRDevice.current
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 2) // 2 days ago
request.to = SRAbsoluteTime.current()
reader.fetch(request)
結果はデリゲートを介して受け取ります。
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 // Return true to continue receiving results
}
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 を、リーダーのセンサーに対応するサンプル型にキャストします。ストリームによっては結果ごとにオブジェクトが 1 つ返されますが、記録されたモーション、ECG、PPG、環境圧力のストリームでは、記録済みサンプルの配列が返されることがあります。
データ保持期間
SensorKit は新しく記録されたデータに 24 時間の保持期間 を課します。この期間と重なる時間範囲のフェッチリクエストは結果を返しません。この遅延を考慮してデータ収集ワークフローを設計してください。
SRDevice
SRDevice はセンサーサンプルのハードウェアソースを識別します。これを使用して、iPhone からのデータと Apple Watch からのデータを区別します。
// Get the current device
let currentDevice = SRDevice.current
print("Model: \(currentDevice.model)")
print("System: \(currentDevice.systemName) \(currentDevice.systemVersion)")
// Fetch all available devices for a sensor
reader.fetchDevices()
フェッチしたデバイスはデリゲートを通じて処理します:
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 | OS 名 (iOS、watchOS) |
systemVersion | String | OS バージョン |
productType | String | ハードウェア識別子 |
current | SRDevice | 実行中のデバイス用のクラスプロパティ |
よくある間違い
やってはいけない: エンタイトルメントなしで SensorKit を使用しようとする
本番用のリーダーを構築する前に、Apple の研究承認、センサー固有のエンタイトルメント値、および対応する手動プロビジョニングプロファイルを取得してください。
やってはいけない: データにすぐアクセスできると期待する
データ保持期間を適用してください。保持期間と重なるフェッチは、記録が失敗した証拠にはなりません。
やってはいけない: フェッチ前にデリゲートの設定を忘れる
startRecording() または fetch(_:) の前にデリゲートを割り当ててください。結果と失敗はデリゲートコールバックを通じて届きます。
やってはいけない: センサーごとの Info.plist 使用目的の詳細を省略する
リクエストするすべてのセンサーに対して、正確な Info.plist 構成の使用目的の詳細エントリを追加してください。
やってはいけない: SRError コードを無視する
少なくとも .invalidEntitlement、.noAuthorization、.dataInaccessible、.fetchRequestInvalid、.promptDeclined、および未知の将来のコードを区別してください。完全な switch とコールバックの配線については、完全なデリゲート実装を参照してください。
レビューチェックリスト
- 開発前に Apple 承認の研究調査が整っている
-
com.apple.developer.sensorkit.reader.allowエンタイトルメントに必要なセンサーのみが列挙されている - 明示的な App ID と SensorKit 機能を備えた手動プロビジョニングプロファイル
- Info.plist に明確な研究目的を記載した
NSSensorKitUsageDescription - Info.plist に有効なプライバシーポリシー URL を記載した
NSSensorKitPrivacyPolicyURL - リクエストするすべてのセンサーに対する
NSSensorKitUsageDetailエントリ - 必須センサーとオプションセンサーに対して
Requiredキーが適切に設定されている - 記録前に認証をリクエストし、フェッチ前にステータスを確認している
-
startRecording()またはfetch(_:)を呼び出す前にデリゲートが割り当てられている - フェッチリクエストの時間範囲が 24 時間のデータ保持期間を考慮している
- すべての失敗デリゲートメソッドで
SRErrorコードが処理されている - フェッチ前に利用可能なデバイスを検出するために
fetchDevices()が使用されている - データ収集が完了したときに
stopRecording()が呼び出されている -
sensorReader(_:fetching:didFetchResult:)が継続する場合はtrueを、停止する場合はfalseを返す
参照
- 拡張パターン (デリゲートの配線、マルチセンサーマネージャー、サンプルタイプの詳細): references/sensorkit-patterns.md
- SensorKit フレームワーク
- SRSensorReader
- SRSensor
- SRDevice
- SRFetchRequest
- センサー読み取り用のプロジェクト構成
- com.apple.developer.sensorkit.reader.allow