首先要知道,你需要查看所需的硬件或传感器是否存在,而不是假设设备有哪些功能。举个例子,你不能假设只有iPhone才有麦克风,而应该使用API来查看麦克风是否存在。下面这段代码的第一个优势在于,它能自动兼容将来推出的新设备和外接麦克风。

第二个优势呢?这段代码只有一行。

检查麦克风可用性的正确方法

1
2
3
4
- (BOOL) microphoneAvailable  {
AVAudioSession *session = [AVAudioSession sharedInstance];
return session.inputIsAvailable;
}

对于麦克风,你还需要检测输入设备变化的提醒。也就是当用户插入麦克风时,除了在viewDidAppear中做相应的修改外,还要激活UI上的Record按钮。听起来挺酷,不是吗?下面就是具体的实现方法。

检查是否插入麦克风

 1
2
3
4
5
6
7
8
9
10
11
12
void audioInputPropertyListener(void* inClientData,
AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData) {
UInt32 isAvailable = *(UInt32*)inData;
BOOL micAvailable = (isAvailable > 0);
//加入更新UI的代码
}
- (void)viewDidLoad {
[super viewDidLoad];
AudioSessionAddPropertyListener(
kAudioSessionProperty_AudioInputAvailable,
audioInputPropertyListener, nil);
}

这里,你要做的就是为kAudioSessionProperty_AudioInputAvailable增加一个属性监听器,然后在回调中检查它的值。

只要增加很少几行代码,就能够写出正确的设备检测代码了。下一步,你需要扩展这段代码,从而支持其他的硬件和传感器。


使用AudioSessionPropertyListeners与观察NSNotification事件很像。当你向一个类中增加一个属性监听器时,需要负责在适当的时候移除它。在前面这个例子中,由于在viewDidLoad中增加了属性监听器,所以需要在didReceiveMemoryWarning方法中移除它。


1. 检测摄像头类型

iPhone最初只有一个摄像头,后来在iPhone 4中增加了一个前置摄像头。iPod touch直到第四代才有摄像头。iPhone 4有前置摄像头,iPad 1(比iPhone 4大)却没有摄像头,而后来的iPad 2同时有了前置和后置摄像头。所有这些都意味着你不应该在假设设备功能的前提下编写代码。实际上使用API更方便。

UIImagePickerController类含有检测源类型可用性的类方法。

检测是否存在摄像头

1
2
3
4
- (BOOL) cameraAvailable  {
return [UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera];
}

检测是否存在前置摄像头

1
2
3
4
5
6
7
8
9
- (BOOL) frontCameraAvailable
{
#ifdef __IPHONE_4_0
return [UIImagePickerController isCameraDeviceAvailable:
UIImagePickerControllerCameraDeviceFront];
#else
return NO;
#endif
}

检测前置摄像头,需要运行在iOS 4或更高版本中。枚举类型UIImagePickerControllerCameraDeviceFront只在iOS 4及更高版本中可用,因为所有带有前置摄像头的设备(iPhone 4和iPad 2)使用的都是iOS 4及更高版本。所以你用到了宏,如果设备使用的是iOS 3或更低版本就返回NO

类似地,可以检查设备上的摄像头是否具备视频录制功能。iPhone 3GS及更新设备的摄像头支持录制视频。你可以使用以下代码来检查。

检测摄像头是否支持视频录制

 1
2
3
4
5
6
7
8
9
10
11
12
13
- (BOOL) videoCameraAvailable  {
UIImagePickerController *picker =
[[UIImagePickerController alloc] init];
// 首次调用前面的方法,检查是否存在摄像头
if(![self cameraAvailable]) return NO;
NSArray *sourceTypes = [UIImagePickerController availableMediaTypesForSourceType:
UIImagePickerControllerSourceTypeCamera]; if (![sourceTypes containsObject:(NSString *)kUTTypeMovie]){
return NO;
}
return YES;
}

这段代码会枚举给定摄像头的可用媒体类型,然后判断它是否包含kUTTypeMovie

2. 检测照片库是否为空

如果你在使用摄像头,几乎总会用到照片库。在调用UIImagePicker显示用户相册前,需要确保它里面有照片。可以用检查摄像头是否存在的方法来查看相册是否为空,只要将UIImagePickerControllerSourceTypePhotoLibraryUIImagePickerControllerSourceTypeSavedPhotosAlbum作为源类型传过去就行了。

3. 检测摄像头闪光灯是否存在

到目前为止,带有摄像头闪光灯的唯一设备是iPhone 4^〔1〕^。在未来几年里,将会有越来越多的设备带有摄像头闪光灯。使用UIImagePickerController的类方法来检查摄像头闪光灯是否存在很容易。

^〔1〕^ 翻译本书时,iPhone 4S和iPhone 5均已发布,它们也带有摄像头闪光灯。——译者注

检测摄像头闪光灯是否存在

1
2
3
4
5
6
7
8
- (BOOL) cameraFlashAvailable  {
#ifdef __IPHONE_4_0
return [UIImagePickerController isFlashAvailableForCameraDevice:
UIImagePickerControllerCameraDeviceRear];
#else
return NO;
#endif
}

