Core Motion 框架是 App Services (Apple 的应用服务)中的一个框架。本篇文章就不分析API 了,毕竟一个框架太大了。有点懒。。。
Core Motion
Core Motion可以从从iOS设备上获取(包括加速度计,陀螺仪,计步器,磁力计和气压计)报告运动和环境相关数据。我们可以使用此框架访问设备生成的数据,以便在应用程序中使用它们。例如,游戏可能会使用加速度计和陀螺仪数据来控制屏幕上的游戏行为。 该框架的许多服务允许我们访问由硬件记录的原始值和这些值的处理版本。处理的值不包括可能会对您如何使用该数据产生不利影响的偏见形式。例如,处理的加速度计值仅反映由用户引起的加速度,而不是由重力引起的加速度。 **注意:**支持 iOS10.0 以上设备,并且在我们访问设备数据的时候需要在 info.plist 文件中添加键值 Privacy - Motion Usage Description
对于 CoreMotion 框架的使用,之前写过 CMPedometer 计步器的使用 。今天主要看一下别的。 首先有必要看一下 API 中对于 Core Motion 框架的一个基本层次划分,主要见下图:
Core Motion 框架基础部分,也就是 API 中的 First Steps,有两个很重要的类是: CMMotionManager 和 CMLogItem: CMLogItem 是所有运动相关数据对象的基类。 CMMotionManager是启动和管理运动服务的对象。可以使用CMMotionManager对象来访问加速度计数据,旋转速率数据,磁力计数据和其他设备运动数据。在创建实例之后,应用程序可以使用它来接收四种类型的运动:原始加速度计数据,原始陀螺仪数据,原始磁力计数据,和处理之后的设备运动数据(其包括加速度计,旋转速率和姿态测量) 说那么多废话,其实想表达的就是CMMotionManager对象可以访问上图中黄色区域的数据。
那么接下来我们分别来看下每一部分的实现
Device motion使用
设备运动服务提供了一种简单的方法,可以为您的应用获取运动相关数据。原始加速度计和陀螺仪数据需要处理以消除其他因素(如重力)的偏差。设备运动服务对您进行此处理,为您提供可以立即使用的精细数据。例如,该服务为用户启动的加速度和由重力引起的加速度提供单独的值。因此,此服务可让您专注于使用数据来处理内容,而不是处理数据。 设备运动服务使用可用的硬件来生成一个对象,其中包含以下信息: CMDeviceMotion 设备相对于参考框架在三维空间中的方向(或姿态) 无偏转速 当前重力向量 用户生成的加速矢量(无重力) 目前的磁场矢量 您可以使用Core Motion框架的类访问设备运动服务。启用服务之前,请始终检查该属性的值以验证该服务是否可供您使用。您可以从设备运动服务接收数据的几个选项。您只能在需要时获取运动数据,或者您可以要求框架定期将更新推送到您的应用程序。每个技术涉及不同的配置步骤,并且具有不同的用例。
CMDeviceMotion 源码:
// 是 CMLogItem 的子类
@available(iOS 4.0, *)
open class CMDeviceMotion : CMLogItem {
// 设备现在所处的的物理状态
open var attitude: CMAttitude { get }
// 设备的转速。
open var rotationRate: CMRotationRate { get }
// 在设备参考系中表示的重力加速度矢量。
open var gravity: CMAcceleration { get }
// 用户给设备的加速度。
open var userAcceleration: CMAcceleration { get }
// 返回相对于设备的磁场矢量。 可以获得校准磁场 ,是一个结构体
@available(iOS 5.0, *)
open var magneticField: CMCalibratedMagneticField { get }
}
复制代码
实现:
let motionManager = CMMotionManager()
var timer: Timer!
let altimeter = CMAltimeter()
override func viewDidLoad() {
super.viewDidLoad()
// 判断DeviceMotion服务是否在设备上可用
guard motionManager.isDeviceMotionAvailable else {
print("DeviceMotion 不可用")
return
}
motionManager.startDeviceMotionUpdates()
print(motionManager.isDeviceMotionActive) // print false
}
// 设备运动
@IBAction func getDeviceMotion(_ sender: UIButton) {
let deviceMotion = motionManager.deviceMotion!
print("1.",deviceMotion.rotationRate)
// 设置获取的时间间隔
motionManager.deviceMotionUpdateInterval = 1.0
//motionManager.showsDeviceMovementDisplay = true
// 开始获取数据
motionManager.startDeviceMotionUpdates(to: OperationQueue.current!) { (motions, error) in
guard let motion = motions else {
return
}
// 设备现在所处的的物理状态
print("2.",motion.rotationRate)
// 设备的转速。
print("2.",motion.gravity)
// 在设备参考系中表示的重力加速度矢量。
print("2.",motion.attitude.pitch,
motion.attitude.roll,motion.attitude.yaw)
// 用户给设备的加速度。
print("2.",motion.userAcceleration)
}
// 注意: 下边的两种方法会导致,上边的那种方法失效,用的时候请根据自己的需求选择
// motionManager.startDeviceMotionUpdates(using: .xMagneticNorthZVertical)
// print(deviceMotion.rotationRate)
//
// motionManager.startDeviceMotionUpdates(using: .xTrueNorthZVertical, to: OperationQueue.current!) { (motions, error) in
//
// guard let motion = motions else {
// return
// }
//
// print("3.",motion.rotationRate)
// print("3.",motion.gravity)
// print("3.",motion.attitude)
// print("3.",motion.userAcceleration)
//
//
// }
}
复制代码
Accelerometer的使用
// 加速计
@IBAction func getAccelerometers(_ sender: UIButton) {
// 使用Core Motion框架的类访问原始加速度计数据。
// 判断Accelerometer是否在设备上可用。
if self.motionManager.isAccelerometerAvailable {
self.motionManager.accelerometerUpdateInterval = 1.0 / 60.0 // 60 Hz
self.motionManager.startAccelerometerUpdates()
// Configure a timer to fetch the data.
self.timer = Timer(fire: Date(), interval: (1.0/60.0),
repeats: true, block: { (timer) in
// 获取 accelerometer 数据.
if let data = self.motionManager.accelerometerData {
let x = data.acceleration.x
let y = data.acceleration.y
let z = data.acceleration.z
print(x,y,z)
}
})
// Add the timer to the current run loop.
RunLoop.current.add(self.timer!, forMode: .defaultRunLoopMode)
}
self.motionManager.startAccelerometerUpdates(to: OperationQueue.current!) { (data, error) in
guard let accelerometerData = data else {
return
}
let x = accelerometerData.acceleration.x
let y = accelerometerData.acceleration.y
let z = accelerometerData.acceleration.z
print(x,y,z)
}
}
复制代码
Gyroscope的使用
// 陀螺仪
@IBAction func startGyroData(_ sender: UIButton) {
// 判断陀螺仪在设备上是否可用
if motionManager.isGyroAvailable {
motionManager.startGyroUpdates(to: OperationQueue.current!) { (data, error) in
guard let gyroData = data else {
return
}
// 旋转速率
print(gyroData.rotationRate)
}
}
}
复制代码
Magnetometer的使用
@IBAction func getMagnetometer(_ sender: UIButton) {
// 判断磁力计在设备上是否可用
guard motionManager.isMagnetometerAvailable else {
return
}
// 获取数据
motionManager.startMagnetometerUpdates()
if let data = motionManager.magnetometerData {
print(data.magneticField)
}
// 获取数据
motionManager.startMagnetometerUpdates(to: OperationQueue.current!) { (data, error) in
guard let magnetomeeterData = data else {
return
}
print(magnetomeeterData.magneticField)
}
}
复制代码
Altitude的使用
// 获取海拔高度。不再是使用CMMotionManager获取了
@IBAction func getAltitude(_ sender: UIButton) {
if CMAltimeter.isRelativeAltitudeAvailable() {
print(OperationQueue.current!.name!)
let queue = OperationQueue()
queue.name = "Altitude"
queue.maxConcurrentOperationCount = 1
altimeter.startRelativeAltitudeUpdates(to: queue, withHandler: { (data, error) in
guard let altimeterData = data else {
return
}
// 海拔高度
print(altimeterData.relativeAltitude)
// 气压
print(altimeterData.pressure)
})
}
}
复制代码
获取各个数据之后如何停止呢?
@IBAction func stop(_ sender: UIButton) {
motionManager.stopDeviceMotionUpdates()
motionManager.stopGyroUpdates()
motionManager.stopMagnetometerUpdates()
motionManager.stopAccelerometerUpdates()
altimeter.stopRelativeAltitudeUpdates()
}
复制代码