sensorkit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SensorKit

SensorKit

Collect research-grade sensor data from iOS and watchOS devices for approved research studies. SensorKit provides access to ambient light, motion, device usage, keyboard metrics, visits, phone/messaging usage, speech metrics, face metrics, wrist temperature, heart rate, ECG, and PPG data. Targets Swift 6.3 / iOS 26+.
SensorKit is restricted to Apple-approved research studies. Apps must submit a research proposal to Apple and receive the
com.apple.developer.sensorkit.reader.allow
entitlement before any sensor data is accessible. This is not a general-purpose sensor API -- use CoreMotion for standard accelerometer/gyroscope needs.
为获批的研究项目从iOS和watchOS设备收集研究级传感器数据。SensorKit支持访问环境光照、运动、设备使用、键盘指标、到访地点、电话/信息使用、语音指标、面部指标、腕部温度、心率、ECG和PPG数据。适配Swift 6.3 / iOS 26+。
SensorKit仅可用于苹果获批的研究项目。 应用必须先向苹果提交研究提案,获得
com.apple.developer.sensorkit.reader.allow
entitlement之后才能访问任何传感器数据。这不是通用的传感器API——如果需要使用标准的加速度计/陀螺仪功能,请使用CoreMotion。

Contents

目录

Overview and Requirements

概述与要求

SensorKit enables research apps to record and fetch sensor data across iPhone and Apple Watch. The framework requires:
  1. Apple-approved research study -- submit a proposal at researchandcare.org.
  2. SensorKit entitlement -- Apple grants
    com.apple.developer.sensorkit.reader.allow
    only for approved studies.
  3. Manual provisioning profile -- Xcode requires an explicit App ID with the SensorKit capability enabled.
  4. User authorization -- the system presents a Research Sensor & Usage Data sheet that users approve per-sensor.
  5. 24-hour data hold -- newly recorded data is inaccessible for 24 hours, giving users time to delete data they do not want to share.
An app can access up to 7 days of prior recorded data for an active sensor.
SensorKit支持研究类应用在iPhone和Apple Watch上录制和拉取传感器数据。该框架要求:
  1. 苹果获批的研究项目——在researchandcare.org提交申请。
  2. SensorKit entitlement——苹果仅会为获批的研究项目授予
    com.apple.developer.sensorkit.reader.allow
    权限。
  3. 手动配置描述文件——Xcode需要启用了SensorKit能力的显式App ID。
  4. 用户授权——系统会展示研究传感器与使用数据弹窗,用户需要为每个传感器单独授权。
  5. 24小时数据保留期——新录制的数据在24小时内无法访问,为用户提供时间删除不愿意共享的数据。
对于处于活跃状态的传感器,应用最多可以访问过去7天的录制数据。

Entitlements

Entitlements

Add the SensorKit reader entitlement to a
.entitlements
file. List only the sensors your study uses:
xml
<key>com.apple.developer.sensorkit.reader.allow</key>
<array>
    <string>ambient-light-sensor</string>
    <string>motion-accelerometer</string>
    <string>motion-rotation-rate</string>
    <string>device-usage</string>
    <string>keyboard-metrics</string>
    <string>messages-usage</string>
    <string>phone-usage</string>
    <string>visits</string>
    <string>pedometer</string>
    <string>on-wrist</string>
</array>
Xcode build settings for manual signing:
SettingValue
Code Signing Entitlements
YourApp.entitlements
Code Signing Identity
Apple Developer
Code Signing Style
Manual
Provisioning ProfileExplicit profile with SensorKit capability
将SensorKit读取权限添加到
.entitlements
文件中,仅列出你的研究项目用到的传感器:
xml
<key>com.apple.developer.sensorkit.reader.allow</key>
<array>
    <string>ambient-light-sensor</string>
    <string>motion-accelerometer</string>
    <string>motion-rotation-rate</string>
    <string>device-usage</string>
    <string>keyboard-metrics</string>
    <string>messages-usage</string>
    <string>phone-usage</string>
    <string>visits</string>
    <string>pedometer</string>
    <string>on-wrist</string>
</array>
手动签名的Xcode构建设置:
设置项
Code Signing Entitlements
YourApp.entitlements
Code Signing Identity
Apple Developer
Code Signing Style
Manual
Provisioning Profile具备SensorKit能力的显式描述文件

