GCDAsyncSocket类库,IOS下TCP通讯使用心得

关于在IOS下使用Socket进行通讯的技术文章也许诺很久了,今日又是一个还债的日子,网上虽然很多介绍过AsyncSocket或GCDAsyncSocket的文章,但其实就那么一两篇大部分都是转载,于是我义正言辞、慷慨激昂的批判他们这种不负责任的态度,学习,不是给自己学的,是要和大家分享的。技术的共享有利于整体行业的进步,也可以使自身更深入全面的了解。

之前的文章中我们讲到过TCP通讯协议,并且也对其进行了较为详细的介绍和描述,关于TCP通讯的原理此处我们不再赘述,如有需要的看官可自行翻阅本人所写的《IOS、安卓IM语音聊天开发初探部分心得——网络基础篇》一文。

正如名称一样GCDAsyncSocket开源类库是以苹果的GCD多任务处理机制完成的一个异步交互套接字通讯。使用方法其实并不复杂,主要说的是在使用这个类库的时候我的一些心得和理解,若有不妥之处望看官指点。首先,每一个GCDAsyncSocket对象(以下简称GCDSocket对象)都可以理解为一个socket套接字,我们的操作都是针对于这个socket执行的各种命令,可以打开一个端口侦听,同样也可以连接其他计算机的端口进行数据通讯等等等等。首先我们来创建一个socket。当然这之前先要将CGDAsyncSocket的.h文件及.m文件加入到我们的项目,并且在需要使用socket连接的地方将.h头文件包含,这些废话我觉得不需要复述了应该(那你还嘚吧嘚的说半天干嘛啊喂!)。具体代码如下

GCDAsyncSocket  socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

代码并不复杂,我们只需要给出一个委托对象也就是第一个参数中的self,以及一个委托运行的GCD队列即可创建一个GCDAsyncSocket,当前代码中我们是使用静态全局函数取得的主消息队列。当然也可以使用其他方法获得其他的GCD队列,比如:dispatch_get_global_queue().

创建了Socket对象我们即可以立即为,当前我们的socket已经进入程序以供操作。但如果你想和服务器进行通讯,那么我们还需要和服务器进行连接。可能有的使用习惯了http协议的人会问,初始化函数中我们为何不直接指定服务器以及端口号?其实这些肯定都是需要的,但是你要理解到,你的socket对象功能不只是可以用来连接服务器,换而言之我们的socket对象一样可以侦听某端口来等待他人连接,所以在通过套接字编程使用TCP协议的时候是我们从http协议过度到TCP协议的一个转变(虽然本文并不会教你如何在IOS上构架服务器。),但并不是第一个,第一个转变是要记得,我们要使用的是协议,并非某个类,所以我上述说明中都是说从http协议过度到TCP而不是跟大家说现在我们将从NSURLRequest和NSURLConnection过度到GCDAsyncSocket。

好了接下来我们看看如何连接服务器。源代码如下:

NSError *err;

[socket connectToHost:@“192.168.10.111” onPort@”60000″ error:&err];

if (err != nil)

{

NSLog(@”%@”,err);

}

代码比前面稍微长了一点,不过实质上完全不复杂,我们只是先声明了一个错误信息的指针,然后使用之前创建的对象调用他的连接方法,第一个参数不难看出是一个IP,第二个参数则是一个端口,如果这里还不理解何为IP和端口的话,就先去看看在开头就提到的我之前写过的那边网络基础篇文章吧…最后一个是出参,如果连接的过程中出现了错误,该方法会把这根指针指向一个具体的错误信息,最后我们再判断一下之前我们创建错误信息的指针是否还是指向空,如果并非指向空那么代表我们连接的过程中出现了错误,将错误信息打印一下吧~不过请切记,此处的错误信息并非你创建连接时所有的错误都会在此处得到反映。

说到这里我们该说一点真正有用的了,GCDAsyncSocket具有一系列完整的委托机制,我们所做的一切处理基本都是异步处理的状态,换句话说,连接之后是否连接成功,连接成功要执行什么懂并非应该写在此处而应该写在相应的委托之中,同样的道理一样适用于发送、读取数据等等。也就是说我们在此处读出的错误只是同步执行的代码处理一些连接时会发生的错误,而更多的处理我们应在相对应的委托中进行处理。首先请看下面这个方法:

-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port

这个方法就是在成功连接服务器之后的委托方法。关于委托该如何使用我在此处就不赘述了和本文的关系实在不大,不过给诸位看管一个建议,也是我才刚刚纠正的一个编码错误习惯,之前碰到所有委托的地方我都会将直接将当前的类对象设置成委托处理对象,并且遵循委托协议扩充代码,这么做的坏处显而易见,显示层与逻辑层的混淆是一方面,另一方面是一旦需要使用过多的委托,将造成大量不必要的代码都堆积在一个类中,并且我们很容易直接在委托方法中直接使用一些类内成员属性或者甚至是私有成员,而实际上这种做法是很不好的,因为这种最发会使得逻辑出现混乱,处理委托应当是单独处于后台的逻辑,如果需要一些必要的数据传递也应该采取属性侦听、甚至是通知等方式来实现而并非直接在显示层中编写逻辑代码来实现。使得代码耦合性大增的同时也使得很多时候在切换操作对象时对委托对象的处理变得复杂,甚至可能完全相同的代码要难免的复制粘贴。所以我给大家的建议是单独编写一个委托类,在每个类中设置一个该类类型的成员指针,将委托设置到专门的委托对象上去处理,这样不仅效率更高,代码可读性更强,更便于维护,同时也更符合面向对象的编程思想。

回到对GCDAsyncSocket使用的讲解上来,在这个委托方法中,我们可以取到一个socket对象一个服务器IP和一个端口号,你可以处理一切在连接建立之后应该马上执行的事情,比如与服务器进行通信确认连接端以免出现其他人通过IP及端口随意的和你的服务器通信,再比如开启心跳包的发送,让服务器一直可以确认你的存在。不管做什么,都是你和服务器的编写者事前约定好的,就像数据传输格式什么的,如果没有当面约定我坚信他也一定要给你出个文档什么的,否则你的工作接下来将举步维艰。但是不管你要在此处都做什么工作,都要处理哪些事宜,请务必记得,在此处你必须要在函数的最后加上一句:

[socket readDataWithTimeout:-1 tag:0];

这是什么?别慌,按照你看到这个函数的第一反应取理解,没错他就是读取数据的方法,两个参数也略显简单,一个超时时间,如果你设置成-1则认为永不超时,而第二参数则是区别该次读取与其他读取的标志,通常我们在设计视图上的控件时也会有这样的一个属性就是tag。如果你做过web开发,那你应该知道Http标签上的id,如果你做过一些桌面级开发,你的控件或许有个id或者是index再或者是tag的属性来区别这些控件,没错此tag和彼tag功效基本一样。

我们可以这样理解,socket在开启之前是一个巨大门,开启这道门之后(也就是连接之后)就是一个宽敞的通道,通过这条通道所达到的地点就是我们连接的目标服务器,或者是连接过来的客户端,两面都是一样的。我们现在不论是发送数据还是读取数据都是往返于这个大门之中的一个个门卫与邮递员,我们可以把读取数据的方法看作是门卫,而发送数据的人看做是邮递员,没错服务器与客户端都一样,我们都会派出一个个邮递员去我们连接的另一端送信,但是如果你没有命令你的门卫去吧门口邮箱中的信拿过来,那么你的邮递员就会假装看不见邮递员,然后呼呼睡大觉,好吧看起来这些门卫实在没什么责任心不是么,其实他们也是有苦衷的,因为这是最初设计者给他们的命令,不接到命令绝对不要出门,万一收到的是金刚葫芦娃高清全集的种子怎么办!好的就这样,为了避免我们的邮件不被错过,所以建立连接之后就让一个门卫跑去门口等着吧~慢着,万一我需要派出很多个门卫我分不清他们该怎么办,其实他们已经被你分配了工号,这个工号就是tag。

现在我们的连接动作算是完整的做完了,接下来我们要做的就只有两件事,第一个在需要发送数据的时候派出邮递员,以及当门卫接到消息的时候在我们的手机端上根据门卫的消息做出反应。等等,好像少了点什么,没错 少点委托,我们来看一下读取和写入的委托,读取的委托即是门卫接到信息的报告,写入的委托就是邮递员将邮件送完的回复:

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag

