美稍纵即逝

6月思摘

6月思摘,即6月的思想摘要。

1.最近读了一点《定位》,没看完。说一点自己的一方面的理解。做到第一很重要,人们能记住的东西很少,一般人的大脑最多能同时记住5到7个左右同类东西,消费者在进行商品选择的时候,从感知角度和选择角度来讲,第一都具有天然的优势。人们不会记得第二,或者有第一这个更好的选择的时候也不会选择第二。第一是一种心智上的胜利,第二的产品未必是比第一差的,但是在消费者的心里贴着第一标签的产品是比第二的产品好的。定位从某种角度来说就是找准一个位置,能让自己做第一,无论是定位自己,还是定位对手。
另一方面,我联想到了《长尾理论》,想到长尾,是觉得这个和定位直接来看似乎是有一些冲突的。长尾理论强调后面的非第一的产品也有很大市场。摘录一段《长尾理论》的话:“我们的文化和经济重心正在加速转移,从需求曲线头部的少数大热门(主流产品和市场)转向需求曲线尾部的大量利基产品和市场。在一个没有货架空间的限制和其他供应瓶颈的时代,面向特定小群体的产品和服务可以和主流热点具有同样的经济吸引力。”。细想一下,又觉得这正好是定位存在的理由,长尾在一个细分市场里找准定位,做细分市场里的第一。

2.最近读了一点《精益创业》,没看完。说一点收获,精益创业讲究“经证实的认知”,我觉得这个词特别好。很多自己认为正确的认知很可能是错误的,只有亲身证实才会有更准确的认识和体会,也才会带来“信念飞跃”。精益模式有一个过程循环,开发——测量——认知,精益模式讲究尽量加速这个循环,首先产生最小化的可行性产品(MVP),然后不断改进。这个精益的很多东西,感觉和敏捷的概念很像。当初看敏捷更多关注的是执行,而现在看精益更多的感受是获取“经证实的认知”。另一方面,“执行”,空谈误国,实干兴邦!
最后摘录几段《精益创业》里的话,未必是最好的,只是有幸被我存下来的。“计划和预测只能基于长期的、稳定的运营历史和相对静止的环境,而这些条件是新创企业所不具备的。”,“我们认为,我们的工作就是要让企业愿景和顾客接受度相匹配”,“我还不知道这东西酷不酷,你就要我冒冒失失地随便请个朋友聊天?他们会怎么看我?”她说,“如果这软件很烂,他们会觉得我很蠢,不是吗?””,“如果他们的计划是“看看会发生什么情况”,那么准保成功,因为他们一定会看到发生的情况,但却并不一定能获得证实的认知。这是科学方法中的重要一环:如果你无法失败,就学不到东西”,“为了规避风险,以免开发多年之后才恍悟产品没人想要,休斯顿使的一招出乎意料的简单:他拍了一段视频”。

3.最近觉得书应该慢慢看,看个一年半载的,这样这个书传达的东西在这段时间一直影响着你,这样经过无数个21天,你就被影响的越深,从观念到行为。以前看书太快,闲来无事乱翻书,看的时候挺爽,很快就看完了,然后看完就忘了。虽然对观念上可能也影响,但是不会对行动上有什么改变。

4.应用面对的需求是各种各样的,游戏面对的需求似乎是一样的,就是娱乐。没细想,不知道对不对。还有娱乐是刚需吗?是个奇怪的问题吗?

5.山寨会带来一种信念,就是这能行,看那大红大紫的可以,我这也可以。当然,由于品质和热度消退等问题,这事未必能行。完全的创新对用户有认知风险,对开发者可能有一种不安,短期内如果没有收获,很可能中途放弃,缺少了一种这能行信念。完全的创新,开发者也可能有一种强力的信念,他会认为他在“改变世界”。山寨还是创新?创新的山寨是微创新吗?

6.翻看了一些热门微博,总结了一下微博上比较火的一些点。近期大片,中国明星,外国明星说句中国话,人生、青春有关,国情问题,社会新闻,段子,趣图,心灵鸡汤,小知识。

7.社会化营销很重要。

日期:2013.06.30
标签: 思摘 读书笔记
分类: 生活杂谈

常用Android开源库,加速Android开发