Info.plist Configuration

Info.plist 配置

Three keys are required:
xml
<!-- Study purpose shown in the authorization sheet -->
<key>NSSensorKitUsageDescription</key>
<string>This study monitors activity patterns for sleep research.</string>

<!-- Link to your study's privacy policy -->
<key>NSSensorKitPrivacyPolicyURL</key>
<string>https://example.com/privacy-policy</string>

<!-- Per-sensor usage explanations -->
<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>
If
Required
is
true
and the user denies that sensor, the system warns them that the study needs it and offers a chance to reconsider.
需要配置三个键:
xml
<!-- 授权弹窗中展示的研究用途说明 -->
<key>NSSensorKitUsageDescription</key>
<string>本研究为睡眠研究监测活动模式。</string>

<!-- 研究项目隐私政策链接 -->
<key>NSSensorKitPrivacyPolicyURL</key>
<string>https://example.com/privacy-policy</string>

<!-- 每个传感器的用途说明 -->
<key>NSSensorKitUsageDetail</key>
<dict>
    <key>SRSensorUsageMotion</key>
    <dict>
        <key>Description</key>
        <string>测量研究期间的身体活动水平。</string>
        <key>Required</key>
        <true/>
    </dict>
    <key>SRSensorUsageAmbientLightSensor</key>
    <dict>
        <key>Description</key>
        <string>记录环境光照以评估睡眠环境。</string>
    </dict>
</dict>
如果
Required
设置为
true
且用户拒绝了该传感器的授权,系统会提醒用户该研究需要此权限,并提供重新考虑的机会。

Authorization

授权

Request authorization for the sensors your study needs. The system shows the Research Sensor & Usage Data sheet on first request.
swift
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)")
    }
}
Check a reader's current status before recording:
swift
switch reader.authorizationStatus {
case .authorized:
    reader.startRecording()
case .denied:
    // User declined -- direct to Settings > Privacy > Research Sensor & Usage Data
    break
case .notDetermined:
    // Request authorization first
    break
@unknown default:
    break
}
Monitor status changes through the delegate:
swift
func sensorReader(_ reader: SRSensorReader, didChange authorizationStatus: SRAuthorizationStatus) {
    switch authorizationStatus {
    case .authorized:
        reader.startRecording()
    case .denied:
        reader.stopRecording()
    default:
        break
    }
}
为你的研究项目所需的传感器申请授权。首次申请时系统会展示研究传感器与使用数据弹窗。
swift
import SensorKit

let reader = SRSensorReader(sensor: .ambientLightSensor)

// 一次性为多个传感器申请授权
SRSensorReader.requestAuthorization(
    sensors: [.ambientLightSensor, .accelerometer, .keyboardMetrics]
) { error in
    if let error {
        print("授权申请失败: \(error)")
    }
}
在开始录制前检查读取器的当前状态:
swift
switch reader.authorizationStatus {
case .authorized:
    reader.startRecording()
case .denied:
    // 用户拒绝授权——引导用户前往设置 > 隐私 > 研究传感器与使用数据
    break
case .notDetermined:
    // 先申请授权
    break
@unknown default:
    break
}
通过代理监听状态变化:
swift
func sensorReader(_ reader: SRSensorReader, didChange authorizationStatus: SRAuthorizationStatus) {
    switch authorizationStatus {
    case .authorized:
        reader.startRecording()
    case .denied:
        reader.stopRecording()
    default:
        break
    }
}

Available Sensors

可用传感器

Device Sensors

设备传感器

SensorTypeSample Type
.deviceUsageReport
Device usage
SRDeviceUsageReport
.keyboardMetrics
Keyboard activity
SRKeyboardMetrics
.onWristState
Watch wrist state
SRWristDetection
传感器类型样本类型
.deviceUsageReport
设备使用
SRDeviceUsageReport
.keyboardMetrics
键盘活动
SRKeyboardMetrics
.onWristState
手表佩戴状态
SRWristDetection

App Activity Sensors

应用活动传感器

SensorTypeSample Type
.messagesUsageReport
Messages app usage
SRMessagesUsageReport
.phoneUsageReport
Phone call usage
SRPhoneUsageReport
传感器类型样本类型
.messagesUsageReport
信息应用使用
SRMessagesUsageReport
.phoneUsageReport
通话使用
SRPhoneUsageReport