4. 检测陀螺仪是否存在

陀螺仪是iPhone 4上新增的一个有意思的传感器。iPhone 4之后发布的设备,包括new iPad和iPhone 5,都有陀螺仪。陀螺仪用于测量设备物理位置的相对变化。相比之下,加速计只能测量力的大小,而不能测量扭动。有了陀螺仪,游戏开发者甚至可能实现六轴控制,类似于索尼PlayStation 3控制器或任天堂的Wii控制器提供的功能。你可以使用CoreMotion.framework提供的API来检测陀螺仪是否存在。

检测陀螺仪是否存在

1
2
3
4
5
6
7
8
9
- (BOOL) gyroscopeAvailable  {
#ifdef __IPHONE_4_0
CMMotionManager *motionManager = [[CMMotionManager alloc] init];
BOOL gyroAvailable = motionManager.gyroAvailable;
return gyroAvailable;
#else
return NO;
#endif
}

如果陀螺仪是你的应用中一个重要功能,而你的目标设备上没有陀螺仪,那么必须用其他输入方法来设计应用。或者也可以在应用的info.plist中的UIRequiredDeviceCapablities键中指定它们,防止没有陀螺仪的设备安装该应用。本章稍后会进一步介绍这个键。


5. 检测指南针或磁力计

指南针可用性可以使用CoreLocation.framework中的CLLocationManager类来检查。调用CLLocationManager中的headingAvailable方法,如果返回值为真,你就可以在应用中使用指南针。指南针在与位置有关的应用和用到了增强现实技术的应用中用处比较大。

6. 检测视网膜屏幕

作为iOS开发人员,你已经知道只要为应用中用到的每个资源增加一个@2x的图片文件,就可以满足视网膜屏幕(Retina Display)的需要。但如果要从远程服务器下载图片,采用视网膜屏幕的设备需要下载的图片分辨率为普通屏幕图片分辨率的两倍。

照片浏览器应用就是一个很好的例子,它类似于Flickr查看器或Instagram。当用户在iPhone 4、new iPad或iPhone 5上启动该应用时,下载的图片分辨率应该为非视网膜屏幕设备上图片分辨率的两倍。一些开发者选择忽略它,直接为所有设备下载高分辨率图片,但这有点浪费带宽,甚至通过EDGE下载时可能要慢得多。相反,你应该在判断出设备使用的是视网膜屏幕之后再下载高分辨率图片。这项检查很容易。

检查设备使用的是否是视网膜屏幕

1
2
3
4
5
6
7
8
- (BOOL) retinaDisplayCapable  {
int scale = 1.0;
UIScreen *screen = [UIScreen mainScreen];
if([screen respondsToSelector:@selector(scale)])
scale = screen.scale;
if(scale == 2.0f) return YES;
else return NO;
}

在这段代码中,你会找到设备的mainScreen,然后检查该设备是否可以显示适用于视网膜屏幕的高分辨率图片。这样,如果苹果推出了外接视网膜屏幕(可能是更新的苹果影院显示器),支持目前这一代iPad直接以视网膜模式输出,那么你的应用无需任何修改依然能工作。

7. 检测振动提醒功能

在写本书时,只有各个版本的iPhone具备振动提醒功能。很遗憾,没有公开的API用于检测设备是否支持振动功能。不过,AudioToolbox.framework有两个方法用来选择性地振动不同版本的iPhone:

1
2
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

第一个方法会振动iPhone,而在iPod touch/iPad上则会发出“哔哔”的响声。第二个方法只会振动iPhone。在不支持振动的设备上,它什么都不做。如果你正在开发的一款游戏通过振动设备来提示危险,或是开发一款迷宫游戏,当玩家撞到墙时发出振动,那么应该用第二个方法。第一个方法用来提醒用户,包括振动和发出哔哔声,而第二个方法只能用来发出振动。

8. 检测远程控制功能

iOS应用可以处理按下外接耳机上的按钮触发的远程控制事件。处理这类事件,使用如下方法接收通知:

1
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

firstResponder中实现如下方法:

1
remoteControlReceivedWithEvent:

调用如下方法,确保在不需要这些事件时关闭该功能:

1
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

9. 检测拨打电话功能

可以检查设备是否支持拨打电话,方法是查看它是否能打开tel:类型的URL。UIApplication类的canOpenURL:方法可以很方便地检查设备上是否有能够处理特定类型URL的应用。在iPhone上,tel:这类URL由iPhone上的电话应用来处理。该方法还可以用来检查能够处理给定URL的具体应用是否已安装到设备上。

检测拨打电话功能

1
2
3
4
- (BOOL) canMakePhoneCalls  {
return [[UIApplication sharedApplication]
canOpenURL:[NSURL URLWithString:@"tel://"]];
}

