图像与设计
在 Apple 平台读取 Core Motion…
适用于 iOS/watchOS 等 Apple 平台应用需要读取设备运动、步数、活动、高度、耳机运动、批量训练或水下传感器数据的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Apple 平台读取 Core Mo特定
解决思路
- 在 Info.plist 中加入 NSMotionUsageDescription,并提供面向用户的说明,解释应用为何需要运动数据;缺少该键会在首次访问时崩溃。
- 对提供 authorizationStatus() 或 authorizationStatus 属性的管理器(CMPedometer、CMMotionActivityManager、CMAltimeter、耳机运动、批量传感器、水下浸没)先检查授权状态。
- 对原始 CMMotionManager 的加速度计/陀螺仪/设备运动流,虽然没有显式授权请求 API,但仍需提供用途字符串,并在 start/update 回调中处理错误。
- 处理授权分支:notDetermined 将在首次使用时提示;authorized 可继续;restricted/denied 引导用户去 Settings;用 @unknown default 处理未知状态。
- 整个应用只创建一个 CMMotionManager 实例并共享;多个实例会降低传感器更新率。
- 启动加速度计前用 isAccelerometerAvailable 检查可用性。
- 为加速度计设置 accelerometerUpdateInterval,例如 1.0 / 60.0,然后用 startAccelerometerUpdates(to: .main) 获取 data.acceleration 的 x/y/z,完成后调用 stopAccelerometerUpdates()。
- 启动陀螺仪前用 isGyroAvailable 检查可用性。
- 为陀螺仪设置 gyroUpdateInterval,例如 1.0 / 60.0,然后用 startGyroUpdates(to: .main) 获取 data.rotationRate 的 x/y/z,完成后调用 stopGyroUpdates()。
- 游戏可用轮询模式:调用 startAccelerometerUpdates() 不传 handler,在游戏循环/display link 中读取 motionManager.accelerometerData,并用 data.acceleration.x 做倾斜控制;完成后停止更新。
- 使用 CMDeviceMotion 获取融合后的设备运动:attitude、去重力后的 userAcceleration、gravity、rotationRate、校准磁场;启动前用 isDeviceMotionAvailable 检查可用性。
- 不要硬编码 corrected、magnetic-north 或 true-north attitude frame;在代码中运行时检查 CMMotionManager.availableAttitudeReferenceFrames(),优先帧不可用时回退到 .xArbitraryZVertical。
- 配置 deviceMotionUpdateInterval 如 1.0 / 60.0,用 startDeviceMotionUpdates(using: frame, to: .main) 读取 motion.attitude 的 roll/pitch/yaw、motion.userAcceleration、motion.gravity、motion.heading(相对于当前 frame 的角度),完成后调用 stopDeviceMotionUpdates()。
- 简单倾斜控制使用 .xArbitraryZVertical 或 .xArbitraryCorrectedZVertical,避免依赖磁力计/定位。
- 在请求 corrected、magnetic-north 或 true-north frame 前调用 CMMotionManager.availableAttitudeReferenceFrames(),并回退到可用 frame。
- 按需选择 attitude reference frame:.xArbitraryZVertical 默认、Z 垂直、X 启动时任意,适合多数游戏;.xArbitraryCorrectedZVertical 同样但随时间校正陀螺仪漂移;.xMagneticNorthZVertical 的 X 指向磁北,需要磁力计;.xTrueNorthZVertical 的 X 指向真北,需要磁力计和定位。
- 使用 CMPedometer 前确认 isStepCountingAvailable,并可用 isDistanceAvailable、isFloorCountingAvailable、isPaceAvailable、isCadenceAvailable 分别检查距离、楼层、配速、步频能力。
- CMPedometer 可提供步数、距离、配速、步频和楼层数。
- 历史查询用 pedometer.queryPedometerData(from: Calendar.current.startOfDay(for: Date()), to: Date()),读取 data.numberOfSteps、data.distance?.doubleValue、data.floorsAscended?.intValue。
- 实时步数用 pedometer.startUpdates(from: Date()) 读取 data.numberOfSteps;完成后调用 pedometer.stopUpdates()。
- 使用 CMMotionActivityManager 前确认 CMMotionActivityManager.isActivityAvailable()。
- CMMotionActivityManager 检测 stationary、walking、running、cycling、automotive(在车辆中)。
- 实时活动用 startActivityUpdates(to: .main) 读取 activity 的 walking/running/automotive/cycling/stationary 与 confidence;完成后调用 stopActivityUpdates()。
- 历史活动用 queryActivityStarting(from: yesterday, to: Date(), to: .main) 遍历 activities,读取 activity.startDate、activity.walking 等。
- 使用 CMAltimeter 时,相对高度也受 NSMotionUsageDescription 覆盖;授权被拒时通过数据不可用和 update handler 错误处理。
- 启动相对高度前确认 CMAltimeter.isRelativeAltitudeAvailable();用 startRelativeAltitudeUpdates(to: .main) 读取 data.relativeAltitude(米)和 data.pressure(kPa);完成后调用 stopRelativeAltitudeUpdates()。
- 绝对高度是相对于海平面的高度,不是 GPS 高度;先检查 CMAltimeter.isAbsoluteAltitudeAvailable()。
- 绝对高度仅支持特定硬件,如 iPhone 12 或后续机型,以及 Apple Watch Series 6、Apple Watch SE 或后续机型。
- 绝对高度用 startAbsoluteAltitudeUpdates(to: .main) 读取 data.altitude(米)和 data.accuracy(米);完成后调用 stopAbsoluteAltitudeUpdates()。
- 更新间隔按需选择:1.0 / 10.0(10 Hz)用于 UI 方向,低耗电;1.0 / 30.0(30 Hz)用于休闲游戏,中等耗电;1.0 / 60.0(60 Hz)用于动作游戏,高耗电;1.0 / 100.0(100 Hz)为 iPhone 最大速率,极高耗电。
- 使用满足需求的最低频率;不要假设所有设备都有固定最大采样率。
- 高频训练运动在支持时使用 CMBatchedSensorManager,并读取其报告的 accelerometerDataFrequency 或 deviceMotionDataFrequency,而不是给这些只读属性赋值。
- 不要创建多个 CMMotionManager 实例;保留一个 app-level CMMotionManager,竞争实例会降低更新率。
- 不要跳过传感器可用性检查;在每个传感器流启动前立即应用对应的 is...Available 门控。
- 不要忘记停止更新;每个 start 都要在对应生命周期或任务取消路径中配对匹配的 stop。
- 不要使用不必要的高更新率;选择满足交互的最低速率,可用更新间隔表作为起点。
- 不要假设 CMMotionActivity 的所有属性互斥;多个属性可能同时为 true,操作前检查 confidence,例如 if activity.walking && activity.confidence == .high { handleWalking() } else if activity.automotive && activity.confidence != .low { handleDriving() }。
- Review checklist: 确认 Info.plist 中有 NSMotionUsageDescription 且解释清晰。
- Review checklist: 确认 CMMotionManager 单例并在全 app 共享。
- Review checklist: 确认启动更新前检查传感器可用性(如 isAccelerometerAvailable 等)。
- Review checklist: 确认在计步/活动 API 前检查授权状态。
- Review checklist: 确认更新间隔设为最低可接受频率。
- Review checklist: 确认所有 start*Updates 调用都有生命周期对应位置的 stop*Updates。
- Review checklist: 确认 handler 派发到合适队列,重处理不要阻塞主线程。
- Review checklist: 确认在根据活动类型行动前检查 CMMotionActivity.confidence。
- Review checklist: 确认检查 update handler 中的 error 参数。
- Review checklist: 确认设备运动代码在请求特定 attitude frame 前调用 CMMotionManager.availableAttitudeReferenceFrames()。
- Review checklist: 确认依据实际需求选择 attitude reference frame,不要不必要地默认 true north。
- 扩展模式参考 references/motion-patterns.md,包括 SwiftUI 集成、batched sensor manager、headphone motion、water submersion。
- 参考 CoreMotion 框架与各管理器文档:CMMotionManager、CMPedometer、CMMotionActivityManager、CMDeviceMotion、CMAltimeter、CMAbsoluteAltitudeData、CMBatchedSensorManager、CMHeadphoneMotionManager、CMWaterSubmersionManager、Accessing submersion data、Getting processed device-motion data。
适用边界 · 注意事项
- 不适用于 Android、Web、Linux 或非 Apple 平台;Core Motion 是 Apple 平台框架。
- 如果只需要 GPS 高度/位置、HealthKit 步数或服务端活动数据,不必直接接入 Core Motion 传感器。
- 如果无法在 Info.plist 添加 NSMotionUsageDescription 或无法处理授权拒绝,不应直接访问运动数据,否则会崩溃或失败。