User Activity Sensors

用户活动传感器

SensorTypeSample Type
.accelerometer
Acceleration data
CMAccelerometerData
.rotationRate
Rotation rate
CMGyroData
.pedometerData
Step/distance data
CMPedometerData
.visits
Visited locations
SRVisit
.mediaEvents
Media interactions
SRMediaEvent
.faceMetrics
Face expressions
SRFaceMetrics
.heartRate
Heart rateHeart rate data
.odometer
Speed/slopeOdometer data
.siriSpeechMetrics
Siri speech
SRSpeechMetrics
.telephonySpeechMetrics
Phone speech
SRSpeechMetrics
.wristTemperature
Wrist temp (sleep)
SRWristTemperatureSession
.photoplethysmogram
PPG stream
SRPhotoplethysmogramSample
.electrocardiogram
ECG stream
SRElectrocardiogramSample
传感器类型样本类型
.accelerometer
加速度数据
CMAccelerometerData
.rotationRate
旋转速率
CMGyroData
.pedometerData
步数/距离数据
CMPedometerData
.visits
到访地点
SRVisit
.mediaEvents
媒体交互
SRMediaEvent
.faceMetrics
面部表情
SRFaceMetrics
.heartRate
心率心率数据
.odometer
速度/坡度里程计数据
.siriSpeechMetrics
Siri语音
SRSpeechMetrics
.telephonySpeechMetrics
通话语音
SRSpeechMetrics
.wristTemperature
腕部温度(睡眠)
SRWristTemperatureSession
.photoplethysmogram
PPG流
SRPhotoplethysmogramSample
.electrocardiogram
ECG流
SRElectrocardiogramSample

Environment Sensors

环境传感器

SensorTypeSample Type
.ambientLightSensor
Ambient light
SRAmbientLightSample
.ambientPressure
Pressure/tempPressure data
传感器类型样本类型
.ambientLightSensor
环境光照
SRAmbientLightSample
.ambientPressure
气压/温度气压数据

SRSensorReader

SRSensorReader

SRSensorReader
is the central class for accessing sensor data. Each instance reads from a single sensor.
swift
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
The reader communicates entirely through
SRSensorReaderDelegate
:
Delegate MethodPurpose
sensorReader(_:didChange:)
Authorization status changed
sensorReaderWillStartRecording(_:)
Recording is about to start
sensorReader(_:startRecordingFailedWithError:)
Recording failed to start
sensorReaderDidStopRecording(_:)
Recording stopped
sensorReader(_:didFetch:)
Devices fetched
sensorReader(_:fetching:didFetchResult:)
Sample received
sensorReader(_:didCompleteFetch:)
Fetch completed
sensorReader(_:fetching:failedWithError:)
Fetch failed
SRSensorReader
是访问传感器数据的核心类,每个实例仅可读取单个传感器的数据。
swift
import SensorKit

// 为单个传感器创建读取器
let lightReader = SRSensorReader(sensor: .ambientLightSensor)
let keyboardReader = SRSensorReader(sensor: .keyboardMetrics)

// 指派代理接收回调
lightReader.delegate = self
keyboardReader.delegate = self
读取器完全通过
SRSensorReaderDelegate
进行通信:
代理方法用途
sensorReader(_:didChange:)
授权状态发生变化
sensorReaderWillStartRecording(_:)
即将开始录制
sensorReader(_:startRecordingFailedWithError:)
录制启动失败
sensorReaderDidStopRecording(_:)
录制已停止
sensorReader(_:didFetch:)
已拉取到设备列表
sensorReader(_:fetching:didFetchResult:)
收到样本数据
sensorReader(_:didCompleteFetch:)
拉取完成
sensorReader(_:fetching:failedWithError:)
拉取失败

Recording and Fetching Data

数据录制与拉取

Start and Stop Recording

启动与停止录制

swift
// 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()
swift
// 开始录制——只要有任意应用在使用该传感器,它就会保持活跃状态
reader.startRecording()

// 停止录制——当没有任何应用或系统进程使用该传感器时,框架会停用该传感器
reader.stopRecording()

Fetch Data

拉取数据

