你的位置:首页 > 操作系统

[操作系统]IOS开发QA


一、

问题描述:使用xcode6和ios8开发定位应用时,发现执行操作之后,不会调用到定位之后的delegate方法中。查看了一下手机上对应用的定位权限界面,发现我的应用的访问用户的地理位置的权限是空的,即使设置了定位权限依然不会生效。当查阅了相关资料以后,得到如下解决方案:

解决方案:

step1:

在 info.plist里加入:
NSLocationWhenInUseDescription,允许在前台获取GPS的描述
NSLocationAlwaysUsageDescription,允许在后台获取GPS的描述

最终如下图所示:

 

 

step2:

1.@interface里:
CLLocationManager *locationManager;
2. 初始化:
locationManager = [[CLLocationManager alloc]init];
3. 调用请求:
// 判断是否iOS8
if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
[self.locationManagerrequestAlwaysAuthorization]; // 永久授权
[self.locationManagerrequestWhenInUseAuthorization]; //使用中授权
}
[self.locationManager startUpdatingLocation];

添加以上内容之后即可以进行定位服务,百度地图和高德地图测试可用。


参考资料&扩展阅读

http://stackoverflow.com/questions/24062509/location-services-not-working-in-ios-8

http://stackoverflow.com/questions/24874997/core-location-not-working-in-ios-8

 

二、

问题描述:最近要开发一个类似微信的demo,需要支持用户语音对话,这个客户端有IOS版本和Android版本,要完成语音通信功能,在网上看了下资料,类似这类产品使用的技术,talkboxAndroid版用的是ilbc的第三方编解码库,在iPhone上用的是caf。微信Android版估计是amr估计转码的是交给腾讯强大的服务器了;米聊Android版和Iphone版用的都是speex。目前支持的开源第三方库有:libopencore_amr,ilbc和speex。

解决方案:

这里我采用libopencore_amr。此库可AMR和WAV音频格式的互转,实现使用iphone录制wav格式,转成amr格式和amr转wav。以便和安卓进行语音聊天。支持architecture i386, x86_64, armv7, armv7s, arm64。

主要思路:

实现过程是先录制WAV,然后再转AMR,然后发送给Andriod。接收时再把AMR格式转WAV然后播放。

step1.录制WAV,参考了官方的SpeakHere范例

IOS提供的AVFoundation框架可以实现大部分系统声音服务不支持的超过30秒的音频播放功能,同时还提供了录音功能。而我们主要使用到的是AVAudioRecorder与AVAudioPlayer两个类,通过名字我们就可以判断出,前者是提供音频录制服务而后者则是提供播放服务。AVAudioRecorder以各种不同的格式将声音录制到内存或设备本地文件中。录音过程可再应用程序执行其他功能时持续进行。而AVAudioPlayer能够播放任意长度的音频。使用这个类可以实现游戏配乐和其他复杂的音频应用程序。可以全名控制播放过程,包括同时播放多个音频文件等。无疑IOS提供的音频服务是强大以及便利的。再使用AVFoundation框架之前必须要将AVFoundation.framework与CoreAudio.framework加入到项目中,再导入两个接口文件。

#import<AVFoundation/AVFoundation.h>

#import<CoreAudio/CoreAudioTypes.h>

具体的使用实例代码如下,首先是音频录制的使用方法:

 

然后是播放音频的部分:

 

现在我我们来详细解读一下者两段代码的含义,首先是音频录制的代码,我们先后声明并且定义了一下几样东西,创建音频的参数键值对MyRecordParam,一个路径数组pathArray,一个Docment路径字符串DocmentPath以及我们这一步的主角AVAudioRecorder对象MyRecorder。

我们先来解释一下路径的获取,至于音频参数,重头戏需要放在后面不是么~

NSSearchPathForDirectoriesInDomains是IOS中一个搜索路径的方法,它三个参数前两个为枚举,而最后一个参数为BOOL类型,第一个参数的枚举列表如下:

