传感器
很多时候,iOS 设备,特别是 iPhone 的“智能”会让很多用户感到好奇。比如,在使用 iPhone 中的地图应用时,它可以显示出我面向的方向。或者,在我旋转 iPhone 时它可 以自动将程序界面随之旋转以适应当前的持握方式。还有,当我从户外走入室内后, iPhone 可以自动降低亮度让屏幕显得不是那么刺眼。所有诸如此类的“智能”,其实都是 由集成在 iOS 设备内部的一系列传感器配合系统完成的。这些传感器,对于 iOS 系统本 身和在其之上运行的各类 App 都用相当重要的作用,也是 iOS 系统“智能”的主要来源之 一。了解这些传感器以及其作用,能够让你更好的认识、利用和保护手中的 iOS 设备, 这一章节,我将为各位简单介绍存在于 iOS 中的传感器。 iOS 设备的不同,所集成的传感器也有不同,这里笔者以 iPhone 5 为例进行介绍,
在本章节最后,笔者也会附带一个列表向你展示不同的 iOS 设备中拥有的传感器类型差异。
iPhone 5 传感器列表 |
---|
运动/加速度传感器 (Motion/Accelerometer Sensor) |
环境光传感器 (Ambient Light Sensor) |
距离传感器 (Proximity Sensor) |
磁力计传感器 (Magnetometer Sensor) |
内部温度传感器 (Internal Temperature Sensor) |
湿度传感器 (Moisture Sensor) |
陀螺仪 (Gyroscope) |
全球卫星定位系统 (GPS-Global Positioning System) |
摄像头 (Camera) |
- 运动/加速度传感器 (Motion Sensor/Accelerometer Sensor) iPhone 上配备的是一款三轴的运动/加速度传感器,它也是最早出现在 iOS 设备上的 传感器之一。它的读数以 G-force 为单位。所谓加速度,是指单位时间中速度的变 化。所谓三轴,是说明其能够检测设备在三个方向上的加速度。将你的设备正面向 上平放在一个水平平面上,从左至右为 x 轴,从下至上为 y 轴,与水平面垂直向上 的为 z 轴。如图: 。由于地球重力加 速度影响,则在此时 z 轴为一个负值,而其它两轴值为 0。这时如果你在水平面上旋 转设备,你会预知所有三个轴上的数据不会发生变化。而如果你让设备从平面上立 起,则这时,z 轴将不会感受到重力加速度的影响 (值为0),那么这时 y 轴应该为一 个负值。然后你再将设备向左或向右90度倾倒,让设备的左或右边缘与水平面保持 平行状态,则此时 y,z 轴则不会收到重力加速度的影响,x 轴则为一个负值。根据 这个传感器提供的数值,设备本身就可以检测到你的持握方式发生的改变,从而可 以使得 iPhone 自动旋转照片或App 界面以适应你当前的持握方式。所以,在 iPhone 4 以前的机型,其用户界面在 Potrait (纵向显示) 或 Landscape (横向显示) 模式之间切换是利用了此传感器。除此以外,我们都知道在 iOS 设备中,很多的 App 都支持“摇一摇”这个操作,那么这个动作也是得益于运动/加速度传感器,当你 摇晃设备时,传感器就会感受到在一个轴向(x,y,z)上的正/反向加速度,当这个正/反 向加速度超过一个特定阈值时,通知系统或 App 响应“摇一摇”这个操作。很多赛车 中都有加速度计这个装置,用于检测赛车在高速过弯时的横向加速度,你也可以通 过 iOS 设备中的这个传感器,自己设计一个程序,用于检测汽车运行时的各方向的 加速度。
环境光传感器 (Ambient Light Sensor) 你应该有这样的经验,当你从一个明亮的室外走入相对黑暗的室内后,iOS 设备会 自动调低亮度,让屏幕显得不再那么光亮刺眼。这一切就得益于环境光传感器的作 用。其实,环境光传感器是 iOS 设备,甚至 Mac 上最为古老的传感器成员。它的存 在能够让你在使用 Mac 或 iPhone,iPad 时,眼睛更为舒适。除此之外,当你使用 iPhone 拍照时,闪光灯会在一定条件下自动启动。还有,几乎所有的笔记本型 Mac 都带有背光键盘,当周围光线减弱到一定条件是会自动开启键盘背光,这都是得益 于环境光传感器的功劳。
距离传感器 (Proximity Sensor) 当你使用 iPhone 拨出电话或者接听电话并将电话放在耳边的时候,iPhone 会自动 关闭屏幕,这样做的好处,1,是节省电量。2,是防止耳朵或面部错误触发触摸屏 操作。这一切都是 iPhone 上的距离传感器在起作用。除此之外,Siri 还有一个开关 叫做 “拿起电话来说话”,当你开启它后,只要拿起 iPhone 放在耳边,这时 Siri 就会 自动启动,倾听你的诉说,这也同样是距离传感器的功劳。说句题外话,iPhone 距 离传感器的存在造成了太多影视剧的穿帮镜头,当剧中人物帅气的拿起 iPhone,拨 打电话并放到耳边时,屏幕却很不争气的亮着,每每看到这种镜头,笔者只能苦笑 导演的粗心。
磁力计传感器 (Magnetometer Sensor) 从 iPhone 3GS 开始,iOS 系统内置了一个指南针的应用。简单说来就是一个电子罗 盘。它的出现得益于 iPhone 装备了磁力传感器。通过磁力传感器对于地球磁场的感 应,获得方向信息。这也使得 iPhone 在位置服务数据提供上更为精准。对于 iPad 来说,磁力计传感器除了用于电子罗盘和导航,还有就是感应 Smart Cover 盒盖睡 眠的操作。
内部温度传感器 (Internal Temperature Sensor) 从 iPad 一代开始,iOS 设备都加入了一个内部温度传感器,用于检测内部组件温 度,当温度超过系统设定阈值时,会出现以下提示, 。提醒你需要将设备静置一段时间 等其冷却后再使用。这个传感器的加入,对于提升 iOS 设备自身安全性与稳定性有 很大的帮助。
湿度传感器 (Moisture Sensor) 相信很多使用 iOS,Mac 设备的朋友都有设备进水后拿去维修被拒绝的经历,原因 是设备进水不在保修范围之内。那么 Apple 的维修人员是如何得知设备进水了呢? 这就是湿度传感器在作怪。湿度传感器与这里介绍的其他基于微电子,微机电的传 感器不同,它是一个简单的物理传感器,简单说就是一张遇水变红的试纸。拿 iPhone 来说,在耳机插孔底部和 Dock 线连接口内部都有这样一张试纸。一旦设备 遇水,它们就会变成红色。Apple 维修人员在接到 iPhone 设备时,会首先查看试纸 颜色,如遇变红,则就会拒绝你的保修请求。但是这个传感器的灵敏度有些过分, 笔者遇到过很多用户,设备明明没有进水,但是试纸也呈现红色,这往往是因为设 备在高湿度环境中暴露的时间过长导致(比如放在一个带有淋浴的洗手间内过长时 间)。Apple 近期也由于这个问题遭遇用户的联合起诉,赔偿了很大一笔数目。笔记 本型的 Mac 也基本都带有这个传感器,多数位于两侧喇叭下。所以很多打翻水杯导 致进水的用户会遭遇拒绝保修服务。
陀螺仪 (Gyroscope) 陀螺仪是随着 iPhone 4 的上市首次出现在 iOS 设备上的传感器,它的加入为 iOS 设备带来了更为精准的持握方式变化侦测和新的 App (特别是赛车类游戏) 控制方 式。在前面我们介绍过运动/加速度传感器,从它本身的特点来说,激发它需要一个 可被察觉的加速度,从而使得它更有利于侦测设备相对于外界参照物的移动,但是 对于检测设备本身的动作或姿态并不精准。这就是陀螺仪进驻 iOS 设备的原因,它 能够让设备对于自身当前的姿态有更准确的了解。iOS 设备中的陀螺仪都是三轴陀 螺仪,三轴的方向与定义与运动/加速度传感器中的三轴定义相同。不同的地方是陀 螺仪并不用来侦测设备在三个轴向上的线性加速度,而是用于侦测设备沿三个轴为 中线所旋转时的角速度。这里有了三个名词,分别为 pitch (纵倾), roll (横倾) 和 yaw (横摆)。让我们还是以前面介绍运动/加速度传感器时的描述开始。 。想象你的设备正面向上平放在一个 水平平面上,则现在你抬起设备左边缘或右边缘,使得设备沿着 y 轴为中心线做旋 转,这就叫做 roll (横倾)。如果你抬起设备的上边缘或下边缘,让设备沿着 x 轴 为中心线做旋转,则叫做 pitch (纵倾)。如果你将设备水平的在平面上沿着垂直于水 平面的 z 轴旋转,则叫做 yaw (横摆)。从这里你可以看到,陀螺仪通过对这三个轴 角速度的侦测,可以计算得出设备当前的姿态。这对于很多赛车类游戏的操控方式 有着重要的意义,可以通过旋转设备检测到的角速度,来模拟汽车驾驶时方向盘旋 转的动作,使得这类游戏的操控体验更为直观,精确。
全球卫星定位系统 (GPS-Global Positioning System) 这是从 iPhone 3G 开始,加入到 iOS 设备中的传感器。目前存在于 iPhone 3G 以后 的所有 iPhone 机型和所有带有 蜂窝数据模块 (3G/4G-LTE) 的 iPad 中。 iPhone/iPad 中带有的 GPS 是一种被称为 A-GPS (aGPS,Assisted GPS 辅助全球 卫星定位系统) 的模块。与普通的 GPS 设备不同,A-GPS 在初始时需要使用 Wi-Fi 无线网络或蜂窝移动网络(基站)来辅助初始定位。这对于iPhone和带有蜂窝数据通讯 模块的iPad来说不是一个问题。而且,普通 GPS 在初始定位时,需要一个可视天空 的开放环境和至少三颗 GPS 卫星的信号才能进行定位,而 A-GPS 则可以利用Wi-Fi 无线网络或蜂窝移动网络(基站),辅以连接远程服务器的方式下载卫星星历,配合传 统 GPS 卫星接收器,让定位动作更加快速,也更少受到外部环境影响。最早在 iPhone,iPad 中存在的 A-GPS 模块只能使用 GPS 卫星信号来进行定位服务,从 iPhone 4S 开始,内置的A-GPS 模块还可以使用俄罗斯 GLONASS 定位系统。说到 这里,要首先给予读者一点解释。目前世界上一共有四大卫星定位系统,美国的 GPS,俄罗斯的 GLONASS,欧盟的 GALILEO 和 中国的 COMPASS (北斗)。而 GPS 和 GLONASS 是覆盖面最广,应用最多的两个系统。其实一般情况下,使用 GPS 定位已经足够,但是由于美国国防部由于某些因素在定位系统中加入了 S/A 干 扰码,使得 GPS 的精度已由以前的 15–20米降至目前的 100米。在这种情况下, GLONASS 就更具优势,由于其没有 S/A 干扰,则定位精度可达 15米。所以从目前 来说,带有这类 A-GPS 芯片的 iOS 设备定位精度要超过普通的 GPS 定位设备。为 导航等应用提供了更为可靠的硬件支持。
摄像头 (Camera) iPhone,iPod 和 iPad 中带有的前置或后置摄像头其实也是一种传感器。除了摄 影,摄像功能外。摄像头还被用来扫描二维码,条形码和名片,文档材料等。很多 应用利用 iOS 设备摄像头,扫描文档材料,并使用 OCR (光字符转换) 技术快速生 成电子文档。Mac 上也拥有 iSight 或 Facetime HD 摄像头,这些摄像头也被很多的 应用程序利用,比如 Should I Sleep 这个软件,可以利用摄像头进行人脸识别或运 动检测,判断是否应该允许 Mac 进入到睡眠状态。
以上简要的介绍了 iOS 设备中的传感器以及其使用场景。其实在系统和App实际运行 中,很少单独的使用某一传感器的数据,而是结合来自多个传感器的数据,经由一定计 算得出更为精确的结果。如现在的 iOS 设备,显示内容随机器姿态变化而进行适配,早 期是单独利用运动/加速度传感器,而现在则是结合陀螺仪的数据,更加精确、快速的判 断设备姿态并进行相应。而导航应用更是如此,通过结合 GPS,运动/加速度传感器,陀 螺仪,磁力计传感器数据,可以获得更为准确的方向,海拔,速度等等信息。另外值得 一提的是,很多朋友都对 iPod touch,或 Wi-Fi 版本的 iPad 这些无 A-GPS 模块的设备 在某些条件下使用内置地图应用也能进行有限导航这个特性颇为不解。其实这也是传感 器的功劳,通过联合使用运动/加速度传感器和陀螺仪,实现惯性导航。用这类设备进行 导航时,初始需要一个 Wi-Fi 网络获得一个粗糙的位置数据,然后通过运动/加速度传感 器、陀螺仪的数据和运行时间进行运算,然后对地图数据进行一系列复杂匹配后能实现 有限导航。但是很多朋友发现这中导航准确性相当差,这是由于在真正的惯性导航中, 也需要 GPS或外部数据 来不断给定数据对方向进行修正,才能正确完成导航。当然,美 国国防部现在也正在研究完全无需 GPS 的惯性导航系统,我们只能盼望这项技术早日进 入到民用产品中,让没有 GPS 的设备也能完成导航工作。
常用的传感器
距离传感器
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//开启距离传感器功能
//这个传感器就是iPhone听筒上方的那个点,打电话的时候当脸靠近传感器就会出发传感器事件
UIDevice.current.isProximityMonitoringEnabled = true
//监听物体靠近或离开设备的通知
NotificationCenter.default.addObserver(self, selector: #selector(stateChange), name: NSNotification.Name.UIDeviceProximityStateDidChange, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
func stateChange() {
//获取当前是否有物体靠近或离开设备
if UIDevice.current.proximityState {
print("有帅哥靠近")
}
else {
print("有帅哥离开")
}
}
}
加速器传感器
在iOS4以前:使用UIAccelerometer,用法非常简单(到了iOS5就已经过期)Swift无法使用
1. 获得单例对象
UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
2. 设置代理
accelerometer.delegate = self;
3. 设置采样间隔
accelerometer.updateInterval = 1.0/30.0; // 1秒钟采样30次
4. 实现代理方法
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
测试图解
#import "ViewController.h"
@interface ViewController ()<UIAccelerometerDelegate>
@property (weak, nonatomic) IBOutlet UILabel *xLabel;
@property (weak, nonatomic) IBOutlet UILabel *yLabel;
@property (weak, nonatomic) IBOutlet UILabel *zLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
accelerometer.delegate = self;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
NSLog(@"%f---%f---%f",acceleration.x,acceleration.y,acceleration.z);
self.xLabel.text = [NSString stringWithFormat:@"%f",acceleration.x];
self.yLabel.text = [NSString stringWithFormat:@"%f",acceleration.y];
self.zLabel.text = [NSString stringWithFormat:@"%f",acceleration.z];
}
@end
加速计(iOS4以后)
从iOS4开始:CoreMotion.framework
使用变化 随着iPhone4的推出 加速度计全面升级,并引入了陀螺仪 与Motion(运动)相关的编程成为重头戏 苹果特地在iOS4中增加了专门处理Motion的框架-CoreMotion.framework Core Motion不仅能够提供实时的加速度值和旋转速度值,更重要的是,苹果在其中集成了很多牛逼的算法
Core Motion获取数据的两种方式
push 实时采集所有数据(采集频率高)
pull 在有需要的时候,再主动去采集数据
区别图解
Core Motion的使用步骤
push
1. 创建运动管理者对象 CMMotionManager *mgr = [[CMMotionManager alloc] init]; 2. 判断加速计是否可用(最好判断) if (mgr.isAccelerometerAvailable) 3. 设置采样间隔 mgr.accelerometerUpdateInterval = 1.0/30.0; // 1秒钟采样30次 4. 开始采样(采样到数据就会调用handler,handler会在queue中执行) - (void)startAccelerometerUpdatesToQueue:(NSOperationQueue *)queue withHandler:(CMAccelerometerHandler)handler;
pull
1. 创建运动管理者对象 CMMotionManager *mgr = [[CMMotionManager alloc] init]; 2. 判断加速计是否可用(最好判断) if (mgr.isAccelerometerAvailable) 3. 开始采样 - (void)startAccelerometerUpdates; 4. 在需要的时候采集加速度数据 CMAcceleration acc = mgr.accelerometerData.acceleration;
import UIKit
import CoreMotion
class ViewController: UIViewController {
@IBOutlet weak var xLabel: UILabel!
@IBOutlet weak var yLabel: UILabel!
@IBOutlet weak var zLabel: UILabel!
//创建运动管理者对象
let manager:CMMotionManager = CMMotionManager()
override func viewDidLoad() {
super.viewDidLoad()
//push()
pull()
}
func push() {
//检测加速计是否可用
guard manager.isAccelerometerAvailable else {
print("设备的加速计坏掉了吗")
return
}
//设置采样时间
manager.accelerometerUpdateInterval = 1.0 / 2
//push,把数据主动告诉外界
manager.startAccelerometerUpdates(to: OperationQueue.main) { (data:CMAccelerometerData?, error:Error?) in
guard let data = data else { return }
self.xLabel.text = String(describing: data.acceleration.x)
self.yLabel.text = String(describing: data.acceleration.y)
self.zLabel.text = String(describing: data.acceleration.z)
}
}
func pull() {
//检测加速计是否可用
guard manager.isAccelerometerAvailable else {
print("设备的加速计坏掉了吗")
return
}
//开始采集
manager.startAccelerometerUpdates()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//在需要的时候采集加速度数据
let acc:CMAcceleration = (manager.accelerometerData?.acceleration)!;
self.xLabel.text = String(describing: acc.x)
self.yLabel.text = String(describing: acc.y)
self.zLabel.text = String(describing: acc.z)
}
}
摇一摇
1、让当前的ViewController支持晃动;
- (void)viewDidLoad
{
[superviewDidLoad];
// 支持shake
[[UIApplicationsharedApplication]setApplicationSupportsShakeToEdit:YES];
}
2、让当前的View成为第一响应者;
-(BOOL)canBecomeFirstResponder
{// 默认值是 NO
return YES;
}
-(void)viewDidAppear:(BOOL)animated
{
[superviewDidAppear:animated];
[selfbecomeFirstResponder];
}
-(void)viewWillDisappear:(BOOL)animated
{
[selfresignFirstResponder];
[superviewWillDisappear:animated];
}
3、重写下面的方法,并在相应的方法中添加手机晃动时需要执行的代码。
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event//开始晃动
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event//晃动结束
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event//
只要在对于的三个事件监听方法中做事情就行了,它们是
override func motionBegan(_ motion: UIEventSubtype, with event: UIEvent?) {
print("摇一摇开始")
}
override func motionEnded(_ motion: UIEventSubtype, with event: UIEvent?) {
print("摇一摇结束")
}
override func motionCancelled(_ motion: UIEventSubtype, with event: UIEvent?) {
print("摇一摇被取消")
}
计步器
功能作用
- 可以判断走了多少步数
- 判断当前楼层
以下代码是iOS8.0之前和之后的做法
import UIKit
import CoreMotion
class ViewController: UIViewController {
let pedometer = CMPedometer()
let counter = CMStepCounter()
override func viewDidLoad() {
super.viewDidLoad()
stepCountiOS8_0After()
//stepCountiOS8_0Before()
}
//iOS8.0之后做法
func stepCountiOS8_0After() {
//需要开启 Privacy - Motion Usage Description 权限
guard CMPedometer.isStepCountingAvailable() else {
print("计步器不可用")
return
}
pedometer.startUpdates(from: Date(timeIntervalSinceNow: 0)) { (data:CMPedometerData?, error:Error?) in
guard error == nil else { return }
print("走了\(data?.numberOfSteps)" //走了多少步
print("走了\(data?.distance)" //走了多远
print("\(data?.currentPace)步/秒") //步/每秒
print("上了\(data?.floorsAscended)台阶") //上了多少台阶
print("下了\(data?.floorsDescended)台阶") //下了多少台阶
}
let startDate = Date(timeIntervalSinceNow: -24 * 60 * 60)//表示昨天
let endDate = Date(timeIntervalSinceNow: 0)
pedometer.queryPedometerData(from: startDate, to: endDate) { (data:CMPedometerData?, error:Error?) in
guard error == nil else { return }
print("---历史数据---")
print("走了\(data?.numberOfSteps)" //走了多少步
print("走了\(data?.distance)" //走了多远
print("\(data?.currentPace)步/秒") //步/每秒
print("上了\(data?.floorsAscended)台阶") //上了多少台阶
print("下了\(data?.floorsDescended)台阶") //下了多少台阶
}
}
//iOS8.0之前做法
func stepCountiOS8_0Before() {
guard CMStepCounter.isStepCountingAvailable() else {
print("计步器不可用")
return
}
let startDate = Date(timeIntervalSinceNow: -24 * 60 * 60)//表示昨天
let endDate = Date(timeIntervalSinceNow: 0)
counter.queryStepCountStarting(from: startDate, to: endDate, to: OperationQueue.main) { (count:Int, e:Error?) in
print("总共走了\(count)步")
}
counter.startStepCountingUpdates(to: OperationQueue.main, updateOn: 1) { (count:Int, date:Date, e:Error?) in
print("走了\(count)步")
}
}
}