Build an
SRFetchRequest
with a time range and target device, then pass it to the reader:
swift
let request = SRFetchRequest()
request.device = SRDevice.current
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 2)  // 2 days ago
request.to = SRAbsoluteTime.current()

reader.fetch(request)
Receive results through the delegate:
swift
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)")
}
创建包含时间范围和目标设备的
SRFetchRequest
,然后将其传递给读取器:
swift
let request = SRFetchRequest()
request.device = SRDevice.current
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 2)  // 2天前
request.to = SRAbsoluteTime.current()

reader.fetch(request)
通过代理接收结果:
swift
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("\(reader.sensor)的数据拉取完成")
}

func sensorReader(
    _ reader: SRSensorReader,
    fetching request: SRFetchRequest,
    failedWithError error: any Error
) {
    print("拉取失败: \(error)")
}

Data Holding Period

数据保留期

SensorKit imposes a 24-hour holding period on newly recorded data. Fetch requests whose time range overlaps this period return no results. Design data collection workflows around this delay.
SensorKit对新录制的数据强制执行24小时保留期。时间范围覆盖该时段的拉取请求不会返回任何结果。请围绕该延迟设计数据收集工作流。

SRDevice

SRDevice

SRDevice
identifies the hardware source for sensor samples. Use it to distinguish data from iPhone versus Apple Watch.
swift
// 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()
Handle fetched devices through the delegate:
swift
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
用于标识传感器样本的硬件来源,可用于区分iPhone和Apple Watch的数据。
swift
// 获取当前设备
let currentDevice = SRDevice.current
print("型号: \(currentDevice.model)")
print("系统: \(currentDevice.systemName) \(currentDevice.systemVersion)")

// 拉取某个传感器的所有可用设备
reader.fetchDevices()
通过代理处理拉取到的设备:
swift
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("拉取设备失败: \(error)")
}

SRDevice Properties

SRDevice 属性

PropertyTypeDescription
model
String
User-defined device name
name
String
Framework-defined device name
systemName
String
OS name (iOS, watchOS)
systemVersion
String
OS version
productType
String
Hardware identifier
current
SRDevice
Class property for the running device
属性类型描述
model
String
用户自定义的设备名称
name
String
框架定义的设备名称
systemName
String
操作系统名称(iOS、watchOS)
systemVersion
String
操作系统版本
productType
String
硬件标识符
current
SRDevice
指向当前运行设备的类属性

Common Mistakes

常见错误

DON'T: Attempt to use SensorKit without the entitlement

不要:未获取entitlement就尝试使用SensorKit

swift
// WRONG -- fails at runtime with SRError.invalidEntitlement
let reader = SRSensorReader(sensor: .ambientLightSensor)
reader.startRecording()

// CORRECT -- obtain entitlement from Apple first, configure manual
// provisioning profile, then use SensorKit
swift
// 错误——运行时会抛出SRError.invalidEntitlement错误
let reader = SRSensorReader(sensor: .ambientLightSensor)
reader.startRecording()

// 正确——先从苹果获取entitlement,配置手动描述文件,再使用SensorKit

DON'T: Expect immediate data access

不要:期望可以立即访问数据

swift
// WRONG -- fetching data recorded moments ago returns nothing
reader.startRecording()
// ... record for a few minutes ...
let request = SRFetchRequest()
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 300)
request.to = SRAbsoluteTime.current()
reader.fetch(request)  // Empty results due to 24-hour hold

// CORRECT -- fetch data that is at least 24 hours old
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 3)
request.to = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400)
reader.fetch(request)
swift
// 错误——拉取刚刚录制的数据不会返回任何结果
reader.startRecording()
// ... 录制几分钟 ...
let request = SRFetchRequest()
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 300)
request.to = SRAbsoluteTime.current()
reader.fetch(request)  // 由于24小时保留期,结果为空

// 正确——拉取至少24小时之前的数据
request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 3)
request.to = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400)
reader.fetch(request)

DON'T: Forget to set the delegate before fetching

不要:拉取前忘记设置代理

swift
// WRONG -- no delegate means no callbacks, results are silently lost
let reader = SRSensorReader(sensor: .accelerometer)
reader.startRecording()
reader.fetch(request)

// CORRECT -- assign delegate first
reader.delegate = self
reader.startRecording()
reader.fetch(request)
swift
// 错误——没有代理就没有回调,结果会被静默丢失
let reader = SRSensorReader(sensor: .accelerometer)
reader.startRecording()
reader.fetch(request)