enum{

NSApplicationDirectory= 1,//Supported applications (/Applications)

NSDemoApplicationDirectory,//Unsupportedapplications and demonstration versions

NSDeveloperApplicationDirectory,//Developerapplications (/Developer/Applications)

NSAdminApplicationDirectory,//Systemand network administration applications

NSLibraryDirectory,//Varioususer-visible documentation, support, and configuration files (/Library)

NSDeveloperDirectory,//Developerresources (/Developer)

NSUserDirectory,//Userhome directories (/Users)

NSDocumentationDirectory,//

NSDocumentDirectory,//

NSCoreServiceDirectory,//Locationof core services (System/Library/CoreServices)

NSAutosavedInformationDirectory= 11,//Location of user’s autosaved documents Library/Autosave Information

NSDesktopDirectory= 12,//

NSCachesDirectory= 13,//Location of discardable cache files (Library/Caches)

NSApplicationSupportDirectory= 14,//Location of application support files (Library/Application Support)

NSDownloadsDirectory= 15,//

NSInputMethodsDirectory= 16,//

NSMoviesDirectory= 17,//

NSMusicDirectory= 18,//

NSPicturesDirectory= 19,//

NSPrinterDescriptionDirectory= 20,//

NSSharedPublicDirectory= 21,//

NSPreferencePanesDirectory= 22,//

NSItemReplacementDirectory= 99,//

NSAllApplicationsDirectory= 100,//

NSAllLibrariesDirectory= 101//

};

其每一项代表一种希望获取到的目录类型,这其中不只是IOS中的目录类型,也有MAC下的路径类型,没错,就跟你想的一样,这个函数并非IOS下专用。

第二个参数的枚举列表如下

enum{

NSUserDomainMask= 1,//用户主目录中

NSLocalDomainMask= 2,//当前机器中

NSNetworkDomainMask= 4,//网络中可见的主机

NSSystemDomainMask= 8,//系统目录,不可修改(/System)

NSAllDomainsMask= 0x0ffff,//全部

};

第二个参数代表要搜索路径的位置,本机?亦或是当前程序,还是局域网连接到的其他电脑。

第三个参数是一个BOOL值他代表是否将返回完整路径

而返回的路径中并不包含文件名,我们一定要记住再路径结尾处加上我们想要的文件名,别忘了我们是要创建一个音频文件。

当然此函数搜索的结果可能又很多条路径,因为根据你的参数不同他返回的路径甚至可能包含其他电脑上的(具体本人未测,有心人可进一步测试,也希望其讲结果与大家分享)所以他的结果是一个数组,而我们要取得的路径目的极为明确,就是程序的Docment路径,并且可以更加肯定是我们的程序只有一个Docment路径,所以我们直接取得了第一条返回记录。

不得不说的是AVAudioRecorder的设计者是个好人,没错,他没有将构造函数的参数设置成一大堆参数,那让人看起来头疼,但其实他用了一个更加让人头疼的方法,没错他让你去手动设置一个参数键值对,你甚至不知道建值对中该填什么参数,哪些参数…这对于习惯看参数列表直接调用方法的人无疑是个噩梦(尤其是当他们英文文档阅读能力低下时--),目前我所掌握的参数键的相关资料如下:

AVSampleRateKey,//采样率

AVFormatIDKey,//音频编码格式

AVLinearPCMBitDepthKey,//采样位数 默认16

AVNumberOfChannelsKey,//通道的数目

AVLinearPCMIsBigEndianKey,//大端还是小端 是内存的组织方式

AVLinearPCMIsFloatKey,//采样信号是整数还是浮点数

AVEncoderAudioQualityKey,//音频编码质量

鉴于考虑到可能各位看官对于我们所要给出的参数并不了解,所以在此我们来依次解释一下每一个参数的含义

首先是采样率,简单地说就是通过波形采样的方法记录1秒钟长度的声音,需要多少个数据。44KHz采样率的声音就是要花费44000个数据来描述1秒钟的声音波形。原则上采样率越高,声音的质量越好。

编码格式可以理解为每种音频格式不同的编解码方式,鄙人对于此了解的也不是非常多(能熟知所有编解码的人一定是偶像级的超人!)而IOS下这些编码方式被集中到一个枚举中,而我们本次代码中所使用的编码格式是WAV文件的格式,想要使用其他的编码格式就在成功导入AVFouncation框架之后即可通过Xcode的自动提示找到以kAudioFormat开头的各种枚举的名称。

