iOS开发如何使用windows语音识别指令来匹配指令

2516人阅读
iOS-音视频(1)
用了半天时间弄明白了在上如何配置语音识别功能,然后用半天时间写了一个,公司坑爹的是不用科大飞讯的语音识别,而使用的是,用查了一下最新的介绍文章是2013年的,是一款国外比较主流的语音识别的第三方框架,全是英文文档(吐槽一下,做开发必须要学好英语啊).
是面向平台的一个离线的语音识别和(文字语音转换)开发工具包.主要是针对英语,也支持中文的语言包,但是我感觉它的识别性不是太好.最重要的是,这是一款免费的工具包,除了基本的免费功能,它还提供了可以用来扩展基本功能的付费插件.今天主要介绍的是它的免费功能,即简单的语音识别功能.
当前的最新版本为2.5,下载地址为
2.详细配置
正常情况下Xcode会为你自动添加好文件的路径,在搜索输入框输入Framework Search Paths,右键点击刚刚添加的
.然后添加AudioToolbox库和AVFoundation库到你的项目里边.
(2)在你需要进行语音识别的.m文件下引入头文件,需引入头文件如下:
在你需要进行语音识别的.h文件下引入头文件,需引入头文件如下:
然后跟你需要实现语音识别的文件下引入协议(绿色&&部分为需要引入的协议),例如
并将OEEventsObserver属性添加到您的其他类属性(OEEventsObserver必须您的类的属性,否则它不会工作):
然后在viewDidLoad或者你需要的地方进行初始化观察者并签订协议:
下一步是创建你需要使用到的语音类文件,这决定你将使用什么语言进行识别,在viewDidLoad或者其他地方均可,具体实现如下:
其中的words是你创建的需要识别的单词.
最后在你需要开启语音识别的地方添加如下方法,开启语音识别:
其中你注册的观察者签订的协议方法如下所示&nbsp>&nbsp
&nbsp>&nbsp
ios教程 &nbsp>&nbsp
iOS语音识别功能实现
摘要:现在市面上的即时通讯app都有语音转文本的功能,那么语音转文本如何实现呢?自己写是不现实的,因为这涉及到模式识别的算法,所以只能用到第三方SDK了,我在项目中用到的是百度语音SDK,自己也是刚刚实现功能,很多地方都还需要优化,就简单介绍一下如何实现吧一注册应用首先登录百度语音登录百度语音在应用管理中添加新的应用创建新应用创建到第4步时,把bundleidentifier填进去填入应用包名创建成功后,可以拿到AppID,APIKey,SecretKey,这些东西都是后面配置用得
现在市面上的即时通讯app都有语音转文本的功能, 那么语音转文本如何实现呢? 自己写是不现实的, 因为这涉及到模式识别的算法, 所以只能用到第三方SDK了, 我在项目中用到的是百度语音SDK, 自己也是刚刚实现功能, 很多地方都还需要优化, 就简单介绍一下如何实现吧
一 注册应用
首先登录百度语音
登录百度语音
在应用管理中添加新的应用
创建新应用
创建到第4步时, 把bundle identifier填进去
填入应用包名
创建成功后, 可以拿到App ID, API Key ,Secret Key, 这些东西都是后面配置用得到的
二 配置环境
下载iOS版本的SDK
下载iOS版本的SDK
下载了官方的SDK之后, 可以看到以下文件
官方SDK文件目录
如果嫌麻烦的话, 直接把除了Doc和Sample文件的其余文件全部拖到工程里去
添加依赖库
添加依赖库1
添加依赖库2
关于添加依赖库, 百度官方是这样解释的:
BDVRClient 使用了录音和播放功能,因此需要在 Xcode 工程中引入 AudioToolbox.framework和 AVFoundation.BDVRClient 还使用到了网络状态检测功能,因此还需要引入SystemConfiguration.为了生成设备 UDID,需要引入 Security.为了支持 gzip压缩,需要引入 libz.1. 网络模块需要引入 CFNetwork.某些场景需要获取设备地理位置以 高识别准确度,需引入 CoreLocation.framework。为了支持识别控件,需要引入 OpenGLES.framework,QuartzCore.framework,GLKit.framework,CoreGraphics.framework 和 CoreText.framework。
添加方式:右键点击 Xcode 中的工程文件,在出现的界面中,选中 TARGETS 中应用,在出现的界面中选中 Build Phase-&Link Binary With Libraries,点击界面中的“+”图标,在弹出的界面中选择此 7 个 Framework 即可,添加完成效果图如图 8 所示(libBDVoiceRecognitionClient.a 将在随后添加
添加完成后先预编译一下, 我在编译的时候遇到的问题都是由于libBDVoiceRecognitionClient.a这个静态库没有正确添加导致的
另外一个问题是我现在的工程文件只能在真机环境下运行, 在模拟器的环境运行始终报错, 目前我还没找到合适的解决方法
三 开始写代码
首先创建一个音频识别管理类
创建音频识别管理类
Note: 需要注意的是, 静态库采用Objective C++实现, 因此, 需要保证工程中引用静态库头文件的实现文件的扩展名必须为.mm
我们实现一个单例构造方法
+ (instancetype)sharedRecognizer {
static ZHLVoiceRecognizer *recognizer =
static dispatch_once_t onceT
dispatch_once(&;onceToken, ^{
recognizer = [[ZHLVoiceRecognizer alloc] init];
在这个类中,我们添加一个 BDVoiceRecognitionClient类的属性 /**
语音识别代理
@property (nonatomic,strong)BDVoiceRecognitionClient *
对它进行懒加载
- (BDVoiceRecognitionClient *)client {
if (!_client) {
_client = [BDVoiceRecognitionClient sharedInstance];
[_client setPropertyList:@[@(EVoiceRecognitionPropertyMusic), // 音乐
@(EVoiceRecognitionPropertyVideo), // 视频
@(EVoiceRecognitionPropertyApp), // 应用
@(EVoiceRecognitionPropertyWeb), // web
@(EVoiceRecognitionPropertySearch), // 热词
@(EVoiceRecognitionPropertyEShopping), // 电商&;购物
@(EVoiceRecognitionPropertyHealth), // 健康&;母婴
@(EVoiceRecognitionPropertyCall), // 打电话
@(EVoiceRecognitionPropertyMedicalCare) , // 医疗
@(EVoiceRecognitionPropertyCar), // 汽车
@(EVoiceRecognitionPropertyCatering), // 娱乐餐饮
@(EVoiceRecognitionPropertyFinanceAndEconomics), // 财经
@(EVoiceRecognitionPropertyGame), // 游戏
@(EVoiceRecognitionPropertyCookbook), // 菜谱
@(EVoiceRecognitionPropertyAssistant), // 助手
@(EVoiceRecognitionPropertyRecharge), // 话费充值
/* 离线垂类 */
@(EVoiceRecognitionPropertyContacts) , // 联系人指令
@(EVoiceRecognitionPropertySetting), // 手机设置
@(EVoiceRecognitionPropertyTVInstruction), // 电视指令
@(EVoiceRecognitionPropertyPlayerInstruction), // 播放器指令
@(EVoiceRecognitionPropertyRadio)]];
/* 设置识别语言为中文 */
[_client setLanguage:EVoiceRecognitionLanguageChinese];
/* 设置不禁用标点符号 */
[_client disablePuncs:NO];
/* 设置对语音进行端点检测 */
[_client setNeedVadFlag:YES];
/* 设置对上传的语音进行压缩 */
[_client setNeedCompressFlag:YES];
/* 设置在线识别的响应等待时间,如果超时,触发同步离线识别 */
[_client setOnlineWaitTime:5];
[_client setPlayTone:EVoiceRecognitionPlayTonesRecStart isPlay:YES];
[_client setPlayTone:EVoiceRecognitionPlayTonesRecEnd isPlay:YES];
/* 在开始识别前,需要加载离线识别引擎, 需要传入授权信息、语言模型文件信息及语法槽信息 */
/* 识别垂类语法槽信息 */
NSDictionary* recogGrammSlot = @{@&$name_CORE& : @&张三/n 李四/n&,
@&$song_CORE& : @&小苹果/n 我的滑板鞋/n&, @&$app_CORE& : @&百度/n 百度地图/n&,
@&$artist_CORE& : @&刘德华/n 周华健/n&};
NSString *licensePath = [[NSBundle mainBundle] pathForResource:@&bdasr_temp_license& ofType:@&dat&];
NSString *datFilePath = [[NSBundle mainBundle] pathForResource:@&s_1& ofType:nil];
int result = [_client loadOfflineEngine:@&8979326& license:licensePath datFile:datFilePath LMDatFile:nil grammSlot:recogGrammSlot];
if (result == 0) {
NSLog(@&加载离线识别引擎成功&);
NSLog(@&加载离线识别引擎失败&);
[_client setApiKey:@&UsLZWXdC45BHo1YXMni2M4Ga& withSecretKey:@&ebbc78d2df8e46ddc4badf25&];
其实懒加载中我们做了很多事情, 而我们进行语音识别主要也是靠BDVoiceRecognitionClient这个类的对象,1.设置属性列表
EVoiceRecognitionPropertyMap = 10060, // 地图
EVoiceRecognitionPropertyInput = 20000, // 输入
以上两个要单独使用, 不能添加到数组中,否则就会出现这个错误
EVoiceRecognitionStartWorkPropertyInvalid
2.进行各种设置
/* 设置识别语言为中文 */
[_client setLanguage:EVoiceRecognitionLanguageChinese];
/* 设置不禁用标点符号 */
[_client disablePuncs:NO];
/* 设置对语音进行端点检测 */
[_client setNeedVadFlag:YES];
/* 设置对上传的语音进行压缩 */
[_client setNeedCompressFlag:YES];
/* 设置在线识别的响应等待时间,如果超时,触发同步离线识别 */
[_client setOnlineWaitTime:5];
[_client setPlayTone:EVoiceRecognitionPlayTonesRecStart isPlay:YES];
[_client setPlayTone:EVoiceRecognitionPlayTonesRecEnd isPlay:YES];
3.在开始识别前,需要加载离线识别引擎, 需要传入授权信息、语言模型文件信息及语法槽信息
/* 在开始识别前,需要加载离线识别引擎, 需要传入授权信息、语言模型文件信息及语法槽信息 */
/* 识别垂类语法槽信息 */
NSDictionary* recogGrammSlot = @{@&$name_CORE& : @&张三/n 李四/n&,
@&$song_CORE& : @&小苹果/n 我的滑板鞋/n&, @&$app_CORE& : @&百度/n 百度地图/n&,
@&$artist_CORE& : @&刘德华/n 周华健/n&};
NSString *licensePath = [[NSBundle mainBundle] pathForResource:@&bdasr_temp_license& ofType:@&dat&];
NSString *datFilePath = [[NSBundle mainBundle] pathForResource:@&s_1& ofType:nil];
int result = [_client loadOfflineEngine:@&8979326& license:licensePath datFile:datFilePath LMDatFile:nil grammSlot:recogGrammSlot];
if (result == 0) {
NSLog(@&加载离线识别引擎成功&);
NSLog(@&加载离线识别引擎失败&);
Note: 其中, 在方法- (int)loadOfflineEngine: (NSString*)appCode license: (NSString*)licenseFile datFile: (NSString*)datFilePath LMDatFile: (NSString*)LMDatFilePath grammSlot: (NSDictionary*)dictS中的第一个参数appCode, 就是之前在百度语音官网上注册的你的AppID
然后再设置API key 和 Secret Key
[_client setApiKey:@&你的ApiKey& withSecretKey:@&你的SecretKey&];
4.接着, 就要写一个开始语音识别的代码了, 其实也是一句代码的事情, 剩下的都是错误处理
- (void)beginVoiceRecognition {
int beginStatus = [self.client startVoiceRecognition:self];
switch (beginStatus) {
case EVoiceRecognitionStartWorking:
NSLog(@&启动成功&);
case EVoiceRecognitionStartWorkNOMicrophonePermission:
NSLog(@&没有系统麦克风使用权限&);
case EVoiceRecognitionStartWorkNoAPIKEY:
NSLog(@&没有ApiKey&);
case EVoiceRecognitionStartWorkGetAccessTokenFailed:
NSLog(@&获取有效的 AccessToken 错误,需要验证开放云平台的注册信息&);
case EVoiceRecognitionStartWorkNetUnusable:
NSLog(@&没有网络&);
case EVoiceRecognitionStartWorkDelegateInvaild:
NSLog(@&没有实现语音回调结果&);
case EVoiceRecognitionStartWorkRecorderUnusable:
NSLog(@&录音设备不可用&);
case EVoiceRecognitionStartWorkPreModelError:
NSLog(@&启动预处理模块出错&);
case EVoiceRecognitionStartWorkPropertyInvalid:
NSLog(@&识别属性设置不合法&);
然后把这个方法暴露给外界使用
5.遵守代理
&MVoiceRecognitionClientDelegate&
6.实现代理回调方法
- (void)VoiceRecognitionClientWorkStatus:(int)aStatus obj:(id)aObj {
switch (aStatus) {
case EVoiceRecognitionClientWorkStatusFlushData: {
// 该状态值表示服务器返回了中间结果,如果想要将中间结果展示给用户(形成连续上屏的效果), // 可以利用与该状态同时返回的数据,每当接到新的该类消息应当清空显示区域的文字以免重复
NSMutableString *tmpString = [[NSMutableString alloc] initWithString:@&&];
[tmpString appendFormat:@&%@&,[aObj objectAtIndex:0]];
NSLog(@&result: %@&, tmpString);
if (self.delegate &;&; [self.delegate respondsToSelector:@selector(getVoiceToMessage:fromRecognizer:)]) {
[self.delegate getVoiceToMessage:tmpString fromRecognizer:self];
case EVoiceRecognitionClientWorkStatusFinish: {
// 该状态值表示语音识别服务器返回了最终结果,结果以数组的形式保存在 aObj 对象中 // 接受到该消息时应当清空显示区域的文字以免重复
if ([_client getRecognitionProperty] != EVoiceRecognitionPropertyInput) {
NSMutableArray *resultData = (NSMutableArray *)aO
NSMutableString *tmpString = [[NSMutableString alloc] initWithString:@&&];
// 获取识别候选词列表
for (int i=0; i&[resultData count]; i++) {
[tmpString appendFormat:@&%@/r/n&,[resultData objectAtIndex:i]]; }
NSLog(@&result: %@&, tmpString);
NSMutableString *sentenceString = [[NSMutableString alloc] initWithString:@&&];
for (NSArray *result in aObj) { // 此时 aObj 是 array,result 也是 array
// 取每条候选结果的第0条,进行组合
// result 的元素是 dictionary,对应每个候选词和对应的可信度
NSDictionary *dic = [result objectAtIndex:0];
NSString *candidateWord = [[dic allKeys] objectAtIndex:0];
[sentenceString appendString:candidateWord];
NSLog(@&result: %@&, sentenceString);
case EVoiceRecognitionClientWorkStatusReceiveData: {
// 此状态只在输入模式下发生,表示语音识别正确返回结果,每个子句会通知一次(全量, // 即第二次收到该消息时所携带的结果包含第一句的识别结果),应用程序可以
// 逐句显示。配合连续上屏的中间结果,可以进一步 升语音输入的体验
NSMutableString *sentenceString = [[NSMutableString alloc] initWithString:@&&];
for (NSArray *result in aObj) { // 此时 aObj 是 array,result 也是 array
// 取每条候选结果的第 条,进 组合
// result 的元素是 dictionary,对应 个候选词和对应的可信度
NSDictionary *dic = [result objectAtIndex:0];
NSString *candidateWord = [[dic allKeys] objectAtIndex:0];
[sentenceString appendString:candidateWord];
NSLog(@&result: %@&, sentenceString);
if (self.delegate &;&; [self.delegate respondsToSelector:@selector(getVoiceToMessage:fromRecognizer:)]) {
[self.delegate getVoiceToMessage:sentenceString fromRecognizer:self];
case EVoiceRecognitionClientWorkStatusNewRecordData: {
// 有音频数据输出,音频数据格式为 PCM,在有 WiFi 连接的条件下为 16k16bit,非 WiFi
// 为 8k16bit
case EVoiceRecognitionClientWorkStatusEnd: {
// 用户说话完成,但服务器尚未返回结果
NSLog(@&用户说话完成,但服务器尚未返回结果&);
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:[UIApplication sharedApplication].keyWindow.rootViewController.view animated:YES];
hud.mode = MBProgressHUDModeCustomV
hud.labelText = @&正在语音转文字中,请稍候&;
[hud hide:YES afterDelay:2];
case EVoiceRecognitionClientWorkStatusCancel: {
case EVoiceRecognitionClientWorkStatusError: {
MBProgressHUD *hud = [MBProgressHUD showHudTo:[UIApplication sharedApplication].keyWindow.rootViewController.view image:nil text:@&语音转文字失败,请重试& animated:YES];
hud.mode = MBProgressHUDModeCustomV
[hud hide:YES afterDelay:2];
NSLog(@&语音转文字发生错误&);
case EVoiceRecognitionClientWorkPlayStartTone:
case EVoiceRecognitionClientWorkPlayStartToneFinish:
case EVoiceRecognitionClientWorkStatusStartWorkIng:
case EVoiceRecognitionClientWorkStatusStart:
case EVoiceRecognitionClientWorkPlayEndToneFinish:
case EVoiceRecognitionClientWorkPlayEndTone: ;
在上面这个方法实现中, 我将语音识别的结果传给我本类的代理方法
@class ZHLVoiceR
@protocol ZHLVoiceRecognizerDelegate &NSObject&
- (void)getVoiceToMessage:(NSString *)message fromRecognizer:(ZHLVoiceRecognizer *)
7.这样,我在其他类中遵守ZHLVoiceRecognizerDelegate这个代理, 实现代理方法时, 就能拿到语音识别的结果, 就是那个字符串啦
比如,在我们公司的项目中, 我就将其赋值给textView.text,这样就用户就可以看到语音识别的结果了
- (void)getVoiceToMessage:(NSString *)message fromRecognizer:(ZHLVoiceRecognizer *)recognizer {
self.textView.text =
给大家看看实现效果, 我觉得语音识别的准确率是很高的,请原谅我不是很标准的普通话
以上是的内容,更多
的内容,请您使用右上方搜索功能获取相关信息。
若你要投稿、删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内给你回复。
云服务器 ECS
可弹性伸缩、安全稳定、简单易用
&40.8元/月起
预测未发生的攻击
&24元/月起
为您提供0门槛上云实践机会
你可能还喜欢
你可能感兴趣
阿里云教程中心为您免费提供
iOS语音识别功能实现相关信息,包括
的信息,所有iOS语音识别功能实现相关内容均不代表阿里云的意见!投稿删除文章请联系邮箱:zixun-group@service.aliyun.com,工作人员会在五个工作日内答复
售前咨询热线
服务与支持
账号与支持
关注阿里云
InternationaliOS开发者:其实你还有很多东西需要学
时间: 14:16:42
&&&& 阅读:293
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&iOS6-10新特性总结
1、废除了viewDidUnload,viewDidUnload
收到内存警告需要到didReceiveMemoryWarning中处理
【小技巧】:
iOS6以后的内存处理方式
-(void)didReceiveMemoryWarning
[super didReceiveMemoryWarning];//即使没有显示在window上,也不会自动的将self.view释放。
// Add code to clean up any of your own resources that are no longer necessary.
// 此处做兼容处理需要加上ios6.0的宏开关,保证是在6.0下使用的,6.0以前屏蔽以下代码,否则会在下面使用self.view时自动加载viewDidLoad
if ([self.view window] == nil)//是否是正在使用的视图
// Add code to preserve data stored in the views that might be
// needed later.
// Add code to clean up other strong references to the view in
// the view hierarchy.
self.view =//目的是再次进入时能够重新加载调用viewDidLoad函数。
2、废除了shouldAutorotateToInterfaceOrientation。
【小技巧】:
iOS6以后的内存处理方式,用下面两个方法代替
- (BOOL)shouldA
- (NSUInteger)supportedInterfaceO
还需要在info.plist进行配置
3、UISwitch可以设置开关颜色和背景图
@property (nonatomic,
retain) UIColor *tintC
@property (nonatomic,
retain) UIColor *thumbTintC
@property (nonatomic,
retain) UIImage *onI
@property (nonatomic,
retain) UIImage *offI
4、UINavigationBar新增了,设置阴影图片属性
@property (nonatomic, retain) UIImage *shadowI
5、UIImage可以在设置图片可以进行缩放
+ (UIImage *)imageWithData:(NSData *)data scale:(CGFloat)
- (id)initWithData:(NSData *)data scale:(CGFloat)
6、新增UIRefreshControl
【小技巧】:与UITableView配合实现下拉刷新
7、UICollectionView
【小技巧】:可以实现瀑布流
8、Autolayout
9、语法相关
NSNumber* number = @(3);
NSArray* titles = @[@&a&,@&b&];
NSDictionary* dict = @{@&a&:@&b&};
1、取消了udid和mac地址访问
提供了UUID,IDFA,IDFV,OpenUDID
【小技巧】:
UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码。它是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。这样,每个人都可以建立不与其它人冲突的
UUID。在此情况下,就不需考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。
开发者可以在应用第一次启动时调用一
次,然后将该串存储起来,替代UDID来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。使用UUID,就要考虑应用被删除后再重新安装时的处理。一个解决的办法是:UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置
。但是不能保证在以后的系统升级后还能用(如果系统保存了该信息就能用)。
#import &AdSupport/AdSupport.h&
NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
广告标示符是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序
-& 通用 -&
还原 -& 还原位置与隐私)
,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-&
关于本机 -& 广告 -&
还原广告标示符)
,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广
告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。
在同一个设备上的所有App都会取到相同的值,是苹果专门给各广告提供商用来追踪用户而设的,用户可以在&设置|隐私|广告追踪&里重置此id的值,或限制此id的使用,故此id有可能会取不到值,但好在Apple默认是允许追踪的,而且一般用户都不知道有这么个设置,所以基本上用来监测推广效果,是戳戳有余了。
注意:由于idfa会出现取不到的情况,故绝不可以作为业务分析的主id,来识别用户
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
Vendor标示符是给Vendor标识用户用的,每个设备在所属同一个Vender的应用里,都有相同的值。其中的Vender是指应用提供商,但准确点说,是通过BundleID的DNS反转的前两部分进行匹配,如果相同就是同一个Vender,例如对于com.somecompany.appone,com.somecompany.apptwo
这两个BundleID来说,就属于同一个Vender,共享同一个idfv的值。和idfa不同的是,idfv的值是一定能取到的,所以非常适合于作为内部用户行为分析的主id,来标识用户,替代OpenUDID。
注意:如果用户将属于此Vender的所有App卸载,则idfv的值会被重置,即再重装此Vender的App,idfv的值和之前不同。
unsigned char result[16];
const charchar *cStr = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];
CC_MD5( cStr, strlen(cStr), result );
_openUDID = [NSString stringWithFormat: @&%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x&, result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15],
arc4random() % ];
每台iOS设备的OpenUDID是通过第一个带有OpenUDID
SDK包的App生成,如果你完全删除全部带有OpenUDID SDK包的App(比如恢复系统等),那么OpenUDID会重新生成,而且和之前的值会不同,相当于新设备;
优点是没有用到MAC地址;不同设备能够获取各自唯一的识别码,保证了唯一性,可以用于以往UDID的相关用途;从代码分析OpenUDID的获取,识别码获取方便并且保存谨慎。缺点是当将设备上所有使用了OpenUDID方案的应用程序删除,且设备关机重启,xcode彻底清除并重启,重装应用程序去获取OpenUDID,此时OpenUDID变化,与之前不一样了,所有OpenUDID应用卸载后,由UIPasteboard保存的数据即被清除,重装故会重新获取新的OpenUDID。
那么当因为用户干预或者恶意程序,致使UIPasteboard数据清除,从而导致OpenUDID被删除,重装也会获取新的OpenUDID。
2、UIPasteboard由共享变沙盒化
iOS7之前的UIPasteboard只要应用知道其名字,即可访问其中的内容,而OpenUDID的实现方式也依赖于此,让开发者能使用一组UUID来标记一个设备。iOS7之后,+[UIPasteboard
pasteboardWithName:create:]和+[UIPasteboard pasteboardWithUniqueName]这两个方法产生UIPasteboard仅供同组应用之间共享数据,也就是Info.plist中CFBundleIdentifier字段的前两段标识(例如com.yourcompany.xx的com.yourcompany)相同的应用才能相互共享数据。不同组应用之间相同名字的UIPasteboard是不同的,而不是以前的同一个。所以当前版本的OpenUDID随着iOS7的出现也将慢慢失去其效用。
3、语法增加instancetype
instancetype用来在声明一个方法时告诉编译器其返回类型,它表示返回调用该方法的类的对象。这比之前返回id的通常做法要好,编译器可以对返回类型做一些检查,如果出现错误,在编译时就能提醒你,而不是在程序运行时发生崩溃。同时,在调用子类方法时,使用它还可以省去对返回值的强制类型转换,编译器能够正确推断方法的返回值类型。
4、设置UIImage的渲染模式:UIImage.renderingMode
着色(Tint Color)是iOS7界面中的一个重大改变,你可以设置一个UIImage在渲染时是否使用当前视图的Tint
Color。UIImage新增了一个只读属性:renderingMode,对应的还有一个新增方法:imageWithRenderingMode:,它使用UIImageRenderingMode枚举值来设置图片的renderingMode属性。该枚举中包含下列值:
UIImageRenderingModeAutomatic // 根据图片的使用环境和所处的绘图上下文自动调整渲染模式。
UIImageRenderingModeAlwaysOriginal // 始终绘制图片原始状态,不使用Tint Color。
UIImageRenderingModeAlwaysTemplate // 始终根据Tint Color绘制图片,忽略图片的颜色信息。
renderingMode属性的默认值是UIImageRenderingModeAutomatic,即UIImage是否使用Tint
Color取决于它显示的位置。
【小技巧】:
UIImage *img = [UIImage imageNamed:@&myimage&];
img = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
5、tintcolor VS barTintColor
有些类,比如说UINaviagtionBar,UISearchBar,UITabBar以及UIToolbar已经有了这么命名的属性。他们现在有了一个新的属性:barTintColor。
【小技巧】:
为了避免使用新属性的时候犯错误,如果你的appp需要支持iOS6以前的系统的时候,请检查一下。
UINavigationBar *bar = self.navigationController.navigationB
UIColor *color = [UIColor greenColor];
if ([bar respondsToSelector:@selector(setBarTintColor:)]) { // iOS 7+
bar.barTintColor =
bar.tintColor =
6、UIButtonTypeRoundRect被UIButtonTypeSystem替代
7、新增检查无线路由是否可用
在iOS7当中,你可以通过AirPlay,蓝牙或是其他的虚线机制了解是否有一个远程的设备可用。了解它的话,就可以让你的app在恰当的时候做恰当的事,比如说,在没有远程设备的时候就不显示AirPlay的icon。
@property (nonatomic, readonly) BOOL wirelessRoutesA //
是否有设备可以连接的无线线路?
@property (nonatomic, readonly) BOOL wirelessRouteA // 设备现在是否连接上了网络
NSString *const MPVolumeViewWirelessRoutesAvailableDidChangeN
NSString *const MPVolumeViewWirelessRouteActiveDidChangeN
8、更详细蜂窝网络信息
在iOS7之前,是使用Reachability来检测设备是否连接到WWAN或是Wifi的。iOS7在这个基础上更进了一步,它会告诉你的设备连接上的是那种蜂窝网络。
这是CTTelephonyNetworkInfo的部分功能,它是CoreTelephony框架的一部分。iOS7还增加了currentRadioAccessTechnology属性和
CTRadioAccessTechnologyDidChangeNotification到这个类。还有一些新的字符串常量来定义可能的值,比如说是CTRadioAccessTechnologyLTE。
【小技巧】:
@interface AppDelegate ()
@property (nonatomic, strong) CTTelephonyNetworkInfo *networkI
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.networkInfo = [[CTTelephonyNetworkInfo alloc] init];
NSLog(@&Initial cell connection: %@&, self.networkInfo.currentRadioAccessTechnology);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessChanged) name:
CTRadioAccessTechnologyDidChangeNotification object:nil];
- (void)radioAccessChanged {
NSLog(@&Now you‘re connected via %@&, self.networkInfo.currentRadioAccessTechnology);
注意:研究一下CTTelephonyNetworkInfo.h文件来看看是否有其他无线网络类型的的字符串常量。如果设备没有连上的话currentRadioAccessTechnology则会返回nil。
9、通过iCloud同步用户设备的密码
iOS7以及Mavericks增加了iCloud Keychain来提供密码,以及iCloud中一些敏感数据的同步。开发者可以通过keychain中的kSecAttrSynchronizable
key来遍历dictionary对象。
由于直接处理keychain比较难,封装库提供了一个简单的处理keychain的方法。SSKeychain封装库可能是最有名的的一个,作为一种福利,现在它支持在iCloud同步。
【小技巧】:
- (BOOL)saveCredentials:(NSError **)error {
SSKeychainQuery *query = [[SSKeychainQuery alloc] init];
query.password = @&MySecretPassword&;
query.service = @&MyAwesomeService&;
query.account = @&John Doe&;
query.synchronizable = YES;
return [query save:&error];
- (NSString *)savedPassword:(NSError **)error {
SSKeychainQuery *query = [[SSKeychainQuery alloc] init];
query.service = @&MyAwesomeService&;
query.account = @&John Doe&;
query.synchronizable = YES;
query.password =
if ([query fetch:&error]) {
return query.
10、使用NSAttributedString显示HTML
在app中使用Webviews有时会让人非常沮丧,即使只是显示少量的HTMLneirong,Webviews也会消耗大量的内容。现在iOS7让这些变得简单了,你可以从用少量代码在HTML文件中创建一个NSAttributedString。
【小技巧】:
//htmlStr -& NSAttriubtedString
NSString *html = @&&bold&Wow!&/bold& Now &em&iOS&/em& can create &h3&NSAttributedString&/h3& from HTMLs!&;
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding]
options:options documentAttributes:nil error:nil];
//NSAttriubtedString -& htmlStr
NSAttributedString *attrS // from previous code
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSData *htmlData = [attrString dataFromRange:NSMakeRange(0, [attrString length]) documentAttributes:options error:nil];
NSString *htmlString = [[NSString alloc] initWithData:htmlData encoding:NSUTF8StringEncoding];
11、系统提供base64编码
NSData* sampleData = [@&Some sample data& dataUsingEncoding:NSUTF8StringEncoding];
NSString * base64String = [sampleData base64EncodedStringWithOptions:0];
NSData* dataFromString = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
12、获取截图事件的通知(UIApplicationUserDidTakeScreenshotNotification)
13、语音播报功能(AVSpeechSynthesizer)
【小技巧】:
AVSpeechSynthesizer *synthesizer = [[AVSpeechSynthesizer alloc] init];
AVSpeechUtterance *utterance =
[AVSpeechUtterance speechUtteranceWithString:@&Wow, I have such a nice voice!&];
utterance.rate = AVSpeechUtteranceMaximumSpeechRate / 4.0f;
utterance.voice = [AVSpeechSynthesisVoice voiceWithLanguage:@&en-US&]; // defaults to your system language
[synthesizer speakUtterance:utterance];
14、UIScreenEdgePanGestureRecognizer
UIScreenEdgePanGestureRecognizer
继承自UIPanGestureRecognizer
,它可以让你从屏幕边界即可检测手势。
【小技巧】:
UIScreenEdgePanGestureRecognizer *recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:
@selector(handleScreenEdgeRecognizer:)];
recognizer.edges = UIRectEdgeL
[self.view addGestureRecognizer:recognizer];
15、UIScrollViewKeyboardDismissMode
滚动的时候可以让键盘消失是一种非常好的体验,苹果给UIScrollView添加了一个很好用的属性keyboardDismissMode,现在仅仅只需要在Storyboard中改变一个简单的属性,或者增加一行代码,你的app可以和办到和Messages
app一样的事情了。
UIScrollViewKeyboardDismissModeNone
UIScrollViewKeyboardDismissModeOnDrag
UIScrollViewKeyboardDismissModeInteractive
16、使用Core Image来检测眨眼以及微笑
iOS给Core Image增加了两种人脸检测功能:CIDetectorEyeBlink以及CIDetectorSmile。这也就是说你现在可以在照片中检测微笑以及眨眼。
【小技巧】:
UIImage *image = [UIImage imageNamed:@&myImage&];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
NSDictionary *options = @{ CIDetectorSmile: @YES, CIDetectorEyeBlink: @YES };
NSArray *features = [detector featuresInImage:image.CIImage options:options];
for (CIFaceFeature *feature in features) {
NSLog(@&Bounds: %@&, NSStringFromCGRect(feature.bounds));
if (feature.hasSmile) {
NSLog(@&Nice smile!&);
NSLog(@&Why so serious?&);
if (feature.leftEyeClosed || feature.rightEyeClosed) {
NSLog(@&Open your eyes!&);
17、给textView的文字上加点击事件
【小技巧】:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:@&This is an example by @marcelofabri_&];
[attributedString addAttribute:NSLinkAttributeName
value:@&username://marcelofabri_&
range:[[attributedString string] rangeOfString:@&@marcelofabri_&]];
NSDictionary *linkAttributes = @{NSForegroundColorAttributeName: [UIColor greenColor],
NSUnderlineColorAttributeName: [UIColor lightGrayColor],
NSUnderlineStyleAttributeName: @(NSUnderlinePatternSolid)};
textView.linkTextAttributes = linkA
textView.attributedText = attributedS
textView.delegate =
//你也可以控制当链接被点击的时候会发生什么,实现这个可以使用UITextViewDelegate协议的新的shouldInteractWithURL方法,就像这样:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
if ([[URL scheme] isEqualToString:@&username&]) {
NSString *username = [URL host];
// do something with this username
return NO;
return YES; // let the system open this URL
18、UI变化
取消了拟物化,变成了扁平化设计
UITabbar,UIbarButtonItem,navigationBar,都以特殊形式渲染,图片没有内部颜色,通过tinColor渲染图片(开发者可以通过渲染模式使用原图颜色)。navigationBar及导航栏也作为self.view的内容,所以self.view的原点从导航栏下面变成了,状态栏的顶端。(可以通过self.navigationController.navigationBar.translucent以及self.edgesForExtendedLayout来决定是否以ios7或ios6样式显示)
19、sprite kit
可以用系统自带框架做小游戏
20、多任务
http://blog.csdn.net/tskyfree/article/details/
http://blog.csdn.net/wwwang89123/article/details/
21、AirDrop
苹果将该功能集成到了UIActivityViewController,如果做了分享功能,则并不要添加特别的代码,具体实现参考UIActivityViewController。
22、MapKit
(1)MKMapCamera,可以将一个MKMapCamera对象添加到地图上,在指明位置,角度和方向后将呈现3D的样子…大概可以想象成一个数字版的Google街景..
(2)MKDirections获取Apple提供的基于方向的路径,然后可以用来将路径绘制在自己的应用中。这可能对一些小的地图服务提供商产生冲击,但是还是那句话,地图是一个数据的世界,在拥有完备数据之前,Apple不是Google的对手。这个状况至少会持续好几年(也有可能是永远)。
(3MKGeodesicPolyline创建一个随地球曲率的线,并附加到地图上,完成一些视觉效果。
(4)MKMapSnapshotter使用其拍摄基于地图的照片,也许各类签到类应用会用到。
5.改变了overlay物件的渲染方式。
23、动态uikit
新增了UIDynamicItem委托,用来为UIView制定动态行为,当然其他任何对象都能通过实现这组接口来定义动态行为,只不过在UIKit中可能应用最多。所谓动态行为,是指将现实世界的行为或者特性引入到UI中,比如重力等。通过实现UIDynamicItem,UIKit现在支持如下行为:
* UIAttachmentBehavior 连接两个实现了UIDynamicItem的物体(以下简称动态物体),一个物体移动时,另一个跟随移动 * UICollisionBehavior指定边界,使两个动态物体可以进行碰撞
* UIGravityBehavior顾名思义,为动态物体增加重力模拟 * UIPushBehavior为动态物体施加持续的力 * UISnapBehavior为动态物体指定一个附着点,想象一下类似挂一幅画在图钉上的感觉。
如果有开发游戏的童鞋可能会觉得这些很多都是做游戏时候的需求,一种box2d之类的2D物理引擎的既视感跃然而出。没错的亲,动态UI,加上之后要介绍的Sprite
Kit,极大的扩展了使用UIKit进行游戏开发的可能性。另外要注意UIDynamicItem不仅适用于UIKit,任何对象都可以实现接口来获得动态物体的一些特性,所以说用来做一些3D的事情也不是没有可能。如果觉得Cocos2D+box2d这样的组合使用起来不方便的话,现在动态UIKit+SpriteKit给出了新的选择。
24、Inter-App Audio应用间的音频
AudioUnit框架中加入了在同一台设备不同应用之间发送MIDI指令和传送音频的能力。比如在一个应用中使用AudioUnit录音,然后在另一个应用中打开以处理等。在音源应用中声明一个AURemoteIO实例来标为Inter-App可用,在目标应用中使用新的发现接口来发现并获取音频。想法很好,也算是在应用内共享迈出了一步,不过我对现在使用AudioUnit这样的低层级框架的应用数量表示不乐观。也许今后会有一些为更高层级设计的共享API提供给开发者使用。毕竟要从AudioUnit开始处理音频对于大多数开发者来说并不是一件很容易的事情。
25、点对点连接 Peer-to-Peer Connectivity
可以看成是AirDrop不能直接使用的补偿,代价是需要自己实现。MultipeerConnectivity框架可以用来发现和连接附近的设备,并传输数据,而这一切并不需要有网络连接。可以看到Apple逐渐在文件共享方面一步步放开限制,但是当然所有这些都还是被限制在sandbox里的。
26、Store Kit Framework
Store Kit在内购方面采用了新的订单系统,这将可以实现对订单的本机验证。这是一次对应内购破解和有可能验证失败导致内购失败的更新,苹果希望藉此减少内购的实现流程,减少出错,同时遏制内购破解泛滥。前者可能没有问题,但是后者的话,因为objc的动态特性,决定了只要有越狱存在,内购破解也是早晚的事情。不过这一点确实方便了没有能力架设验证服务器的小开发者,这方面来说还是很好的。
27、iBeacon
一种全新的基于蓝牙的传输协议,可以实现非常精确的定位
1、UIAlertController
UIAlertController整合了actionsheet和alertview
【小技巧】:
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@&取消& style:UIAlertActionStyleCancel handler:nil];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@&好的& style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:cancelAction];
[alertController addAction:okAction];
[self presentViewController:alertController animated:YES completion:nil];
2、SizeClasses
可以根据不同尺寸,横屏竖屏在StoryBoard上或者Xib上对app进行适配
3、Health Kit
4、Home Kit
智能家居方面
5、SceneKit
6、Handoff
如果你的程序有mac版本,那么它可以和ios版本进行自由的交互
( 例如系统的电话,短信,facetime功能)
7、CLFloor室内定位
CLLocation的floor可以告诉你当前的楼层
8、TouchID
指纹识别方面
9、PhotoKit
一个新的相册框架,替代了原来的AL
10、UIPopoverPresentationController
其相当于ipad中的UIPopoverController,在某个空间周边显示一个气泡菜单
【小技巧】:
MyViewController*
contentVC = [[MyViewController alloc]init];
contentVC.preferredContentSize = CGSizeMake(110, 160);
contentVC.modalPresentationStyle = UIModalPresentationP
self.popover = contentVC.popoverPresentationC
self.popover.delegate =
self.popover.backgroundColor = [UIColor greenColor];
self.popover.sourceView =
self.popover.sourceRect = button.
self.popover.permittedArrowDirections = UIPopoverArrowDirectionUp;
[self presentViewController:contentVC animated:YES completion:nil];//推出popover
11、Cloud Kit
其类似于BaaS,与之不同的是,Cloud Kit倾向于对数据的集成。你可以不更改应用现有的数据模型和结构,而只是使用
Cloud Kit 来从云端获取数据或者向云端存储数据。但是其最大限制在于只能用于苹果端。
12、全新的通知机制
13、定位权限的变化
【小技巧】:
// 当使用iOS8定位的时候需要请求用户授权,且在info.plist里添加字段NSLocationAlwaysUsageDescription请求用户授权的描述
// iOS7仅仅需要在info.plist里添加字段Privacy - Location Usage Description请求用户授权的描述
if (IOS8) {
[self.maneger requestAlwaysAuthorization];//请求用户授权
14、各种小插件
Today Widget Extension
第三方输入法 Extension
Document Picker Extension
Photo Editing Extension
Shared Extension
Action Extension
Watch Extension
15、Metal Kit
一套图形接口
和Direct3D类似主要制作3D相关
16、Apple Pay
苹果支付相关sdk
17、tableviewcell自动适应高度
如果cell用autolayout布局,只需要两行代码就可以实现自动计算高度
self.tableView.estimatedRowHeight = 44.0f;
self.tableView.rowHeight = UITableViewAutomaticD
18、WebKit
WKWebView可以替代UIWebView
19、Swift语言
1、https网络
默认https,如果不支持https,需要到info.plist做配置
2、后台定位
【小技巧】:
_locationManager.allowsBackgroundLocationUpdates = YES;
3、Bitcode
4、inHouse需要进入系统设置权限(弹窗同意)才能安装
5、URL scheme
在iOS9中,如果使用URL scheme必须在&info.plist&中将你要在外部调用的URL
scheme列为白名单,否则无法跳回来。
在info.plist中设置 LSApplicationQueriesSchemes类型为数组,下面添加所有你用到的scheme
6、苹方字体
7、iPad适配Slide Over和 Split View
可以进行多窗口开发
8、tableview局部reload
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
9、Watch Connectivity
由于watchOS 2的架构变化,需要这么一个东西来对iPhone和Watch进行双向通信
10、Spotlight&
可以让自己的app在系统搜索栏搜到内容
11、App Thinning
可以针对设备对app优化,让安装包变小
12、Safari Services Framework(SFSafariViewController)
但你的app需要展示一个WebView又不需要太多定制的时候,用它来替换掉你现在在用的UIWebView或者WKWebView。他可以让Safari以一个Controller的形式加载你的网页,和系统的Safari完全共享Cookie和Autofill等特性,最重要的,Safari的JavaScript引擎
13、3D touch
14、UI Test
可以用Xcode进行项目的自动化测试了
15、GameplayKit,ReplayKit,Model I/O
对游戏的支持
16、语法相关
(1)泛型 &如:
NSArray&NSString*&*
(2)可空标记 &
@property (nonatomic, strong) NSArray *__
@property (nonatomic, strong, nonnull) NSarray *
可以让返回值用kindof
17、UIStackView
类似于安卓的线性布局
18、preferredStatusBarStyle
控制器管理状态栏
1、User Notifications
2、iMessage Apps&表情包App
3、新的插件
iMessage Extension
Notification Content Extension
Notification Service Extension
Audio Unit Extension
Broadcast UI Extension
Broadcast Upload Extension
Call Directory Extension
Content Blocker Extension
Intents Extension
Intents UI Extension
Shared Links Extension
Sticker Pack Extension
4、SiriKit(使用siri服务)
中,我们只能用 SiriKit来做六类事情,分别是:
语音和视频通话
发送或接收付款
5、SpeechFramework语音识别
6、Proactive Suggestions
7、CallKit
8、隐私权限
所有的功能都需要加隐私权限说明(弹窗),否则会闪退
9、tabbar未选中颜色
tabBar.unselectedItemTintColor =[UIColor redColor];
10、跟着系统字体变化
self.labels.font =[UIFont preferredFontForTextStyle:UIFontTextStyleBody];
self.labels.adjustsFontForContentSizeCategory = YES;
11、UIViewPropertyAnimator属性动画器
那么在iOS 10之前,我们使用UIView做动画效果或者自定义一些layer的动画,如果开始了,一般无法进行停止操作更不能暂停操作,而且一些非常复杂的动画处理也比较麻烦,但是在iOS10,苹果退出了一个全新的API&&UIViewPropertyAnimator,可供我们处理动画操作UIViewPropertyAnimator
中新增的一个执行 View动画的类,具有以下特点:
丰富的动画时间控制功能
12、UIColor新方法
苹果官方建议我们使用sRGB,因为它性能更好,色彩更丰富。
+ (UIColor*)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
NS_AVAILABLE_IOS
13、ipv6适配
14、UITextContentType
在iOS 10 UITextField添加了textContentType枚举,指示文本输入区域所期望的语义意义。
使用此属性可以给键盘和系统信息,关于用户输入的内容的预期的语义意义。例如,您可以指定一个文本字段,用户填写收到一封电子邮件确认uitextcontenttypeemailaddress。当您提供有关您期望用户在文本输入区域中输入的内容的信息时,系统可以在某些情况下自动选择适当的键盘,并提高键盘修正和主动与其他文
本输入机会的整合。
15、UIScrollView新增refreshControl
16、判断系统版本
//值为 1
[[[[UIDevice currentDevice] systemVersion] substringToIndex:1]
integerValue]
//值为10.000000[[UIDevice currentDevice] systemVersion].floatValue,
//值为10.0
[[UIDevice currentDevice] systemVersion]
17、Xcode8不能用插件
http://vongloo.me//Make-Your-Xcode8-Great-Again/?utm_source=tuicool&utm_medium=referral
18、[[UIApplication sharedApplication] openURL被废弃
【小技巧】:
用&[[UIApplication sharedApplication]
openURL:nil options:nil completionHandler:nil]代替。
19、字体变化
ios10字体变大,有可能字体显示不全,所以lable大小不要写死
20、UICollectionView性能优化
对UICollectionView进一步的优化。
UICollectionView cell pre-fetching预加载机制
UICollectionView and UITableView prefetchDataSource新增的API
针对self-sizing cells的改进
Interactive reordering
21、https适配
iOS 9中默认非HTTS的网络是被禁止的,当然我们也可以把NSAllowsArbitraryLoads设置为YES禁用ATS。不过iOS
10从2017年1月1日起苹果不允许我们通过这个方法跳过ATS,也就是说强制我们用HTTPS,如果不这样的话提交App可能会被拒绝。但是我们可以通过NSExceptionDomains来针对特定的域名开放HTTP可以容易通过审核。标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&原文:http://blog.csdn.net/hahahakonghee/article/details/
教程昨日排行
&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!

我要回帖

更多关于 语音识别关键词匹配 的文章

 

随机推荐