// 正确——先指派代理
reader.delegate = self
reader.startRecording()
reader.fetch(request)

DON'T: Skip per-sensor Info.plist usage detail

不要:缺少Info.plist中每个传感器的用途说明

swift
// WRONG -- missing NSSensorKitUsageDetail for the sensor
// Authorization sheet shows no explanation, user is less likely to approve

// CORRECT -- add usage detail for every sensor you request
// See Info.plist Configuration section above
swift
// 错误——传感器缺少对应的NSSensorKitUsageDetail配置
// 授权弹窗不会展示用途说明,用户授权的可能性更低

// 正确——为你申请的每个传感器都添加用途说明
// 参考上文Info.plist配置章节

DON'T: Ignore SRError codes

不要:忽略SRError错误码

swift
// WRONG -- generic error handling
func sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {
    print("Error")
}

// CORRECT -- handle specific error codes
func sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {
    if let srError = error as? SRError {
        switch srError.code {
        case .invalidEntitlement:
            // Entitlement missing or sensor not in entitlement array
            break
        case .noAuthorization:
            // User has not authorized this sensor
            break
        case .dataInaccessible:
            // Data in 24-hour holding period or otherwise unavailable
            break
        case .fetchRequestInvalid:
            // Invalid time range or device
            break
        case .promptDeclined:
            // User declined the authorization prompt
            break
        @unknown default:
            break
        }
    }
}
swift
// 错误——通用错误处理
func sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {
    print("错误")
}

// 正确——处理特定的错误码
func sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {
    if let srError = error as? SRError {
        switch srError.code {
        case .invalidEntitlement:
            // 缺少entitlement或者传感器不在entitlement数组中
            break
        case .noAuthorization:
            // 用户尚未授权该传感器
            break
        case .dataInaccessible:
            // 数据处于24小时保留期或其他原因不可用
            break
        case .fetchRequestInvalid:
            // 时间范围或设备无效
            break
        case .promptDeclined:
            // 用户拒绝了授权弹窗
            break
        @unknown default:
            break
        }
    }
}

Review Checklist

审核检查清单

  • Apple-approved research study in place before development
  • com.apple.developer.sensorkit.reader.allow
    entitlement lists only needed sensors
  • Manual provisioning profile with explicit App ID and SensorKit capability
  • NSSensorKitUsageDescription
    in Info.plist with clear study purpose
  • NSSensorKitPrivacyPolicyURL
    in Info.plist with valid privacy policy URL
  • NSSensorKitUsageDetail
    entries for every requested sensor
  • Required
    key set appropriately for essential vs. optional sensors
  • Authorization requested before recording, status checked before fetching
  • Delegate assigned before calling
    startRecording()
    or
    fetch(_:)
  • Fetch request time ranges account for 24-hour data holding period
  • SRError
    codes handled in all failure delegate methods
  • fetchDevices()
    used to discover available devices before fetching
  • stopRecording()
    called when data collection is complete
  • sensorReader(_:fetching:didFetchResult:)
    returns
    true
    to continue or
    false
    to stop
  • 开发前已获得苹果批准的研究项目
  • com.apple.developer.sensorkit.reader.allow
    entitlement仅列出所需的传感器
  • 已配置带有显式App ID和SensorKit能力的手动描述文件
  • Info.plist中已添加
    NSSensorKitUsageDescription
    ,清晰说明研究用途
  • Info.plist中已添加
    NSSensorKitPrivacyPolicyURL
    ,指向有效的隐私政策链接
  • 为每个申请的传感器都配置了
    NSSensorKitUsageDetail
    条目
  • 已为必要和可选传感器正确设置
    Required
  • 录制前已申请授权,拉取前已检查授权状态
  • 调用
    startRecording()
    fetch(_:)
    之前已指派代理
  • 拉取请求的时间范围已考虑24小时数据保留期
  • 所有失败代理方法中都已处理
    SRError
    错误码
  • 拉取数据前已使用
    fetchDevices()
    发现可用设备
  • 数据收集完成后已调用
    stopRecording()
  • sensorReader(_:fetching:didFetchResult:)
    返回
    true
    继续接收结果或
    false
    停止接收

References

参考资料