ActionBarSherlock,https://github.com/JakeWharton/ActionBarSherlock,现在几乎是做符合4.0风格应用必用的库了,很多应用都在使用。ActionBarSherlock是基于Google官方出的support library之上的,提供了更多兼容性的解决方案,主要是ActionBar之类的。该库的作者也开发了其他的几个不错的库。

比如Android-ViewPagerIndicator,https://github.com/JakeWharton/Android-ViewPagerIndicator ,提供了丰富的ViewPager指示器。截图如下。也有大量应用使用这个库。

https://raw.github.com/JakeWharton/Android-ViewPagerIndicator/master/sample/screens.png 

还有一个NineOldAndroids,https://github.com/JakeWharton/NineOldAndroids ,是提供了在低版本的Android手机上使用3.0提出的新的Animation的API,很不错。但是就我之前的使用经验来讲对于2.x的设备上,兼容性还是有点问题。

SlidingMenu,https://github.com/jfeinstein10/SlidingMenu,类Facebook的侧滑菜单,现在很多应用使用。  

Android-PullToRefresh,https://github.com/chrisbanes/Android-PullToRefresh,下拉刷新,不多说。  

android-async-http,https://github.com/loopj/android-async-http ,网络请求是大部分应用都会用到的,网络应用一般都是异步的,自己每次写网络请求的应用,都在自己封装一堆东西。这个库提供了异步回调方式的API,简单,好用。

Android-Universal-Image-Loader,https://github.com/nostra13/Android-Universal-Image-Loader,极强的图片异步加载库,简单,好用,也是很多应用在用。

其它的还有很多,列举的这些开源库,基本上现在很多应用都会用上一两个。近些日子,空闲的时候写了几个简单的应用,有的应用基本用了个遍。有了这些,开发一些简单的应用真实大大的提速,生产力迅速提升。 用不着的话,都是开源的,研究研究代码也好。

日期:2013.05.28
标签: Android
分类: 技术研究
0 Comments

Socket网络编程

本文主要简介TCP、UDP协议和Socket编程模型。

做网络编程肯定要和TCP或者UDP协议打交道,有时候我们可能用过相应封装好的类,却不一定知道底层的实现。TCP或者UDP详细讲起来可以讲两本书,有一套很有名的书《TCP/IP详解》,内容很丰富,介绍了方方面面。本文以介绍TCP为主,主要介绍TCP建立连接和连接关闭的步骤。次要提及一些相关知识。

先说最基本的TCP与UDP一个最大区别是,TCP是面向连接的,而UDP不是。进而TCP是可靠的,当然还有其它一些机制保障,UDP是不可靠的。也显然TCP因要建立连接,所以更加消耗资源,速度也会较UDP慢。各有优缺点。大名鼎鼎的HTTP协议是建立在TCP之上的,还有很多也是在TCP之上。当然UDP也有很多它的使用场景。

因TCP比UDP复杂,所以一个TCP包的头占用的字节显然会比UDP多。下图分别是UDP和TCP的包结构。