好的让我们来看看这些委托中我们都能得到什么,首先是读取的委托,是一个socket对象,一个读取到的数据以及一个“门卫的工号”,嗯,大概也就这些,我们还能要什么的,没错这些足够了,别抱怨第二个参数的数据类型,要知道其实最开始接到数据的时候只是字节数组啊,已经给你转换成NSData对象了你就要学会感恩啊,谁让你要用套接字传输了,这就是活该的,所以改怎么读取转换解析这些数据你需要好好的和服务器编写者沟通。除此之外你还要详细的了解如何将NSData转换成各种各样的数据或者文件如果你还不知道该怎么做我这里实在帮不了你,因为我总不能吧多如牛毛的情况都列举在这一篇文章中吧,要知道我每篇文章的篇幅都够长了。。。不过也别因此而气馁百度和谷歌肯定可以帮到你~

接下来我们再看看“邮递员的委托”,嗯一个socket的对象,一个tag嗯,没错,哎哎,慢着,好像哪里不太对啊,我来看看,哪里不对呢,哦对了!发送的数据呢!怎么没有!哎也不对。。。明明是我自己发的数据我还要来干嘛,有了工号我不就知道发送的是什么了么。那是哪里不太对呢。。。哦!是名字!我们的数据传输来说接受可以是读取read而发送通常我们应该写成Send一类的单词,为何这里是Write?写入?没错就是写入,向TCP的通讯流之中写入数据。TCP通讯协议是一个基于字节流的运输层通信协议,其数据传输的形式也是以流的形式提现,而我感觉在使用GCDAsyncSocket的过程中我们可以很好的体会到流的概念,首先来说为什么这种TCP的这种传输形式要叫流而不像UDP中的那样叫做包?流之中又写入和读出的概念,我们可以把整个TCP通讯的连接看作为一条无水的河流,当然因为他没水所以你可以称它为沟,而向其写入数据即是向河流注入水,被写入的数据会向水一样流向连接的另一端。读即是从河流中取水,只要读得动作在继续,并且河流之中有水,那么我们就可以不停的取到数据,不论是河流之中有水你确没有去读亦或者是你去读了而河流之中没有水都会引发看起来完全相同的反应就是没有数据返回,所以在很多时候我们要处理更多的关于接收数据的逻辑的处理。正如我们目前使用的方法就是一种比较粗暴有效的方法——一旦开启连接读取的动作就永不停歇。

接下来我们还要记住使用TCP流式传输数据时的一个关键性问题,数据是不会自己分段的。没错,就如一次次倒入河流中的水一样,数据也同样会向水一样融合为一个整体,换句话说,数据在TCP中传输本身是没有起始或结尾之分,如果我先向数据流中写入两个人的聊天记录,第一句是“你好”,对方回复了一句“不好”,结果发到了服务器,服务器读取出的信息是“你好不好”,同样类似的情况会发生很多,比我举出的这个例子要常见的多比如我先发了一段音频,又发了一段图片,又发了一段文字,最后服务器接收到了一个带语音和字母的静态图片。实际情况上比我说的要遭的多,因为由于字节之间并没有边界,所以字符、文字、音频,我们根本无法确定他们各有多长,胡乱截取,只会导致无法编码解析成图片、文字及音频,所以如何界定数据之间的边界是你开始使用TCP协议之后又一个问题。你可以使用一个固定的字节数组组合来区分开头以及结尾,也可以将所有的字符串都添加一个特殊的界定字符来区分不同的命令与操作。

如果看到这里的看官有心使用GCDAsyncSocket去编写了一个服务器端,并且使用它来接受客户端的数据,比如传输了一些音频,图片等从字节单位看来将会不小的长串数据的话就会发现,服务器端接到的程序是一段一段的,没错,但我没有欺骗你,TCP协议并不会区分你发送数据的头尾,被划分为段知识GCDAsyncSocket为了保证在并不通常的移动互联网之中一样可以安全的传输数据,于是将你所有写入到流的数据都一分割为一段一段的内容,所以请正确理解我在上一段开头所说的“数据是不会自己分段的。”这句话,不要较真哦亲~

写到这里,GCDAsyncSocket的基本操作及其核心思想就全部写完了,对于思想部分皆为笔者本人个人理解,若有缺少或意见不同之处,欢迎交换意见相互学习,感谢您的阅读。

IOS、安卓IM语音聊天开发初探部分心得——网络基础篇

今儿是个还债的日子,没错,承诺了许久的网络传输篇虽然没有千呼万唤,不过我还是厚着脸皮始出来,继上两篇文章总结了一下开发IM语音功能时所遇到的音频问题,而今天就让我们来看看这个让我们看似近在眼前,确始终犹抱琵琶半遮面的网络传输吧~不过在开始我先要提醒一下诸位看官,我们的本章的内容中只是介绍网络的基础只是以及网络协议部分的知识,针对于如何在IOS下应用使用各种协议进行开发,我们将在IOS网络开发应用篇中详细的讲解,或许对于几千字的纯文字描述来说,讲解各种协议以及一些网络基础知识会显得非常枯燥,但相信我,这几千字的文章中是你最易于理解最全面最值得你品读的,关于一个程序所应具备的互联网知识。

网络一词早已不是什么新鲜话题,不要说来看本文的技术型看官们,就连个小学生嘴里都能冒出几句http,tcp等网络协议的名称,可网络是怎么传输的,协议又是干嘛用的?恐怕这一问就要从念叨名词的受众人群中砍掉绝大部分的回答者了。没错从开头看来大伙应该就明白了,笔者又要从远古时期开始讲解,别嫌我烦,做学问要刨根问底,没有个打破沙锅问到底的精神,就做不成大学问。现在这个时代,是知识爆发的时代,也是知识竞赛的时代,你懂个浮皮潦草,别人都懂没意思,想要出类拔萃,就要为人所不能为,知人所不知,方可凭其一身学识,立一方事业。好了跑偏的话题到此为止,接下来,就让我们从“远古时期”一步步来理解网络传输的概念、原理、最终到如何善用。

在计算机领域中,网络就是用物理链路将各个孤立的工作站或主机相连在一起,组成数据链路,从而达到资源共享和通信的目的。我们用直观一些的白话来说,可以认为是看官与我之间架起一根管道,而通过这个管道把某个物体从一端仍到另一端去,这期中所用到的道具、动作以及双方的通知准备就是计算机网络运行的基础模型。计算机网络的创造者也是人,他们在创造这个跨时代产物的时候也是通过自身常识来判断和设计的,或许这个架起管道的实例并不恰当或具体,不过简单的动作往往更能让人容易理解。从计算机的角度说,计算机网络常用的传输模式是遵循网络七层协议(OSI),而这个协议就是将这个简单的过程复杂化,以达到很多简单过程无法达到的理想效果。说实话如果可以,我一直再绞尽脑汁改如何避开OSI来继续讲解,因为他太底层太复杂并且作为我们程序员并不需要取完全了解它,最重要的是。。。说来惭愧,笔者也不是那么了解这个七层协议,无法讲解的面面俱到,但是,想到下面对于tcp、udp以及http等常用协议的讲解,又不得不提到那么一点,所以我在此设下伏笔,稍后我们会略有涉及,但出于不要误人子弟的中心思想,本文不会详解,如果又感兴趣的看官自行询问度娘,作为一代傲娇弱受,她可谓是上知天文下晓地理,而对于网络七层协议她更是专家中的专家

如果说网线、路由、网卡等硬件设备是我们之前所提到需要传输时架起的管子,那么作为程序员,我们更应该关注的问题应该是如何再错综复杂的管子之间找到要仍的那一根(要知道因特网连接的计算机是数以亿计的!),如何告诉对方我们要扔出物体了,如何扔出我们的物体,以及如何接到这个物体。以不至于东西仍错了管子误伤到无关的路人,或是东西已经扔到对方脸上,他还不知道是什么。或许真正的人不会那么迟钝,因为人是神奇的天作之合,最不可思议的大自然结晶,而计算机则不然,如果管子另一端是犹如计算机的机器人,那么你要是不以他理解的方式告诉他一下,真的就会砸到脸上都木有反应啊!