采样位数即采样值或取样值,是用来衡量声音波动变化的参数,是指声卡在采集和播放声音文件时所使用数字声音信号的二进制位数。声卡的位客观地反映了数字声音信号对输入声音信号描述的准确程度。

通道数目应该很好理解了,1意味着单声道声音,2指立体声,4是指四个声道等等。

接下来的AVLinearPCMIsBigEndianKey是指再内存中音频的存储模式,在计算机中,通常采用的字节存储机制主要有两种:big-endian和little-endian,即大端模式和小端模式。这个参数为BOOL值,YES为大端,NO为小端。关于大端和小端相关到两个关键词,MSB以及LSB。MSB:MostSignificant Bit( 最高有效位),LSB:LeastSignificant Bit (最低有效位)你可以理解为一段数据再内存中的起始位置以及终止位置,大端模式就是MSB存放在最低端的地址上。而小端口模式就是LSB存放在最低端的地址上。

在Big-Endian中,对于bit序列中的序号编排方式如下(以双字节数0x8B8A为例):
bit | casino 01 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15
——MSB———————————-LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
——————————————–

在Little-Endian中,对于bit序列中的序号编排和Big-Endian刚好相反,其方式如下(以双字节数0x8B8A为例):

bit| 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0
——MSB———————————–LSB
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
———————————————

总之可以理解为在内存中正反两种存储顺序。

对于采样信号是整数还是浮点数也是一个BOOL类型的参数,本人并未理解会影响到的含义,或许是设计到音频信号再解析时候的精准度但并不敢确定还有待设定,所以也没有设置这个参数。

最后一个参数音频编码质量比较好理解了,这个参数又是一个枚举,我们可以找到以AVAudioQuality开头的High、Low、Medium、Max、Min五种设置。介于参数键值对的解释暂时就是这些了,如果又看官得到了一些其他参数的资料或者对于我的解释有纠正补充的欢迎指教。

 

AVAudioRecorder构造函数中的最后一个参数为一个出参,用以保存音频录制的错误信息,如果不想保存错误的信息直接设置为空即可

接下来我们的AVAudioRecorder对象好像看起来成功创建完成了,慢着,不对,为什么会提示错误?仔细看一下,原来是路径的问题,别担心,其实只是AVAudioRecorder跟你开了个小玩笑,因为他实在太懒了,都懒得把字符串路径转换成URL了,所以我们得手动转换一下~没错使用NSURL的静态方法urlWithString即可解决~接下来只要调用record方法即可开始录音。而以上代码只是实例,建议在编写程序的时候,我们的AVAudioRecorder对象要声名在类内属性中。否则需要结束录音时无法调用到AVAudioRecorder的stop方法。

AVAudioRecorder对象创建起来或许会比较麻烦,但是使用起来确很方便,只要再录音开始时调用record,暂停的时候调用pause方法,而结束的时候调用stop方法就可以了。

相对于录音,播放音频可以说简单的可以,我们在创建AVAudioPlayer对象的时候只需要将之前录音的文件路径给它并且给一个空的错误出参便可轻松的创建出一个AVAudioPlayer对象,使用起来也是那么的方便只要调用一下play函数即可~~~他和AVAudioRecorder一样也可以提供暂停和停止的功能,那它是否可以支持进度调节呢?想知道的话不如用自动提示打开他的方法列表看看呢~一切看起来好像都很简单,我们就要轻松愉快的大功告成了,可当你运行程序之后却惊奇的发现为什么播放不出声音!使用iTools一类的软件检查一下程序的Docment目录,没错啊!文件在啊~,莫非我录制错了?等等等等上万种可能就这样出现在你的脑中!好吧我真不忍心看你像我一样没头没脑的研究几个小时只是因为你没有把实例代码中AVAudioPlayer的声明放到类属性中。。。没错,如果你再某个方法中声明了它并且调用播放函数你就会发现怎么样也播放不出声音,如果你在调用play方法的位置设置下断点再仔细听的话可能会听到一小段声音,为什么呢?因为你刚调用了play的方法你的AVAudioPlayer对象就被释放了,当然什么也没有了也就播放不出声音了~使用AVAudioPlayer就把它的对象放入类内属性吧!

 

这部分转自http://cvito.net/index.php/archives/854