接下来介绍一下TCP建立连接和关闭连接的过程。(http://robinjie.iteye.com/blog/289843)

首先是建立连接,建立链接俗称三次握手。

第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

然后是关闭连接,也可以称为四次挥手。

1.任何一方都可以主动终止一个连接。主动断开的一方发送FIN。

2.当被动关闭的一方收到FIN报文时,它会发送ACK确认报文。

3.被动关闭在应用层准备关闭的时候,发送FIN报文。(有时候,被动关闭端会将ACK和FIN两个报文合在一起发送。)

4.主动关闭端收到FIN后发送ACK,然后连接关闭。

整个流程还是较为复杂的,有的时候我们可能需要知道一些TCP连接当前是什么状态,可以通过netstat命令来查看,这个命令会显示TCP连接当前状态,很是好用。

 

下半部分是Socket编程的介绍。Socket编程是建立在TCP或者UDP协议上的,发送的数据包就是TCP或者UDP的包。纯粹的网络的编程是使用Socket技术的。比如可以使用Socket来编写服务器软件。

关于Socket网络编程的模型,我在网上找到了两张图片,较好的说明了编程的流程。图片如下,分别是UDP编程流程,TCP编程流程:

 

 

Socket编程的过程中涉及到一些参数,比如SO_RCVBUF,SO_SNDBUF表示接收和发送的缓冲区大小。

 

之前和室友分享的ppt:


日期:2013.04.29
标签: socket 网络编程 tcp udp
分类: 技术研究
0 Comments

B-树与Sqlite数据库

B-树和数据库还是春节前研究的,现在回想起来,很多细节都要耐心的细想。还好有若干索引,所以说索引真的是个好东西~ B-树是一种常用的索引数据结构,B-树不是二叉树,比二叉树要复杂一些。中文维基百科上是这样写的: “在计算机科学中,B树是,存储排序数据并允许以O(log n)的运行时间进行查找,顺序读取,插入和删除的数据结构。B树,概括来说是一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同,B-树为系统最优化大块数据的读和写操作。B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。” B-树有一个变形是B+树,数据库索引用到更多的是B+树。关于B-树和B+树的具体定义和查找,插入,删除等操作,可以参阅相关的书籍或者文章。查询是B-树的目的,插入,删除操作都是要保持B-树的性质。 之前花了一些时间,写了一个B-树的实现,网上没有找到什么好的实现,所以自己写了一个,也加深了对B-树的理解。实现的很丑陋,代码在:https://gist.github.com/5226953 数据库为什么要用到B-树呢? 我们都知道数据库查询是数据库使用的主要场景,查询效率是数据库性能指标的一个重要因素。查询的话,最基本的方法是循序遍历,当数据量很大的时候,这样效率当然很慢。再者是二分搜索,虽然时间复杂度变成O(logn),但是这样要求数据有序。另一方面,查询的条件可能很复杂,使用传统的方法效率会更加低效。使用索引可以加快检索的过程,索引就是把关键码与对应数据的位置相关联的过程。检索的过程,由直接检索数据,变成检索索引,然后定位数据,这样设计好索引就会大大加快检索的过程。 索引也有好多种,为什么数据库要用B-树及其变体B+树呢? 这个和磁盘的访问有关,我们知道,数据库存储的数据文件是在磁盘上的,而且数据量很大,一般相关的索引也会很大,所以索引也是存在磁盘上的。我们都知道访问磁盘比访问内存速度相差非常多,所以磁盘IO的性能就不能不考虑了。B-树正是满足了减少磁盘IO次数的需求。这里提到的磁盘是指传统的机械磁盘。 数据库设计存储索引的时候,会按页存储,读取索引的时候,会一次读取几页,由于磁盘也是在读取的时候会预读,每次读取都是按磁盘扇区大小来读取到内存中的。这样数据库读书数据的时候就会更有效。另外,B-树比其他树的有点在于树高会矮很多,因为B-树在每节点都可以有很多元素,这样随着树深的增加,下一层子节点的数量成指数级别增长。所以树高会较其它树小,这样在检索的时候,为了找到元素,从树根找到叶子节点就会减少很多访问外存的次数。另外B+树只在叶子节点存储实际键值,虽然增加了深度,但是增加了插入、删除的复杂度,切B+树由于所有键值都在叶子节点,所以对范围查询支持更好。 关于B+树在外存访存的分析上《MySQL索引背后的数据结构及算法原理》这篇文章写的很好,强烈推荐看看一看。 B-树具体到文件中是怎么存储的呢? 我们知道了,数据库索引使用的B-树,但是到底数据库是怎么实现的呢?为此,我研究了Sqlite数据库。这个号称最简单的数据库,在我看来也是极其的复杂的,我抽取了几部分作为研究。主要看了Sqlite的文件存储格式。 Sqlite是采用单文件存储的数据库(为了事务,异常恢复等会有多余的日志文件)。文件的格式设计官方有个文档:http://www.sqlite.org/fileformat.html。 这个文档详细说明了sqlite数据库文件的存储格式,包括文件头规定,Page页的设计(包括表内部页、表叶子页、索引内部页、索引叶子页),Page页的头规定,Cell单元Payload的设计等等。 国人有个分析的文档,写的很详细:http://vdisk.weibo.com/s/r1VK3,可以参阅。 这些东西展开说,都要费些时间,花些脑筋,就不写了。我模拟Sqlite的文件格式写了一个简化的数据库引擎的部分,之前写的,还没有完成,实际写起来还是很是费劲的,文件的读写操作就很麻烦,比操作内存要麻烦很多。 最后,再重新推荐一下这两篇文章: MySQL索引背后的数据结构及算法原理 SQLite文件格式分析 还有一本书: 数据库系统实现      
日期:2013.03.23
标签:
分类: 技术研究
0 Comments

Java内存管理和垃圾回收

最简单的,Java可以通过new关键字来申请分配一块内存。例如:Object obj = new Object();变量obj是这个内存对象的引用。同时Java对于引用引入四种类型,分别是:强引用,软引用,弱引用,幽灵引用。前面这个obj就是个强引用。其他三个引用分别对应三个类SoftReference 、 WeakReference 和 PhantomReference。从垃圾收集角度考虑,强引用在引用存在的情况下是不会进行内存回收的,SoftReference在内存不足需要回收时是可以被回收的,WeakReference每次来及回收的时候都是可以被回收的。 那么,为什么要进行垃圾回收呢?如若不进行垃圾回收,不断的进行内存申请分配,内存容量是有限的,则会造成内存溢出。那么内存都在哪些区域分配的呢,哪些区域又会造成内存溢出呢?来看下面这张图,这是网络上面的一张图画,看到运行期数据区是内存非配的区域。分为:方法区,Java堆,Java栈,程序计数器,本地方法栈。 jvm内存非配 通常,我们所说的内存溢出大部分是Java堆部分。Java栈也会造成内存溢出,常见的例子是递归调用方法造成死循环,这个时候会造成内存溢出,这和Java方法调用过程有关。Java堆部分则是前面所说给对象申请分配内存,内存不足导致的内存溢出。内存溢出也就是常说的OOM。 写C,C++的程序员都知道要自己申请内存空间,然后自己小心的释放。这种手工管理内存的方法,由于马虎大意很可能出现纰漏。Java采用了自动垃圾收集的方式,解放了生产力。那么Java的垃圾回收是什么样的呢? 要回收垃圾,首先要找到垃圾所在地,最简单的方式是引用计数方法,一个对象每增加一个引用增加一个计数,反之减少一个计数,当计数是0的时候,我们知道这个对象是不可达的,所以可以安全的将这个对象的内存释放。但是引用技术存在一些问题,比如常说的循环引用问题。另一种方式是对象引用遍历方式,Java采用的就是这种方式。如下图所示。“对象引用遍历从一组对象(GC ROOT)开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。 ” 对象引用遍历 找到了垃圾那么怎么回收呢?有几种方法,如标记-清除,标记-压缩,复制。对应示意图分别如下: 标记-清除,就是标记的那些不可达的对象内存区域直接释放,优点是是速度快,缺点是内存碎片多。 标记清除 标记-压缩,就是那些可达的对象内存区域重新排列,整理成顺序区块。优点是没有内存碎片,缺点是速度慢。 标记压缩 复制,内存区域分两半,一半不使用,当使用的那半用满需要收集的时候,将分配的单元复制到之前没用的那一半,然后以此类推。优点是速度和内存随便达到了较好的平衡,缺点是浪费空间。 复制 那么到底使用哪种方法呢?对于Java虚拟机而言,对于不同的分代和不同的版本的垃圾收集器往往采用不同的方法。Java虚拟机采用分代垃圾收集机制。如下图所示: 分代垃圾收集 分为三代,分别是年轻代、老年代和持久代。 “年轻代:所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。 年老代:在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。 持久代:用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。 对于实际的java虚拟机又有很多版本,简要罗列一下,分别有:Serial 最基本,最古老的收集器 ,新生代复制算法,老年代标记整理算法;ParNewSerial多线程版本(新生代) ;Parallel Scavenge;Parallel Old (Parallel Scavenge老年代版本) ;CMS(Concurrent Mark Sweep);G1(JDK1.7)。此处需要一些注意说说明,传统早期的GC(垃圾收集)需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止,只有GC运行。 对于并行的GC,多个线程同时进行GC,其它线程仍然需要停止。对于的并发GC,实现复杂,其它线程最短时间的停止。
日期:2013.02.17
标签:
分类: 技术研究
0 Comments

写一个游戏

大学以前玩了很多电脑游戏,花费了不少时间。之后就没怎么玩游戏。以前更没有想过制作游戏,大一那年学了C语言,第一个课程设计恰好是个游戏——打砖块。感觉写游戏比较难,而且这个游戏还属于即时类的,意思是说游戏程序在“无时无刻”的计算和绘制。这个程序当时花费了我不少时间,折腾了一个月才搞定。

现在写了一个Android版本,功能可能没原来的多,时间总共只用了几个小时,而且这里面的很长时间花在了数学和物理知识上,比如正弦余弦函数的性质,动量守恒定律等等。新的游戏程序保留了原来的配色,交互上使用了移动设备特有的加速传感器来控制移动下方挡板。

Linus说“Talk is cheap. Show me the code.”。(其实我是主要觉得没啥写的)

代码地址在这里:https://github.com/qhm123/hitblocks

代码写的可能并不漂亮。代码结构是依照android自带的lunar那个游戏的结构安排的。

写完后还看了一下以前用C写的那个代码,想想当时的水平,觉得写的还成。当时还隐约的分了mvc三层架构,有做动态适应屏幕尺寸等,代码对齐也比较良好。多亏了那时有大神指导我。缺点是看到不少重复代码,变量和函数命名有的不是特别好。

最后记录几个细节:

游戏View用的是SurfaceView,这个可以在工作线程中更新canvas然后一次绘制出来。mSurfaceHolder.lockCanvas(null);mSurfaceHolder.unlockCanvasAndPost(c);。

工作线程通过handler给主线程发送消息。

可以通过Region做一些碰撞检测。

Sensor传感器使用SensorManager.SENSOR_DELAY_GAME参数。

 

最后,写一个游戏。

 

日期:2013.01.28
标签:
分类: 编程实例
0 Comments

PhoneGap非编译式打包

写过Android或者iOS应用的都知道,一个应用的诞生都需要经过编译这一步,PhoneGap是基于Android和iOS等之上的,常规的方式也是需要将代码编译,才能产生对应的安装包。大多数情况,编译过程会消耗相对较多的时间,对于Android平台为了代码安全性的考虑,有的时候会进行代码混淆,这更加增加了编译代码的时间。并且对于iOS,编译必须在Mac平台上进行。基于上面一些原因,我们需要寻找一种不需要编译过程的打包方案。 对于Phonegap应用,Android和iOS平台的源码文件都在www目录下面,从某种角度来说他们是静态的资源文件,我们基本上对应用的更改都是改动www目录下面的文件,他们是不需要编译的,对于文件的更改,只需要简单替换掉相应文件就行。这样就很容易想到,对于Phonegap应用,其实我们可以将原来的包解包,然后替换www目录下的文件,再重新打包。这就引发了两个问题,原来的包如何获得,如何解包和重新打包。有的时候我们还需要替换应用的icon,名字等,这些东西如何替换? 首先,我们先来看看通常的一个打包的流程是怎样的。对于各个平台大体流程应该都是一样的,编译代码,资源文件处理,压缩成一个文件,这个文件也就是最后的安装包了。我分两部分来做说明,依次介绍Android和iOS包结构和打包流程。 对于Android打包的流程还是很复杂,经过若干步骤,有兴趣的可以参看一下我以前写的有关Android打包流程的内容:http://t.cn/zjMXqkx。简单说来,还是刚才的话“编译代码,资源文件处理,压缩成一个文件”。 再来看看这最后生成的一个文件具体是什么样的,Android生成的安装包是apk包,其实这是一个zip压缩包,解压缩后可以看到里面的文件,里面有AndroidManifest.xml,这个是整个包的描述信息,包含包名,应用名,版本,icon等信息。还有assets目录,这个目录下面就是www目录,也就是PhoneGap用到的最重要的代码的目录。还有res目录,里面是一些资源文件,如icon等。还有classes.dex文件,这个就是Android编译后代码生成的文件。对于我们的需求,替换PhoneGap的www目录文件,很容易实现了,而对于替换应用名、icon等,就替换AndroidManifest.xml文件和res下的对应的资源文件就好了。 于是思路来了,先用unzip把包解开,然后替换相应文件和文件里的变量,最后再用zip把包压缩。这样可以吗,实验表明不可以,这里面有很多问题。首先AndroidManifest.xml是被压缩成二进制的,无法替换变量。再有,使用zip工具再压缩为apk文件后是无法在Android手机上运行的。还有压缩的包可能需要重新进行包的签名。另外直接替换像icon这样的资源文件,再打包也是不行的,apk里面的资源文件也是都必须经过压缩处理的,否则即使后面打包签名正确,也是无法在Android上面运行的。 正确的思路有两种:一种是采用原来正常的打包流程,在正常流程编译好classes.dex文件后,暂停。保留当前这个状态的所有文件为模板,然后对www文件和AndroidManifest.xml,res等相关文件替换,然后继续之前未完成的正常打包流程,资源文件处理,压缩成一个文件。这样每次就跳过了编译的过程。 第二种是使用apktool,apktool是一个反编译apk的工具,我们可以利用apktool将apk解包,然后替换文件,再用apktool打包,然后使用jarsign进行签名。使用这种方式对于不了解apk打包机制可能更容易理解一些。这种方法的好处是,你不需要清楚Android打包流程,逻辑上是“解包-更改-打包”的思路,更容易理解。 后来,我又想到可能更好的方法,最早我们的做法是把一个Android的Project作为模板,然后每次收到打包任务的时候,就把这个模板拷贝到一个工作目录中,然后把外来的PhoneGap用到的www目录放到这个模板中,然后打包。其实Android打包的过程是有类似于cache的机制的,或者说是增量编译,对于没有更改的地方它不会重新进行操作,比如编译代码。如果你的代码没有变更的话,它是不会重新编译的,由于之前每次都把这个模板拷贝出去,所以每次打包都是一个全新的包。这个新的想法是,工作目录存放这个模板,而不是每次打包的时候拷贝一份新的,这样的话就会节省一些步骤,从而减少了打包时间。 方法其实还是很多的,每个方法都可以work,没有对错之分。我自己更喜欢后来想到的和第一种方式。但是当时采用了第二种方式,这种更接近于hack的方式,不是很美好的方式。这有点像最近热映的电影少年派一样,第一个更加美好,但现实可能是第二个。 对于第一个和第三种方式写过一些测试,后来是懒得写出完整的代码了。于是尝试在第二个的基础上稍作更改,做了一个更适合个人使用的版本。最后会说道。前面跳过了很多细节,写的也不详细,只提供了一些思路,具体实现可以参考这个开源项目的代码。 再来说,对于iOS的ipa包的打包流程。其实我对iOS并不十分了解,大概了解了一下ipa包的结构。其实ipa包就是一个zip压缩包,解包的话就unzip,打包的话就zip就可以了(一个限制是生成的是未签名的ipa包,只能越狱安装),非常简单。对于压缩包里面,是一些层级目录。包里面有个Info.plist文件,描述了包的信息,如包名、应用名、版本、icon路径等(对应Android里面的AndroidManifest.xml文件),还有一些资源文件,如icon等,还有代码编译后产生的文件。www目录也在里面。替换PhoneGap的代码就把www目录下的文件替换掉就好。对于应用名称,版本号的替换,就是替换刚提到的Info.plist文件里面的内容。这里有个小细节,就是用xcode生成的ipa包里面的资源文件都做了压缩处理,Info.plist等文件处理成非文本文件,这样进行变量替换的时候就麻烦了一些,其实使用压缩前的纯文本Info.plist也是可以的,这个包是可以正常运行在iOS设备上的。 最后说一下这种方式的缺点,最大的缺点就是缺乏扩展性,不支持动态增删PhoneGap的插件,模板底包一旦生成,插件就固定了。 新浪移动云的打包平台大体上基于上面的思路,然后提供了封装了web的api接口,对内提供了打包服务。现在基于上面的思路开源了一个更加轻量级别的个人PhoneGap打包工具,里面的模板是基于新浪移动云平台的,开源在了github上面,有兴趣的可以去看看。https://github.com/qhm123/PhoneGap-Packager
日期:2012.12.05
标签:
分类: 编程实例
0 Comments