没错,将上面一段话用稍显学术点的话语总结起来就是,数据行驶在路由、网卡、网线、无线信号之上,而我们程序员要做的是在数据出发前,出发后,以及接收前和接受后所做的一切准备、判断、解释、执行、保存等工作,这些工作可谓繁多复杂,无规矩不成方圆,如果每个程序员都按照自己想法去编写,那么我想我在MSN上从这段发送一句你好之后,你在另一端可能看到的将会是我问候你家庭成员的肮脏语句,那么….后果将不堪设想不对么….为了避免这样的错误发生,为了让苍老师的种子总是可以安全的发送到下一位基友的手中,并且保证他下载的不会是金刚葫芦娃1080P的全集,于是众多的网络协议诞生了。

这里我们来深究一下,为什么网络协议要叫协议?这个名字让众多刚接触的人感到高不可攀,难以理解,简单来说,就是产生了虽但厉的赶脚!回到正题,为什么网络协议不叫网络黄金合体?不叫网络十万个为什么?不叫网络布拉布拉得痛呢?我们接着从现实的事物中来体会协议二字的意义,如果我现在接一个盖楼房的项目,那么雇主要跟我谈一个合同,从哪天到哪天让我去招工,哪天到哪天开始动工打地基,哪天到哪天盖楼,盖到什么时候结款。那么这样一个流程就是一个协议的达成。我们双方遵循协议的规定,按照协议中制订的计划一步步完成。如果我在招工的时候自己跑去挖地基了,挖地基的时候又想要开始收钱,那么雇主会一个嘴巴把我扇回去招人,等到盖楼的时候,我发现地基还没挖完然后挖掘机等机器已经不存在了,于是我只能带着我刚招到的工人用双手刨地基了。。。到最后就是整个工程被我弄得乱七八糟。没错,互联网协议虽然功能大相径庭,但是总的说来思路是一致的,我们该在什么位置做什么事,这就是协议所规定的,我们要做的是先按照需求选定协议,再按照协议的规范一步步将自己的需求完成,那么终于改说一下协议都有哪些了。

好吧,我们就先说一点我们平常常见的来举例。TCP、UDP、FTP、HTTP我相信这些名词大家早已耳熟能详,但是,我首先要提醒各位的是,别光看他们的名字都是XXP或者是XXXP,并且都名字后面都加上了协议就把他们归为一类,他们有着本质的区别,具体的说,TCP、UDP是同一类,他们是位于网络七层协议中的第四层传输层,再准确一点他们是完成第四层传输层所指定的功能,也是位于我们计算机编程人员所接触到的网络七层协议中的最底层(前三层由硬件构成),而FTP与HTTP他们完成的是网络七层协议中第七层也就是最顶层的应用层。还要提醒大家的是,虽然从字面上看第四层与第七层相距甚远,而实际上,他们的跨度不是很大,更并非风马牛不相及,相反他们是紧紧相连的,比如,FTP其实就是基于TCP/IP协议而实现的文件传输协议。

我们从深到浅从计算机网络是什么说到了网络协议是什么有哪些,接下来我们需要换个顺序,从浅到深,依次讲讲今天说到的这4个协议,第一个协议,我们先来说说我的诸位同事——php程序员们所最常接触的http协议。

Http协议,全称hypertext transport protocol, 中文名称是超文本链接传输协议他详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。他是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。他诞生于上世纪九十年代初期,最初被广泛应用的是http0.9,但是它最为知名并且被沿用至今的就是http1.1。

http的特点主要由以下4点较为突出。

1、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

2、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

3、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

4、无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。

简单的来说,http协议架起的就是一根用户和服务器之间的单向请求管道,用户可以随意向服务器访问,并且要求服务器返回数据,但是并不允许服务器通过相同的方式,向客户访问,这种机制保证了客户端与浏览器单次通话的效率,但是也存在着对于开发者而言不够便捷的问题,当然现如今我们已经可以通过很多技术手段来达成服务器的主动相应,但是,这并非http本身具有的特性。同时Http协议的连接可以理解为即时性的,他每完成一次操作请求,需要重新进行查找、准备、传输、响应、回传、关闭等这个流程步骤,而不能像tcp协议那样一次性连接之后可以持续的收发请求即时做出反应,等所有操作完成再关闭连接。所以,其实你在浏览网页的时候,输入一个网址或者点击一个连接都是重新向服务器发送请求并要求返回数据,这样的效率可以说从原理上来讲并不高效,但是现在我们可以通过诸如缓存等方式来减少这种操作的弊端。Http协议中总共定义了八种方法来表明指定资源的不同操作方式。也就是对某个网址下的网页,或者某个URL下的文件的八种不同操作。

OPTIONS

返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送”*”的请求来测试服务器的功能性。

OPTIONS请求方法的主要用途有两个:

1、获取服务器支持的HTTP请求方法;也是黑客经常使用的方法。

2、用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。

HEAD

向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。

客户端可以使用HEAD请求来收集相关信息以确定如何操作该资源.例如,在IE中,如果一个OBJECT元素缺少TYPE参数,浏览器就会发送一个HEAD请求,目标URL为这个OBJECT元素的SRC属性指定的URL.然后浏览器就能够根据响应中的Content-Type头知道这是哪种类型的OBJECT.

GET

向指定的资源发出请求。获取一个文档,大部分呗传输的浏览器的html,images,js,css,……都是通过get方法发出请求的。它是获取数据的主要方法

注意:GET方法不应当被用于发布命令,更新数据库,或任何明确的客户端动作。其中一个原因是GET可能会被网络蜘蛛等随意访问。

POST

向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。

关于GET请求以及POST请求的安全问题

所谓安全,意味着操作用于获取信息而非修改信息。换句话说,GET请求一般不应该产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。这里安全的含义仅仅是指是否修改信息。

接下来,POST的安全性要比GET的安全性高。注意,这里所说的安全性和上面的GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不做数据修改,而这里安全的含义是真正的Security的含义,比如通过GET提交数据,用户名和密码将铭文出现在URL上,因为登陆页面有可能被浏览器缓存,其他人查看浏览器的历史记录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击,虽然我不知道它到底是什么攻击。。。喜欢研究“如何不使用菜刀做菜而去杀人”的童鞋请自行百度“跨域伪造请求”。

PUT

通常用于向服务器发送请求,如果URI不存在,则要求服务器根据请求创建资源,如果存在,服务器就接受请求内容,并修改URI资源的原始版本

关于POST与PUT的区别

POST请求的URI表示处理该封闭实体的资源,该资源可能是个数据接收过程、某种协议的网关、或者接收注解的独立实体。然而,使用PUT请求对服务器操作的情况下,如果是要上传文件,则需要确定服务器上尚无重复的文件名,并且生成URI而后提交请求,如果该文件已经存在,则会出现被替换的情况,即使服务器做出判断判别出当前文件已存在,针对PUT请求,服务器也无法修改PUT请求当前所要操作的URI,智能拒绝用户的请求并且让用户重新发送该请求。

DELETE

请求服务器删除Request-URI所标识的资源。

在服务器接收到DELETE请求对某个URI的删除请求后,服务器并不会马上对其进行操作,即使客户端接收到的了200 OK信息的返回码,也只是代表服务器已经成功接收到该请求,具体操作则由服务器端完成。

TRACE(追溯)

回显服务器收到的请求,主要用于测试或诊断。

TRACE和TRACK是用来调试web服务器连接的HTTP方式。

支持该方式的服务器存在跨站脚本漏洞,攻击者可以利用此漏洞获得合法用户的私人信息。

CONNECT

HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器

以上就是Http协议的八种请求,也是通过http协议与服务器沟通的所有方法,如今http协议被大量的应用在万维网领域也就是我们常说的web开发之中,但不代表http协议只能使用在web端,比如手机应用之中,也存在很多使用http协议与服务器建立沟通的。比如比如百度地图API,新浪微博App,比如人人网手机端,比如我们的三姑……