可用性小提示 在iPod touch上,开发者应该完全隐藏面向电话的功能。举个例子,如果你开发一个显示因特网上电话号码列表的黄页应用,应该只在能够拨打电话的设备上显示拨打电话的那个按钮。不要只是简单地禁用它(因为用户做什么都无法启用它)或是显示一个错误提醒。有先例说明,在iPod touch上显示一个“Not an iPhone”错误提醒会导致该应用无法通过苹果应用审核部门的审查。

iOS中检测硬件和传感器的更多相关文章

  1. OS X以及iOS中与硬件环境相关的预定义宏

    由于现在ARM处理器的飞速发展,从Apple A4到现在的Apple A7,从32位到64位,每一代处理器几乎都增加了不少特性,从而在架构上也有所不同.比如Apple A6引入了ARMv7S架构,增加 ...

  2. iOS中使用 Reachability 检测网络

    iOS中使用 Reachability 检测网络 内容提示:下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测.   写本文的目的 了解Reachability都 ...

  3. 【开发记录】iOS中使用 Reachability 检测网络

    如果你想在iOS程序中提供一仅在wifi网络下使用(Reeder),或者在没有网络状态下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测. 写本文的目的 了解Re ...

  4. iOS中使用 Reachability 检测网络区分手机网络类型 WiFi 和2 3 4 G

    如果你想在iOS程序中提供一仅在wifi网络下使用(Reeder),或者在没有网络状态下提供离线模式(Evernote).那么你会使用到Reachability来实现网络检测. 写本文的目的 了解Re ...

  5. (转)如何处理iOS中照片的方向

    如何处理iOS中照片的方向 31 May 2015 • 7 min. read • Comments 使用过iPhone或者iPad的朋友在拍照时不知是否遇到过这样的问题,将设备中的照片导出到Wind ...

  6. iOS 中 UIView 和 CALayer 的关系

    UIView 有一个名叫 layer ,类型为 CALayer 的对象属性,它们的行为很相似,主要区别在于:CALayer 继承自 NSObject ,不能够响应事件. 这是因为 UIView 除了负 ...

  7. Android系统编程入门系列之硬件交互——传感器

    到目前为止,关于应用程序与用户之间的相关内容便比较肤浅的大致介绍完毕.而在整个系统架构中,应用程序与用户之间的交互,犹如参天大树上的枝干和树叶,交互起来五彩缤纷,但使整个生态系统保持生命力的核心,在于 ...

  8. 正则表达式在iOS中的运用

    1.什么是正则表达式 正则表达式,又称正规表示法,是对字符串操作的一种逻辑公式.正则表达式可以检测给定的字符串是否符合我们定义的逻辑,也可以从字符串中获取我们想要的特定部分.它可以迅速地用极简单的方式 ...

  9. iOS中使用正则

    一.什么是正则表达式 正则表达式,又称正规表示法,是对字符串操作的一种逻辑公式.正则表达式可以检测给定的字符串是否符合我们定义的逻辑,也可以从字符串中获取我们想要的特定部分.它可以迅速地用极简单的方式 ...

随机推荐

  1. xml之基础了解

    1.简介 1>什么XML语言(eXtensible Markup Language) 可扩展标记语言XML是SGML的子集,其目标是允许普通的SGML在Web上以目前HTML的方式被服务.接受和 ...

  2. 阿里云:linux 一键安装web环境

    参考地址:http://www.cnblogs.com/ada-zheng/p/3724957.html

  3. 用R语言对NIPS会议文档进行聚类分析

    一.用R语言建立文档矩阵 (这里我选用的是R x64 3.2.2) (这里我取的是04年NIPS共计207篇文档做分析,其中文档内容已将开头的作者名和最后的参考文献进行过滤处理) ##1.Data I ...

  4. hdu 2853 Assignment KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853 Last year a terrible earthquake attacked Sichuan ...

  5. Leetcode#166 Fraction to Recurring Decimal

    原题地址 计算循环小数 先把负数转化成正数,然后计算,最后添加符号 当被除数重复出现的时候,说明开始循环了,所以用一个map保存所有遇到的被除数 需要考虑溢出问题,这也是本题最恶心的地方,看看通过率吧 ...

  6. NYOJ-205 求余数 AC 分类: NYOJ 2014-02-02 12:30 201人阅读 评论(0) 收藏

    这题目看一眼以为难度评级出错了,只是一个求余数的题目,,后来才发现,位数小于百万位,,,我还以为是大小小于百万呢,所以借鉴了另一大神的代码, 用大数,重点是同余定理: (a+b)mod m=((a m ...

  7. HDOJ 1062 Text Reverse

    Text Reverse Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  8. (转载)李剑英的CSLight入门指南结合NGUI热更新

    原地址:http://www.xuanyusong.com/archives/3075 李剑英的CSLight入门指南文档撰写者:GraphicQQ: 1065147807 一. CSLIGHT 作者 ...

  9. jquery offset() 与position()方法的区别

    jquery 中有两个获取元素位置的方法offset()和position(),这两个方法之间有什么异同?使用的时候应该注意哪些问题?什么时候使用offset(),什么时候又使用position()呢 ...

  10. Random的用法

    import java.util.Random; public class RandomTest { public static void main(String[] args) { Random r ...