首先,我需要感谢看官您读到了这里,这属实不易,我想如果您真的是用心读到此处估计会问,你洋洋洒洒写了2000多字的http协议,可它跟你之前所说的架起一根管道对仍实物的比方好像完全没什么关系,bingo!全中!就是这样,http协议的运作模式的确和之前的比喻不太相符合,如果硬要做一个比方的话,那么服务器就相当于棒球中的接球手,而客户端则相当于投球手,每次当客户端投出一个球之后,服务器都会告诉你这是个好球还是坏球,当然也有可能是被本垒打了。。。之所以要把http放到第一个还讲这么多,是因为它确确实实是我们在日常应用中最容易接触到的协议,比如你输入任何网址之前先打上的“http://”。好吧,让我们回到讲解http协议之前,也就是管道对仍物品的例子中,没错,接下来我们要说的就是与此例非常相近的FTP协议

FTP协议全称File Transfer Protocol,中文名称文件传输协议。它使用 TCP 生成一个虚拟连接用于控制信息,然后再生成一个单独的 TCP 连接用于数据传输。文件传输协议是TCP/IP网络上两台计算机传送文件的协议FTP是在TCP/IP网络和INTERNET上最早使用的协议之一,它属于网络协议组的应用层。FTP客户机可以给服务器发出命令来下载文件,上传文件,创建或改变服务器上的目录.

没错,就如同他的名字一样,FTP是专门用于文件传输的协议,而就像我之前说过的那样它的底层是基于TCP协议的。与http的模式不同,如果想要通过他来完成数据的传输,那么我们首先要做的第一步是先建立连接,而非直接对某个服务器发送请求。FTP有两种使用模式:主动和被动。主动模式要求客户端和服务器端同时打开并且监听一个端口以建立连接。在这种情况下,因为必须开放一个随机的端口以建立连接,当防火墙存在时,客户端很难过滤处于主动模式下的FTP流量。所以,创立了被动模式。被动模式只要求服务器端产生一个监听相应端口的进程,这样就可以绕过客户端安装了防火墙的问题。

 

一个主动模式的FTP连接建立要遵循以下步骤:

1.客户端打开一个随机的端口(端口号大于1024,在这里,我们称它为x),同时一个FTP进程连接至服务器的21号命令端口。此时,源端口为随机端口x,在客户端,远程端口为21,在服务器。

2.客户端开始监听端口(x 1),同时向服务器发送一个端口命令(通过服务器的21号命令端口),此命令告诉服务器客户端正在监听的端口号并且已准备好从此端口接收数据。这个端口就是我们所知的数据端口。

3.服务器打开20号源端口并且建立和客户端数据端口的连接。此时,源端口为20,远程数据端口为(x 1)。

4.客户端通过本地的数据端口建立一个和服务器20号端口的连接,然后向服务器发送一个应答,告诉服务器它已经建立好了一个连接。

被动模式FTP:

为了解决服务器发起到客户的连接的问题,人们开发了一种不同的FTP连接方式。这就是所谓的被动方式,或者叫做PASV,当客户端通知服务器它处于被动模式时才启用。

在被动方式FTP中,命令连接和数据连接都由客户端发起,这样就可以解决从服务器到客户端的数据端口的入方向连接被防火墙过滤掉的问题。

当开启一个 FTP连接时,客户端打开两个任意的非特权本地端口(N > 1024和N 1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交 PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P > 1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N 1到服务器的端口P的连接用来传送数据。

对于服务器端的防火墙来说,必须允许下面的通讯才能支持被动方式的FTP:

1. 从任何大于1024的端口到服务器的21端口 (客户端的初始化连接)

2.服务器的21端口到任何大于1024的端口 (服务器响应到客户端的控制端口的连接)

3. 从任何大于1024端口到服务器的大于1024端口 (客户端初始化数据连接到服务器指定的任意端口)

4.服务器的大于1024端口到远程的大于1024的端口(服务器发送ACK响应和数据到客户端的数据端口)

好吧,我知道以上这些虽然足够准确无误,但是它会让人感觉头晕目眩,什么是端口?哪来的PORT和PASV?让我们用通俗一些的话语来重新描述一遍整个过程。

首先,FTP下载模式的确立需要一个FTP服务器和一个客户端,主动模式中,客户端会按照指示找到一个FTP服务器,如果连接成功了,客户端会先向服务器端发送一个指令,这个指令包含的内容大致是你的所在位置。

接下来就像我们之前举的例子一样,当管道架到另一头之后,对方会告诉你,你的管道已经在我手里了,可以准备发东西了。此时的FTP服务器就会回头跟客户端打个招呼,“嘿,兄弟,你找到我了”,而当前这根管道并非我们用来互扔物品的管道,他用来传递一些命令,这就像你发了个不会上门送件的快递给朋友,与此同时你还要先打电话告诉他一下,“别忘了取邮局取快件”那么现在这根管道就相当于你的电话。你可以在其中传达各种信息及命令,比如你想要通过哪个物流来完成这次快递,顺丰还是圆通?再比如你要传输的文件是什么,以及你是谁等等等等。

还记得我们第一步中发给服务器的那个地址么?没错是你的地址,当服务器向你打过招呼后会紧接着向你之前所给出的地址发出一个连接,这个连接管道就是用来传输文件的管道了,而作为客户端在成功连接之后你也应该用同样的方式回头再打个招呼,“嘿,你真聪明,没错管道送过来了!”而这就是整个主动FTP连接的建立过程,在这之后你就可以与连接完毕的FTP服务器进行文件收发了。但是我们的过程中有个让人不太满意的地方,是的,当服务器想你的机器进行访问的时候,可能你还没接到管道,就被自己家的门卫给轰跑了,因为门卫觉得他来历不明,竟然还要想连一根管子进小区,没错像这样可恶的家伙可能你的防火墙门卫每天都会轰出去很多个~因为有很多家伙想在你不知情的情况下通过一根根管道在你的家中行窃!

当然问题都会又解决的方法,这就是被动FTP,它与主动FTP的不同的地方就是,你在连接服务器之后并不会发给他地址,让它直接来找你,而只是告诉他“嘿,伙计,我可算找到你了,等下哈,我马上把管道牵过来!”然后服务器就会乖乖的把一个约定地址回发给你,当然这个地址会与你刚找到他的那个不同,那是一个准备要简历传输管道的地址。接下来客户端要做的就是按照接到的地址再去连接一次服务器,这样传输的管道就架好了,同时你的门卫也不会像对待那些歹徒一样赶走服务器了。

好了,FTP就介绍到这里,或许我换了一种解释方法之后你明白了FTP是怎么运作的了,可是依然不了解什么是端口,没关系,接下来我们将要要更深入一层,解一下TCP/IP协议,与UDP一样它是位于软件所涉及到最低层的网络协议,而在这个过程中,我不只要告诉你什么是端口号,还要告诉你很多FTP和TCP他们最大的区别。

TCP全称Transmission Control Protocol中文名,传输控制协议 ,TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议。而我们之前讲到的TCP/IP准确的来说是不完全相同的,因为TCP只是一部分,而后续的IP是另一部分

如果你还听说过TCP/IP4,TCP/IP6的话其实别把他们之间的TCP分开看因为那是一个东西,不同的其实是IP4和IP6,IP4中规定IP地址长度为32,即有2^32-1(符号^表示升幂,下同)个地址;而IP6中IP地址的长度为128,即有2^128-1个地址。说实话我们或许不应该谈论太多关于IP的内容,所以我只把IP4和IP6之间的区别列出了一点,因为IP他更倾向于网络七层协议中的第三层,他的作用就是用于表示每台计算机,在一个局域网或广域网或任何一个网络中的物理地址,相当于一台计算机的门牌号,当然这是电子门牌号,所以设置与更换起来可能让你觉得没有实际的门牌号那么困难,起码你不用找有关当局申请或协商,但是作用其实是一样的——都是让别人来找到你的位置。

好了关于IP我们就说这么多,现在回头我们来说说TCP,前面说过,TCP通讯协议是面向连接的,可靠的,基于字节流的运输层通信协议,那么这一连串的名头都代表着什么?我们逐一讲解。

首先要说到的就是面向连接,说到这个名词我们就得说说与它向对应的一个名词面向无连接, 其实我们通过http与FTP就可以看出二者的区别,当然我这么说肯定会挨喷但是为了有助于各位理解我还是要说,http起码从操作上来讲,让你感觉,不管服务器是否开启,是否接受,我都只管发送我的请求,并不需要先向服务器确认什么,即时服务器是关闭的,没有启动的,或者是网络断开的,对于我们客户端来说该发送数据依然可以发送,当然不过是服务器接不到嘛。但是FTP则不然,我们在真正发送数据之前需要先跟FTP服务器进行连接通信,当一系列的通信完成之后我们才可以做一系列传输数据等工作。这就是二者的区别。但是我必须要澄清,Http协议的底层虽然不是全部,但是依然主要依靠TCP的面向连接来完成的,而真正面向无连接的协议是UDP,关于这方面的知识,有兴趣的童鞋可自行百度。

面向连接和面向无连接之间二者的区别我们理解了,可以确定的是,面向无连接协议传输速度要比面向连接的传输速度快很多,非常多,但也仅限于你的网络带宽之内,同时他还存在着很多不安因素,就像之前的比喻,如果我把管道加载一个机器人面前并且毫无前兆的就通过管道向他仍各种物品,那么结果就是砸到他脸上他都会置之不理。而再实际开发中,诸如此类的问题就如繁星一样,躲到你忘记几个都不会发现。。。所以说TCP协议是可靠的。

最后我们来说说什么是基于字节流的,字节我们很好理解,计算机中一切的存储内容,不论是内存还是内盘之中的存储信息都是通过01机械码来实现的,而每8位的01机械码所组成的就是1字节,以此向上的单位千字节就是KB,1024字节等于1KB,当然在不同系统下换算进制不一样,比如MAC系统下就是1000进制,而之后的MB,GM,TB我相信你们都懂的- -而流就是不包含边界数据的连续数据流,字节流我们从字面分析来看,一长串以字节为单位组成的不包含边界数据的连续数据流。

如果我们要使用TCP协议来传输数据的话就得先确认一个需要链接的对象,请注意我这里的用词,并非服务器也非客户端,没错TCP的连接建立,从协议本身来讲并没有服务器或者客户端一说,他只是将两个IP地址的计算机相连接起来,而我们需要的知识对方的IP地址,可是问题来了,或者我的服务器上并不只是运行一个服务器端程序,有人访问我的时候我该如何区分这些访问信息分配给不同的程序呢?没错,这里我们就用到了套接字socket它与我们之前总是提到的端口号密不可分。

socket的英文原义是“孔”或“插座”。作为4BDS UNIX的进程通信机制,取后一种意思。通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。常用的socket套接字有3种,而我们通过TCP协议所使用的就是流套接字(SOCK_STREAM)。而我们之前所说的端口号就是给予不同套接字所绑定的唯一的编号ID,取值范围再0-65535之间,而前1024个端口是被各系统所占用内部定义使用的换而言之就是我们在开发应用程序分配端口号是要分配编号在1024以上的。而我们之前再FTP举例中所提及的20端口号和21端口号就是特列,他们就是被系统所分配专门用于FTP传输的端口号。

通常一个基于TCP协议的客户端与服务器端的流程如下:

  1. 服务器程序开启,同时监听某个指定好的,大于1024的端口号
  2. 客户端启动,并且按照服务器的IP与端口号向服务器访问
  3. 服务器接到链接请求,链接接连成功,并且向客户端返回一个链接成功的返回包

以上就是一个服务器与客户端之间最简单的连接建立的过程。

在创建连接之后我们要做的就是开始收发数据,连接一旦创建第一件事情就是开启一个无线性的循环/等待的的过程,不论是客户端还是服务器端都要让socket不停的接收数据,哪怕根本没有数据。这样是为了再你需要向对方发送数据时,你只需要将需要发送的数据写入数据流,那么对方就可以读到你所写入的内容了,别高兴的太早,这一切并没有看起来的那么简单。

按逻辑来说在建立连接之后,除非手动关闭,否则连接理论上与程序逻辑中会一直判定为该连接存在,但实际上我们需要通过很多手段来确认连接是否正常。通常我们使用心跳包的方式来确认连接的正常性,所谓的心跳包就是每间隔固定时间,从客户端向服务器端发送的一个固定的数据包,服务器则会根据受到包的内容判断出这个数据包是个心跳包,同时也返回给客户端一个信息,以让客户端得知连接正常无误。以继续进行连接操作,又很多情况会导致程序逻辑上的连接状态与实际的连接状态不同,所以当客户端长时间接收不到心跳包的返回时我们就需要对程序的逻辑做出一定的修改,以避免严重错误的发生。

除此之外,我们还要判断数据是否完全发送/接受,而且对于数据的处理也会面临很多问题,因为TCP协议是基于字节流传输的所以数据并没有开头与结束之分,甚至如果一口气连续发送几个文件的话,我们在另一端接收到信息时甚至无法分清有几个文件?他们都多长?这些都不知道,只是收到了一长串很长很长的字节流。

就如上面所说的,使用TCP协议是通过系统最底层的网络传输协议来传输数据,如果说http协议和ftp协议是定义了如何接收信息和如何区分信息以及传输信息的格式。那么tcp完成的就是确立目标位置,并将数据统一化之后发送到目标位置。直接通过tcp协议进行开发可以达到最理想的面向连接协议传输效果,相对而言的我们需要付出更多的精力去编码,用大量的代码来维护链接的安全,在保证他的健壮性的同时,还要设定数据的分割以及接收的方式,等等等等,好吧,如果我说道这里你就觉得复杂了,我只想提醒你,后面还有UDP呢。。。。。。

好了今天天的内容就到这里吧。。。已经洋洋洒洒写了近万字。。。我如果非要把UDP也讲完,估计也没有童鞋能够看完了,对于UDP我已经不打算再此为大家继续讲解了,因为它的内容其实前面我们已经提得差不多了,而关于具体的详细内容,请有心得童鞋自行百度吧,我们下篇文章将介绍,如何在IOS系统下使用http和tcp两种方式的网络传输。好吧各位看官,我们下期见。

IOS、安卓IM语音聊天开发初探部分心得——本地音频处理篇(下)

前文书咱们说到IOS下如何录制一个wav格式的音频,然而现在的情况确实安卓不支持wav格式,于是有看官说了,你个二百五,就不能选个安卓支持的格式录制么,我很负责任的说,苹果和谷歌掐架,苦的就是我们这帮苦逼的技术人员。。。安卓的格式苹果全不支持,看好是全不,不是全部,反过来苹果的格式,安卓也不惯着。。。。

当然上有政策下有对策是万年不变的真理,Ios与安卓的音频互通是难不倒我们伟大的程序员的,而目前解决这个问题方案有很多种但大致以下3种方式,且听我细细道来。

第一种方案对于服务器负荷较大,不论是安卓端亦或是IOS端都将音频传输到服务器,通过服务器进行转换再进行转发。这种做法可以不受系统限制,但是信息量较大时对服务器负荷较大,对服务器端的要求很高。据传闻,微信就是采用这种方式进行的语音IM交互

第二种方案是不论IOS端还是安卓端都统一使用相同的第三方音频库进行编解码处理,然后再进行网络传输,优点是可供选择的音频库非常多,可以根据自己不同的需求选择各种各样的音频格式,但是因为不论是IOS端还是安卓端都需要对其进行i编码解码处理,而项目初期并没有设计这方面的需求所以如果双端都进行修改修改量实在太大。同样据传闻,同为语音IM的成熟案例微米就是依靠Speex的三方开源库来完成的,这种格式体积小,能降噪,是目前比较受推崇的方式。

我采用的是第三种方式,amr格式的音频文件是安卓系统中默认的录音文件,也算是安卓支持的很方便的音频文件,IOS系统曾经是支持这种格式的文件,自4.3以后才取消了对amr的支持(原因应该不需要我多说。。。),可见,amr格式的音频文件并非IOS处理不了的,因为有了这样的概念和潜意识的植入,我就开始一门心思在网络上找寻各种各样的实例以及demo,我要做的就是把问题尽量都解决在IOS端。终于功夫不负有心人,最终让我得以成功的在IOS端成功的转换出安卓端可以使用的amr文件。接下来,我们就说说如何在IOS端完成wav与amr文件的互转。

首先推荐给大伙提供一个demo在下面的连接下载。此demo转载自中国开源社区,本人发自内心的向发布者Jeans大人致以最崇高的敬意。

http://www.oschina.net/code/snippet_562429_12400

demo下载打开项目后将如下四个源码文件以及两个库文件拖入自己的项目,引用AudioToolbox.framework、CoreAudio.framework以及AVFouncation.framework即可完成类库的导入

打开我们导入的头文件就会发现有又大量的struct,而在开启ARC项目中是禁止使用struct和union的,而我们的项目确实可以开启ARC的,这里涉及到一个知识点,之前也在网络上看到有人提问在开启ARC后改如何使用struct,我也是接触这个项目之后开始涉及混编才了解该如何解决这个问题, 只要将Compile Sources As(设置编译源)的设置为Ojbective-C 或者将包含到声名struct和union头文件的实作文件的扩展名改为.mm就可以在项目中使用struct和union了,但是请注意此时你编写的代码不再是纯粹的Objective-C语言了,而是涉及到Objective-C ,此处涉及到混编的问题,我们再后面还会再讲解混编相关的内容,但并不会很多,感兴趣的看官可以自己查找资料。回到原题,如果在导入文件后遇到了编译错误,请点击项目的TARGETS下的Build Settings找到以下编译设置并按照图内容修改

注意,如果是新建空项目Compile Sources As的设置在According to File Type(依照文件类型选择编译源)的模式下应该也可以正常编译,尽量不要设置为Ojbective-C 进行编译,我是因为项目中含有其他的SDK需要用到所以才如此设置,一旦设置成Ojbective-C 会和我们之后讲的网络传输篇中所使用的SDK产生一定冲突很那解决。所以此最好保持According to File Type。

文件正常导入之后就可以直接使用转换方法了,和常规的SDK不同,这个库并非以累的形式封装的,而是数个功能函数,所以并不需要我们去构造对象,接下来我们说一下转换时具体用到的方法,虽然这些方法简单易用,但是我还是愿意为大家提供一点便利,所谓帮人到底送佛送到西,下面我每一个方法的名称、功能、参数说明以及使用示例贴出以供大家参考~。

哦~对了不要忘记,我们的第一步永远都是导入头文件

#import “amrFileCodec.h”;

接下来我们开始第一个函数EncodeWAVEFileToAMRFile从函数名称中就可看出,此方法是将WAV转换为AMR文件的,我们先来看一下示例

参数列表也并不是很复杂4个参数分别问:1.WAV的文件地址,2.AMR的文件地址,3.音频通道数,也就是我们上篇文章中所提到录制音频的最后一个参数,声道数量。4.编码位数,同样在上一篇文章中我们也已经介绍过不再赘述。

接下来第二个函数,DecodeAMRFileToWAVEFile这个参数与前一个功能正好相反,是从amr转换为WAV,下面是具体代码示例

这个参数可以说较上一个更加简单,第一个参数是需要一个AMR的文件地址也就是源,第二个参数则是目标地址也就是一个WAV文件的地址,简单的两个参数就可完成调用了。需要注意的是,此处所使用的地址和之前我们再使用AVFouncation的时候又不同了,它既不是要NSString的字符串,也不是NSURL对象而是一个const char的指针,但是这并不是问题,实例代码中所转换的方法并不是最简的只是急于演示所以拖拽出来的,希望有心的看官可以自行过滤,过眼不过心是编程大忌。

相对于导入可以说使用的方法简单的一塌糊涂,并不需要我们多少功夫,也没有那么高深莫测,但是测试还是要下一定功夫的,经过实机检测IOS下录制出的WAV转换为AMR之后放到安卓平台可以正常播放,而安卓录制的AMR文件拿到IOS下转换出WAV一样可以播放完全没有任何问题。但是这个方法也是有一定的弊端,音频转换的速度较慢,如果是时间较长的音频文件转换起来会有短时间顿卡,但是用来实现语音IM聊天是完全可以满足的

至此我们本地音频处理篇的内容全部完结,也算是告一段落,但是我们现在只是在本地机器上实现了正确的音频转换以及播放,想要完成语音IM聊天我们还差关键的环节就是与服务器的交互,详细的内容,我们将在下一篇文章中介绍,尽请关注IOS、安卓IM语音聊天开发初探部分心得——异步Socket传输篇

IOS、安卓IM语音聊天开发初探部分心得——本地音频处理篇(上)

最近的项目的内容开始涉及到一定的IM语音对讲的内容,而笔者从未接触过此类开发,也只是在摸索中一点点探索学习,几日下来略有了一点收获,以博客的形式跟诸位看官分享

先说明一下什么是IM语音聊天,IM全称Instant Messenger,即时通讯,简单的来说就是MSN ,QQ一类的聊天软件。而IM语音聊天即是使用语音音频来代替传统文字交流的方式进行沟通交流,目前市面上的语音IM根据聊天的方式又几种不同的方式,一种是即时发言犹如电话通信一样的语音通信,其中比较具有代表的软件有UCTalk,YY语音等,此类语音软件以PC平台为主,另外一种则是先进行录音之后发送形式与传统文字IM的形式略有相似之处的聊天方式,比较具有代表性的软件有微信,陌陌等,此类的语音软件大多出现在移动端,PC平台上同时也具有少量的使用。还有一种则可以视为介于两者中间的,模仿传统对讲机形式进行轮流发言的聊天方式,这种方式只在PC台上少量使用出现过,较前两者使用的范围比较小。

本次我们做的是移动端的项目,于是也难免于俗套使用先录制后发送的方式实现语音聊天,鄙人才疏学浅了解不深,所以可能是主观上的臆断,感觉以录制发送的形式实现的语音IM实现起来从技术将要简单很多,毕竟不会设计流媒体的问题。

既然是语音聊天难免涉及到一些音频相关的问题,笔者是负责IOS端开发的,所以大部分的内容以IOS角度为主,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,//Unsupported applications and demonstration versions

NSDeveloperApplicationDirectory,//Developer applications (/Developer/Applications)

NSAdminApplicationDirectory,//System and network administration applications

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

NSDeveloperDirectory,//Developer resources (/Developer)

NSUserDirectory,//User home directories (/Users)

NSDocumentationDirectory,//

NSDocumentDirectory,//

NSCoreServiceDirectory,//Location of 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:Most Significant Bit( 最高有效位),LSB:Least Significant Bit (最低有效位)你可以理解为一段数据再内存中的起始位置以及终止位置,大端模式就是MSB存放在最低端的地址上。而小端口模式就是LSB存放在最低端的地址上。

在Big-Endian中,对于bit序列中的序号编排方式如下(以双字节数0x8B8A为例):
bit | 0 1 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就把它的对象放入类内属性吧!

wav没错我们的成功的录制并播放了一个wav,就在你开心的时候你会发现一个问题,纳尼!?安卓不支持wav!!!这可怎么办?难道要让本来就少的可怜的用户还要永隔安卓与IOS的大洋两岸么!大丈夫!一切问题都会有解决方法的!但是,预知后事如何,请听下回分解~~~~~

对于百度地图API搜索请求,消息请求,线程控制等最新应用心得

内容可能较为散乱,皆是最近学习的一部分心得,记录下以备不时之需

首先是对百度地图API请求机制的一点理解。

百度地图API并非开源请求,所以针对于其内部机制,只是从使用上面一些猜的而已,如有错误,忘情指教

第一,百度地图的消息推送,百度地图API的消息推送并非之前所使用的一些API包是通过HTTP请求发送消息,应该是TCP/IP的消息推送,因最近再使用搜索功能再优化期间发现的一些BUG推断,当搜索对象在数次发送相同请求之后出现了crash而crash的原因通过百度查出可能是因为消息列队或socket阻塞引起的,而之前在其他项目上并未碰到过此类情况,所以推断可能是因为传输机制的差别而产生的

第二,百度地图的响应机制也略有差异,虽然同其他的网络应用API(如新浪微博,腾讯微博等)同样拥有相似的回调方法来处理请求结果,但是新浪微博和腾讯微博等采用的方式是可以自设回调函数,通过设置的回调对象和函数指针来实现消息回传,而百度地图则是使用协议委托的机制,遵从协议后完成指定的方法从而处理返回的结果数据,后者更加符合IOS惯有的程序理念,而二者各有优缺点,前者的优点是足够灵活,灵活程度几乎可以媲美弱类型语言,但是缺点也是对编写者要求较高,使用起来较为繁琐,并且上手的难度略为高一些,错误也容易出现,如果是自己完成可能还略为好一些,如果是团队协作就很容易出现各种各样的错误,因为通过函数指针调用的方法传参只能是id类型,对于数据的结构等错误理解,很可能导致很多不必要的错误,而后者则没有这些缺点,完整的参数列表,多参数的设置,可以让其他程序编写者很容易理解函数的意图以及使用方法,而缺点就在于过多的代码冗余再一起,当然可以通过调用多个方法将代码分离开来,但是始终是不够方便,再一些情况下过多的判断使代码看来很空洞,难以编写易于理解的代码。

第三,说说关于线程的操作,IOS中的线程操作十分强大简便,但是正是由于简便,很多时候反倒感觉到无从下手,改如何关闭以及怎样关闭线程,对于现在的我来说依然有些模糊,尤其是混入ARC机制之后更是时而让人摸不着头脑,就目前而言,我对大家提出几点使用线程的建议,如有错误还忘情指教,首先,线程套线程的操作应当尽量避免,可能是由于个人习惯的原因,我很多时候再开启线城时并非是使用NSThread,而是使用

performSelector…一系列方法(这个习惯可能很不好。。。由于没有老师教导。。。我只能自行摸索所以不敢妄言。。。),这种方式开启的线程,你无法得以全局的控制,所以也就不能像使用普通的NSThread对象那样取判断isCancel属性来对线程进行exit操作,而根据个人经验,如果在这种情况下,再去无限制的开启线程,那么你的线程数只能突飞猛进,到数十,甚至造成很多线程无法关闭,那么碰到需要再线程之中在开启线程的需求怎么办呢?我也遇到了这个问题,比如再使用自行封装的http请求类的时候,异步请求的回调函数中需要使用其中数据来开启新的视图或再次发送一个异步请求等,这种情况下如果保存到类内属性,则不知该何时开启视图,简单的通过延时调用来解决只是唯心主义的自我欺骗,不符合正确的逻辑观念,所以并不可取,我推荐给大家一个好的办法,就是将需要开启视图的代码封装成函数,然后这是通过performSelectorOnMainThread:withObject:waitUntilDone:方法将封装的好的函数运行再主线程上,这样,不论如何开启线程,都是在主线程开启,就可以关闭当前的子线程避免冗余的情况发生。

最后再说一个刚解决过的小BUG,这个BUG虽然解决起来容易,不过找出问题确花费了我不少功夫,BUG是这样的,再我们当前制作的项目中,一个提交订单的请求发送之后,会跳转到下一个界面,而在下一个界面经过一定时间后则会返回到之前的界面,如此反复的操作之后会出现的creash的BUG,经过反复查证原来是百度地图BMKSearch引发的BUG,BUG的起因如下:在下订单的界面中ViewDidLoad会创建视图对象并且对其设置,经过一番操作,跳转到下一个界面之后再次返回之前的界面,而此时的BMKSearch执行搜索操作时就会出现crash,而crash的原因可能是以下几种,第一可能是再下单视图推入下一层视图时被销毁,而回调委托找不到之前的对象而crash,第二可能是之前的delegate委托对象依然在执行中,线程并未正常退出,导致的消息列队阻塞,第三还可能是之前的Search对象已经销毁而且当前的对象并未重新设置过委托对象从而返回的消息无法正确发送给视图(因为调试过程中最后发现crash虽然可以避免但是会一直无法接收到百度地图的搜索消息返回),恕本人愚钝。。。暂时还不能给出正确的解答,但是可以肯定的是,通过重新设置BMKSearch对象的委托即可解决当前的Crash问题,算是以解燃眉之急吧。。。

以上是最近几天的探索心得,记录下来,一来与众看官分享讨论,二来以备个人日后学习参考备忘

如何才能在appstore发布你的应用 ——Xcode4.6原生ipa提交审核之最详尽步

经过几月的编码,终于在iTunesStore上提交了三姑微博的审核,之前处于破解框架开发状态下的我对于苹果对应用管理的机制可以说是两眼一摸黑。。。但是好在,在Chrome浏览器强大的翻译功能支持下,最终成功的提交了审核(虽然还尚未通过审核。。。)

其中在网上寻找教程的时候由于编译环境版本的差异,走了不少的弯路,为了避免后人同有此遭遇,遂书此文以供参考。但是在此之前我希望各位看官在开本文之前请先忽略它的长度,并且切记,这是个麻烦事,别怕费劲耐心的跟着我们做到最后你会成功提交应用的。

首先你需要确定你有一个mac系统的电脑,而不是虚拟机,从某篇文章上看到了略述此问题,如果是虚拟机可能会出现一些的问题,当然由于有着mac系统在手鄙人没有详细观看,需要此方面的资料的话还请百度。

其次,是素材的准备,

第一,图标:填写应用提交信息的时候,需要一张1024*1024的大图标,此图标需为jpg格式,DPI72像素以上,建议设置的更高些,150~200左右,72DPI的图标在你填写资料的时候并无问题,问题在于你缩小该图标使用在应用中的图标也有要求,必须为57*57像素,此时如果你的DPI过低,在iphone的屏幕上就会出现马赛克的现象,iphone对于图片质量的要求非常高。

第二,应用截图,对于应用截图的要求,苹果的要求具体是这样,3.5寸手机屏,4寸手机屏,以及ipad屏的截图三种截屏加起来只需要至少一张,也就是书你填写资料的时候保存的截图可以只有一张截图。而详细的情况是要看你的应用,比如你的应用支持3.5寸的手机屏和Ipad屏那么在准备截图的时候你就必须要准备至少两张。每种支持的屏幕一张。此处还有一点需要特别注意,就是在使用ios SDK6.0以及Xcode4.5以上的编译环境制作应用时,你会经常看到一个警告提示,此提示只要双击根据弹出的对话框就会自动解决,其解决方法就是在你的项目中加入一张名字为,Default-586@2x.png的纯黑色图片,请别忽略这张图片,如果你是使用的Xcode4.5以上的编译环境我建议你此时也检查一下项目中是不是有这么一张图片,如果存在这张图片,那么编译器就会认为你的项目是支持Iphone5的驴脸屏的,而换到当前要提交审核的情况下来说,你填写信息时是不会有任何错误提示的,在你上传Ipa后,并且你恰巧没有想要适应凤5驴脸屏的打算下,会发现你的应用状态并非在审核中,而是提示你缺少了素材,因为你没有上传凤5驴脸屏的截图。好在解决方法不难,只要删除掉这张让人不知该爱该很的Default-586@2x.png就好了- –

关于图像素材的准备,就到这里,可以了,我们接下来就到苹果开发者中心看看,一步一步的来提交我们的应用。后面需要的主要到的问题,我会在遇到时提醒。

好吧,现在如果你是一个破解了Xcode框架面证书时机调试,或者从开发之初就一直选择模拟器编译的家伙,那么恭喜你,你遇到的第一个问题就是,开发者中心在哪?我的天……太可怕了……我们原来还不知道要该在哪里工作,可应用已经都做出来了……没关系,打开百度,度娘会告诉你你想知道的一切,前提是,你发问的方式正确。告诉度娘,我们要去“苹果开发者中心”他会把你要去的地方显示在搜索结果中非推广链接的第一个。

现在我得提醒你一下如果你没有chrome浏览器,又恰巧英文烂的一塌糊涂,那么你最好现在先问问呢度娘应该在那下载chrome,否则打开了开发者中心你也会一头雾水,没错,全是你从上学起就恨之入骨的24个老朋友的规律编程集合体。什么?你说26个?好吧,管他呢,如果你用到了这里的帮助,我猜测你都应该和我有一个共通点就是跟他们20几位都不太熟。

为什么要用chrome浏览器,因为它的翻译功能是在太强大了!强大透了!百度翻译那种烂货完全没法相比的强大,基本上有了它的翻译你可以完全无障碍阅读整个苹果开发者中心的所有页面了。当然有的时候你也需要一些想象力……

好吧,我们来到了一个有点陌生的网站,恕我直言,如果你想要搞IOS开发或者是mac开发,那么你早就该来这了,多熟悉下没坏处,别跟着教程走,多去点点看看,反正有度娘,你可以随时再次找到主页。另外提醒您一下,如果你想在appstore上架您的应用,必须要有一个开发者账号,个人开发者账号99美元一年,企业账号299美元一年,如何申请,本博客内另有NickLiu大师的有文章介绍,所以此处不再赘述。

继续我们的步骤,点击主页的iphone开发者中心。当然这是翻译过后的内容,搞不定翻译的,请先别继续了后面更难,真的。。。

进入Iphone开发者中心之后请先点击网页上放一个蓝色的小按钮进行登录。在Iphone开发者中心里可有着最新xcode编译环境的和SDK以及各式各样的应用下载,你可以找到你想用的一切原生开发工具。为什么要说这个?因为如果你之前的xcode编译环境不幸的被你免证书调试修改了文件,你最好再下载一个新的编译环境。

接下来别忘了我们要干什么,没错上架应用。再网页最上方会有翻译过来的一个菜单,虽然它不太起眼,但是你找到它应该也不难,在此处打开会员中心。

接下来进入的网页会有6个主要项目,分别是,开发者中心,IOS的置备门户,AppStore的资源中心,iTunes连接,苹果开发者论坛以及开发人员支持。

此时我们先进入IOS的置备门户,此项下只有一个连接你应该不会搞错~

我们在此处需要创建证书、应用ID等,如果配置,在本博客NinkLiu大师的博文中也有所描述,但是我们这里说到的应该不太一样,别弄混了朋友,因为他只是要调试,我们要的是发布!

创建证书请求CSR步骤如下:

设置OCSP和CRL为关闭状态。

Mac OS 中,打开应用程序,找到 钥匙串访问(Keychain Access)工具打开主菜单- 证书助理(Certificate Assistant)-从证书代理请求证书(Request a Certificate From a Certificate Authority)输入iDP注册时的email,用户名自定义,选择“存储到磁盘”,选择‘Let me specify key pair information’。

选择保存路径,证书请求创建成功。
接下来就可以登录iDP Portal提交证书请求了,到这个页面
http://developer.apple.com/iphone/manage/certificates/team/index.action 

点Development,‘Request Certificate’,然后点Browser,添加刚才生成的证书,点submit。

点击Approve,一分钟后会生成一个.cer文件。

好的我们的证书创建完成了如果你还没能创建出你的证书,请百度其他证书创建的教程,由于时间问题,所以其实以上创建步骤笔者也是百度上复制粘贴而来……深感惭愧……

接下来我们回到IOS置备门户的主页。在左侧的菜单中点击“应用程序的ID”当然这也是翻译后的显示。打开后在菜单右侧的页面的右上角有着一个按钮上书“新的应用程序ID”没错你真聪明猜对了,点击它。

此处需要你填写两项,第一项是输入一个描述,这里随意,你记得是什么就好,但是只能输入英文字母别妄想使用中文了。

接下来还需要填写捆绑标识符,这里需要注意了,此处必须和你的项目中填写的唯一标识一致,就是在你创建项目时所填写的com.xxx.xxxxx,如果不记得也没关系,打开Xcode,点击你的项目—〉TARGETS—〉info—〉Bundle identifier的值便是我们要填写在此处的捆绑标识符,复制到此处粘贴。填写后submit提交。

再从左侧菜单栏点击“供应”,然后在右侧窗口中点击分配选项卡,打开选项卡后,在选项卡内部右上角,点击“新的配置文件”按钮,分配方法选择“应用程序商店”,在配置文件名称中输入一个名称,应用程序ID中选择刚刚创建的应用程序ID,点击submit提交按钮后创建完成,此时如果看到刚刚创建的配置文件的状态不是“活跃”的话就等1到2秒钟时间,再点击一下分配选项卡,刷新一次就好了。

此时需要创建的内容已经全部完成了,现在将刚才创建的证书、和在分配选项卡内创建的配置文件下载下来。,出于“活跃”状态后操作栏会出现下载按钮。

双击运行下载的文件,就会将证书和配置文件导入系统和xcode中,此时如果你使用过面证书编译的话,建议使用重新下载安装后的Xcode编译器。点击项目—〉TARGETS—〉Build Settings找到CodeSigning Identity选项,点击展开,找到和你刚刚创配置文件对应的选项选中设置。

点击Run按钮左侧的项目名,也就是选择测试设备/模拟器按钮的右侧,点击后会展开,选择Manage Schemes,点击左下角Edit按钮,在弹出的对话框中选中左侧菜单栏中的Archive。将Build Configuration设置为Release,点击OK按钮。在Xcode屏幕最上方的菜单栏中,打开Product菜单,点击Archive选项。此时编译器会开始编译项目,时间可能比普通运行时稍慢,不要着急请耐心等待。编译完成后,会自动打开Organizer窗口,并且显示你刚才编译过的项目。点击Distribute按钮,选择第二项,Save for Enterprise or Ad-Hoc Deployment.点击Next按钮,在CodeSigningIdentity选项中,选择对应的配置信息,然后点击Next稍时过后就会编译出ipa文件,并且询问你保存位置,放到一个好找的地方哦,一会要用到的。

回到会员中心,点击iTunes连接下面的“提交和管理您的应用程序在AppStore上。”在接下来的页面中,点击“管理您的应用程序”,在打开页面的下方找到“下载应用程序加载”的连接,好吧,此处chrome翻译的过头了- -,这是下载提交ipa的一个应用程序,可名称被翻译了- -接下来将会下载一个66.6M大小的dmg镜像文件,多么吉利的体积!下载完成后打开镜像双击其中的安装包进行安装。

安装之后,你需要打开你的mac系统盘符,如果找不到,点开Finder,然后点屏幕最上方菜单栏中的Finder,打偏好设置,打开边栏选项卡,将设备中的所有选项选中。关闭偏好设置,你会发现finder右侧中多出了一个XXX的“mac”选项,点中它之后就可以看到所有盘符,其中当然也包括系统盘符,打开系统盘符下的Developer文件夹,打开Applications文件夹,打开Utilities文件夹之后就可以看到ApplicationLoader.app这个应用了。他就是用来上传IPA的,但是现在别着急,我们还需要在iTunes连接也就是网上常说的iTunes Connect中创建应用~

回到网页中的“管理应用”页面也就是刚才下载ApplicationLoader的页面。点击页面右上角蓝色的addNewApp按钮,首先需要选择语言,然后填写您应用程序的名称SKU编号填写刚才我们填写过的那段com.xxx.xxxxx的那串标识即可,捆绑ID中选择刚才我们新配置的ID,,点击页面右下角Continue的蓝色按钮继续。选择上市日期、价位、等信息,请更具自己情况设置。设置完成后继续点击Continue按钮。此页面中所有选项请根据您的应用情况自行填写,如有不明白的信息,请点击后放的问号圆型按钮,即可得到提示,截图、图标等应用信息都在此处添加,注意事项前面已经说过,不再赘述,全部填写完成后点击右下方的Save按钮保存信息。保存信息过后你会发现自己的应用处于准备上传的状态,此时再次打开查看详细信息,在详细信息页面的右上角的Ready to Upload Binary按钮在询问信息项中按照您应用的信息选择单选按钮点击save保存,再点击Continue按钮回到应用信息页面,此时应用的状态时等待上传。

现在暂时最小化网页,我们回到MAC中继续操作。

打开Application Loader也就是刚才安装好的应用,登陆后点击DeliverYourApp按钮,在Choose下拉菜单中选择您刚刚创建的应用,起反应可能有点慢,因为MAC需要加载应用的信息,等待选择完成后,点击Next按钮继续。此时你就会看到自己应用信息了,点击左下角的Choose按钮,选择之前导出的ipa文件点击Open按钮打开。然后点击Send按钮提交应用,此时如果您前面操作无误即可等待应用上传完毕后去网页上查看你的应用信息,已经成为待审核了,如果上传ipa时出现错误,或者在应用信息界面出现错误,请详细翻阅本文提示内容,或经百度查询错误原因。

以上就是提交一个应用到appstore审核的全部过程……没错这的确有点长…4000多字的文章我纯手打出来也不易…现在我已经被累得一个字都不想多打了…诸位我们今天就到这里,再见吧!

12