make a little difference

[置顶][转载]关于性格内向者的10个误解

日期:2012.02.05
标签: 转载 心理
分类: summary

[置顶]Micolog部落——一个Micologer的聚集地

日期:2010.11.09
标签: micolog 个人项目
分类: what

Fedora16_x64编译Android4.0.3源码

这个勉强算是How,但是我无法准确的说出Fedora16编译Android4.0.3源码的整个过程,按步骤一步一步的该怎么做,因为我的编译过程是跌跌撞撞的,并且一些细节我可能现在写的时候也忽略甚至遗忘,我只是想分享编译Anrdoid源码过程中遇到的一些问题的解答,官方给出的编译流程对于Linux是针对Ubuntu发行版的,Fedora细节上有一些不同,以下内容大多并非原创,只是摘自网络,大多来自android-building group,更多问题或许可以在那找到答案。

准备工作,在编译源码之前,建议还是到andriod open source project上去看看,那里可以了解到一些基本的知识,尽管实践起来Fedora的一些细节可能不同,但是对于一些注意事项,基本的理解还是有好处的。另一方面,建议不要下载最新版本的android源码,而是下载稳定的branch,比如android-4.0.3_r1,这样可能会更顺畅一些。

在编译之前我们需要做一些准备,下载必要的开发包,这个链接http://rootzwiki.com/topic/8037-compile-android-on-fedora-1516-by-xoomdev/,说明了针对Fedora发行版的Linux操作系统该怎么做一些准备。

我简要叙述一下,

下载sun-java-jdk6,注意一定不要使用openjdk,如果使用openjdk之后的编译会出现问题。

cd ~/Downloads
sudo sh jdk-6u27-linux-amd64.rpm
sudo ln -s /usr/java/default/bin/javah /usr/bin/javah

然后安装必要的开发包

sudo yum install -y zip curl gcc gcc-c++ flex bison gperf glibc-devel.{x86_64,i686} \
zlib-devel.{x86_64,i686} ncurses-devel.i686 libX11-devel.i686 libstdc++.i686 libsx-devel \
readline-devel.i686 libXrender.i686 libXrandr.i686

sudo yum install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev \
gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev ia32-libs x11proto-core-dev \
libx11-dev lib32readline5-dev lib32z-dev libX11-devel.i686

然后安装make3.81,(注意,Fedora16的make是3.82,编译Android会出现问题,所以需要降级安装3.81)

sudo yum downgrade make --releasever=13

但是按照这种降级方法我也没有安装成功,最后我选择了下载3.81版本的源码自己编译安装的,方法

http://www.gnu.org/prep/ftp.html下载"make-3.81.tar.gz到/tmp目录

su
cd /usr/local
tar -zxvf /tmp/make-3.81.tar.gz
cd ./make-3.81
./configure
./sh build.sh
./make install

然后配置PATH环境变量

PATH=$PATH:/usr/local/make-3.81 
export PATH

(当然为了永久生效,可以放到~/.bashrc)

但是这样并没有好,Fedora16上一些包的版本和Android源码不太兼容,需要对Android源码作出一些更改,https://groups.google.com/forum/#!msg/android-building/gIC_t7GXzQ4/1l7Se9Mb910J这个链接给出了大部分方法,

1. in ./build/core/combo/HOST_linux-x86.mk
        replace : HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0
        with    : HOST_GLOBAL_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0

2. in ./development/tools/emulator/opengl/host/renderer/Android.mk
        add : LOCAL_LDLIBS += -lX11

3. in ./external/gtest/include/gtest/internal/gtest-param-util.h b/
include/gtest/internal/gtest-param-util.h
        after : [CODE]#include <vector>[/CODE]
        add : [CODE]#include <stddef.h>
                #include <cstddef>[/CODE]

4. in ./external/gtest/src/Android.mk
        replace (this is done in 2 places with the same line) :[CODE]LOCAL_CFLAGS += -O0[/CODE]
        with : [CODE]LOCAL_CFLAGS += -O0 -Wno-missing-field-initializers[/CODE]

5. in ./external/llvm/llvm-host-build.mk
        add : [CODE]LOCAL_LDLIBS := -lpthread -ldl[/CODE]

6. in ./external/mesa3d/src/glsl/linker.cpp
        after : [CODE]#include <climits>[/CODE]
        add : [CODE]#include <stddef.h>[/CODE]

7. in ./external/oprofile/libpp/format_output.h
        replace : [CODE]mutable counts_t & counts;[/CODE]
        with : [CODE]counts_t & counts;[/CODE]

8. in ./frameworks/compile/slang/slang_rs_export_foreach.cpp
        replace (line 249 - be careful, there are 2 line the same, the other
one is required) : [CODE]llvm::StringRef ParamName = PVD->getName();[/CODE]
        with :[CODE] // llvm::StringRef ParamName = PVD->getName();[/CODE]

另外我编译的过程还遇到了

host SharedLib: libGLES_CM_translator (out/host/linux-x86/obj/lib/libGLES_CM_translator.so)
/usr/bin/ld: skipping incompatible /usr/lib64/libGL.so when searching for -lGL
/usr/bin/ld: cannot find -lGLcollect2: ld 返回 1
make: *** [out/host/linux-x86/obj/lib/libGLES_CM_translator.so] Error 1
make: *** Waiting for unfinished jobs….

解决方法是

sudo yum install libgle.i686 libgle.x86_64 libgle-devel.i686 libgle-devel.x86_64 yum install mesa-libGL-devel.i686

又遇到

Java: CtsVerifier 
(out/target/common/obj/APPS/CtsVerifier_intermediates/classes) 
cts/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java: 
191: onCreateDialog(int,android.os.Bundle) in android.app.Activity 
cannot implement onCreateDialog(int,android.os.Bundle) 
in com.android.cts.verifier.PassFailButtons.PassFailActivity; 
attempting to assign weaker access privileges; 
was public private static <T extends android.app.Activity & 
PassFailActivity> 
                           ^ 
1 error 
make: *** 
[out/target/common/obj/APPS/CtsVerifier_intermediates/classes-full- debug.jar]

有人说是使用openjdk,没有使用sun-jdk的原因,但是我使用的确实是sun-jdk,我采取了有人说的方案,从PassFailActivity接口中删除掉Dialog onCreateDialog(int id, Bundle args)

 

有了这些修补后,就可以正式开始编译了,

source build/envsetup.sh

lunch full-eng(注:这个属于没有设备专有驱动的配置,实际的机器比如Nexus S,你要到官网下载相应的驱动包,具体见这里

make -j4(注:-jN可以加快编译速度,但是数值不要过大,推荐值是电脑CPU线程的1或2倍)

日期:2012.02.06
标签: Android
分类: how
1 Comments

思考有的时候就是意淫

前几天写了《拾掇旧玩应——那些年,我独自做过的小站》,我发现大部分我的项目都烂尾了。我发现我总是偶尔想到一个想法,然后开始行动,然后过程中又冒出新的想法,然后又突然觉得无趣,然后就萎靡,然后就罢手了。

就在最近这两天我又烂尾了一个Android的项目,当我想好这个项目的一切想法,我想好了它的需求,并且为它想好了一个专门设计的网站,想好了一些文案,并且在做的过程中偶尔兴奋,我刚做出一个较为完整的alpha版本,写了一点单独的推广的网站,但是它还是烂尾了。就像我之前做过的一个Android项目,再之前做过的一个Android项目一样。

记得曾经写过《目标》中说“我想到我经常穿梭于Web上的各种链接,我时常的目的是打开Google,用它搜索点什么,然而我最初的目的就随着我一次一次点击链接而渐渐远去。”。

我时常觉得,做出一个完整的产品是很艰难的,视觉,文案,代码,想法,推广。有的时候我只能完成初始想法和部分代码的部分,然而视觉和文案则让我费心费力,我一直认为做出一个完整的东西是需要花费完成一个东西两倍甚至更多的精力的。

有的时候我又觉得,我更喜欢做Web,因为Web无论做的怎么样我都可以把它挂到网上去,然后迅速改进重构,但是Android软件或者说软件,你怎么能忍心发布一个很惨的状况的东西出去。下载与安装是一个门槛,而Web点开就可以看到你的东西,尽管你的初期版本可能很是丑陋用户迅速离去,但是当你发布新版的时候Web用户再次看一眼的代价并不大,而软件不好用的话,很可能用户再也不会选择你,因为这玩应相对代价要更大一些,所以第一版必须足够好。

很多时候,我在想大众需求是个什么东西,我一直觉得我是个小众的人,也喜欢小众的品味,当长尾概念烂大街的时候,你会觉得小众的聚集就是大众,然而我却发现我每一个大众的想法都被别人做掉了,所以有的时候无知者无畏,难得糊涂,据说人们只能看到一面的月球。

我想,思考有的时候就是意淫。

接下来,我该不会借由着什么想法去做一些东西了,就比如就在今天我又想到一些。记得《重来》里写“你的头脑中有ebay的创意和你实际去创见ebay那一点关系也没有的”,或许说半毛钱关系都没有。我这样说后我又觉得这些东西不做有点可惜,但是再远了一点想,也许它们又会烂尾。

或许是我想要的太多,想做的太多,比如我想做个记者,想做警察,想徒步旅行,想做产品,想做程序员,想做交互,想做生意,想做老师等等。单从我现在所从事的编程而言,我想做后端,想做前端,想做移动,单从后端来说,我想做Python,想做Java,想做Erlang,想做Hadoop,想做PHP,想做MongoDB,想做Redis,想做C,想做云计算,想做数据挖掘,从前端来说,我想做CoffeeScript,想做HTML5,想做JS,想做jQuery,想做NodeJS,想做CSS,从移动来说,我想做Android,想做iOS,想做PhoneGap,想做WP7。

我想我已经疯了。

我又想到刚才的话,思考有的时候就是意淫。

所以接下来一段时间内,我可能会不再折腾这些东西了,我想参与一个开源的项目,贡献代码。

再一个,我的博客的内容方向可能发生转变,我原来的分类是why-写为什么,how-写怎么做,what-写是什么,when-写随想,summary-写总结。新的方向可能是重在how,而且不是原来的大how,原来喜欢写比较大、通用的主题,现在想写一些小的、特别的主题,比重应该是how:when:why大概是8:1:1的样子。

更重要的是,我要加强一个信念,“没有什么是我做不来的!”

据说很多事情应该立即行动,所以我就要开始了!

然而每次情绪高昂的时候,我都喜欢泼冷水,我记得我写的《犯贱》一文,也许我会再次犯贱。

如果泼冷水真的能让我清醒,那么在凛冽的寒风中猛烈的泼我吧~

日期:2012.02.05
标签: 思考
分类: when
0 Comments

拾掇旧玩应——那些年,我独自做过的小站

这两天拾掇了一下以前写的小网站,有的年久失修已经不能用了,有的简单到弱爆了,都是gae上的东西,用python的,web framework有的是webapp,有的是django,后期主要用django,这里主要回顾一下这几个东西。另外,拾掇的过程中充满尴尬与对自己陈旧代码的鄙视,心想怎么代码写的如此垃圾,过程中还发生了种种烦心的事情,这里一并写下。

在gae上做的第一个玩应叫做“Keep so Go!”,忘了写了多久,可能1天左右,是个很简单的玩应,也很让人摸不着头脑。玩应的介绍就是,“如果网页不被关闭,那么你的在线时常会被不断累加,然后进行排行”,这个东西的灵感现在想想多半来自小的时候玩游戏挂机的经历,亦或是QQ挂机,这个说不准了。只写了1天然后就终止了,本也就是练手的小东西,自然没有传播,用户有2个,一个显然是我,另一个是后来在you8g注册域名被别人悄然发现的。需要注册的东西,还是很难获取初期用户的,除非有知名人事的推动与宣传,像当年“知乎”的邀请码相当难搞,大家趋之若鹜。视觉上,我忘了抄袭了哪的视觉,总之不是我的原创,虽然很简陋,就那个黑条。代码上,真心写的很烂,web框架用的是webapp,总共没多少python代码,200多行,感觉用python代码,这小玩应,写的代码行数越多,越显得低端。看svn的记录,代码是2010年10月写的,剩下应该没有什么了。

第二个应该就是“爱颜色”(现在是在sae上的版本),时间与第一个应该差不多,文案是“选择你最爱的颜色,选择你当前心情的颜色,分享最爱的颜色,对颜色进行解说,通过颜色寻找朋友。”,想法来源是有个挺出名的国外的关于颜色的网站,现在想不起来了,这个是整合了新浪微博的,用了新浪微博的API,信息流会自动同步到微博上。视觉上最早应该是自己的原创,已经不记得长什么样子了,但是提交新浪微博审核的时候,被说界面太丑陋,然后我采用了我博客上的那套css,后来才通过。这个也1年多了,很早以前,由于新浪微博api调整过,然后这个“爱颜色”就不能用了,我也没想改,但是网站处于不能访问的状态,于是我把与新浪微博相关的东西全部注释掉了,然后一直苟延残喘至今,近两天我修复了新浪微博交互的问题,并且把“爱颜色”移植到了sae上。在gae上的现在虽然可以运行,但是还是有很多问题,然后我在gae上可运行的状态上,进行的sae版本移植,然后在sae版本上修复了算是挺大量的东西,然后gae版本作为一个branch躺在那里。“爱颜色”是用的django web framework,而众所周知django在gae上的兼容性并不是很好,我当初使用了google维护的django helper,但也早就停止维护,gae上的django和django最大不同是model层,而我model层当初未完全封装,向外暴漏了好多gae自己的东西,当然当初也想不到会有一天用纯粹一点的django来写,sae上的django算是纯粹一些,不像gae很多不能用。但是移植过程中遇到超多细节问题,而且python不想编译强类型语言,很多问题不到运行时还是挺难发现的,想很多类型问题,我很是无语。一个糟糕的问题是新浪微博的认证过程必须在有外网地址的情况下才能测试,所以我只能部署到真实环境才能测试,于是不停的部署啊,不停的发现问题。看来还是写点单元测试靠谱点啊,于是动手写。磕磕碰碰折腾了小两天时间,每次一部署或者svn提交,我就刷眼微博,关注下方寒战事,终于移植完成,修复了大量错误,并且赶紧了大量代码,有的时候觉得重写都比这块,但是修正代码过程发现我的代码的拙略,改后稍好一点,维护代码总是比捋起袖子从头干起费劲纠结一些。我想起了《UNIX编程艺术》中写的

正如Brian Kernighan曾经说过的:“计算机编程的本质就是控制复杂度”,排错占用了大部分额的开发时间,弄出一个拿得出手的可用系统,通常与其说出自才华横溢的设计成果,还不如说是跌跌撞撞的结果。

另外,又想起在修正gae版本的时候,遇到域名过期,突然不能访问了,想这是咋了,想了会才意识到域名过期啦。。。

然后就是“Micolog部落”了,这个是我用时最多,也是我稍微满意,稍微有点用户,也通过这个网站想了很多,学到很多的一个玩应。曾经写过《最近做一个网站过程中产生的一些想法和疑问》,那里简介写到“2010年11月06日动手,由于我不是美工,加之之前站点UI的失败,为此我特意看了几本Web设计的书。最终借用了Wordpress的Motion主题。开发平台使用Google App Engine,语言Python,框架Django,RCS使用Git,GitHub托管。主要利用平常的闲暇时间开发。”时间来看,这个也1年多了,而且我最近打算基于这个做点扩展。这个网站我修改了好多次,对于注册环节我那篇博文里说过,注册我改了能有5次左右。开发时间总共加起来可能并没有多少,但是为这个我想了很多事情。用户量依然很少,但是也算是个突破,有80左右个人,并且当初还有点小意思,有几个活跃用户,我算是最大的活跃用户了吧,我在想当一个东西的创始人不在活跃的时候,那么多半这个东西就完了。后来怎么没有在搞,“”,堵住了micolog的用户,我这个基于micolog的聚合站也就黄了。

然后就是沉寂了,很久没写出什么,过程中有一些小东西,大多是在别的东西基础上做的二次开发,而且都是未完成品,做完一个东西的时间是代码第一次完工时间的一倍。

面条”,我觉得这个名字很有爱,名字叫什么无所谓了,这其实是显示豆瓣书影音收藏轨迹的一个东西,并没有100%完成,但是可以用,在豆瓣ID那输入自己的豆瓣ID,然后点选书影音组合,然后点“点”,可以显示自己的书影音收藏。

the10000”,名字来源是《异类》这本书,想法来源同是这本书和“Dan计划:重新定义人生的10000个小时”,标语用的是v2ex下面的那个“Do have a faith in what you're doing”,这个东西的玩法是:用户在上面写下一个自己要实现的目标,然后自己记录自己为这个目标做了什么,做了多少小时,距离达到10000小时还差多久,你已经为你的梦想努力了多少小时。我第一个用户的目标是做这个网站10000小时,然而我做的一个扯淡的行动是,在我做了5个小时左右后,就再也没动过他。这个网站另一个很扯的地方是也采用了邀请码注册机制,而且未登录用户神马也看不到,所以我想到了这个是在知乎刚出那会做的,依然是前面所说的。忘了说了,这个是基于v2ex进行的二次开发。

"Wiki",基于nancywiki做了一点二次开发,我之前博文写过一直想写个wiki,弄个我wiki,但是现在不做了。

再有就是写过一些micolog的插件。写过一个Android的烂玩应。

再有就是"网上书店",这个最初不是GAE上的,是之前学校写的网上书店,花了一会时间移植到SAE上,网上书店用的是Django写的,移植到SAE上很方便,但是网上书店用到了pylucene,SAE上没法搞,所以搜索和相关用pylucene做的推荐没法用,我主要写的后端,前端是一个同学写的,前端页面我基本没写,都交给同学了。这应该是我第一个纯Django的项目,之前在GAE上有一些不同和限制,写这个时候觉得Django开发是快,很爽,我们很快在我宿舍写完了。数据是豆瓣API搞下来的,用了memcache。总的来说挺糙的,不过和同学一起写还是有点意思的。

本来想配图,但是配图太麻烦,太讨厌配图了,我采集到了花瓣上,地址这里,http://huaban.com/boards/170195/

写于两天前,这两天纠结在libvirt和xen上了。

日期:2012.01.31
标签: gae sae 项目 django
分类: summary
0 Comments

phoengap源码解析——插件机制,java和js代码互调用详解

看了眼phonegap的android实现的源码,其实还是挺简单的。出乎意料的是,我原以为js这套api的封装是使用addJavascriptInterface这个接口完成的,但是它是用了一种奇异的方法来实现的。我们一步一步慢慢说。

http://docs.phonegap.com/en/1.3.0/index.html这个链接是phonegap的js api,可以看到api是分模块的,有Accelerometer,Camera,Capture,Compass,Connection,Contacts,Device,File,Geolocation,Media,Notification,Storage,Events,而每一个模块恰好是phonegap的一个plugin。而每一个plugin恰好大体对应一个java文件和一个js文件。在实际用phonegap开发的时候,我们引用的phonegap.js是经过编译整合后的文件,源码的framework/build.xml中有如下一段可以说明:

<!-- Create uncompressed JS file -->
<concat destfile="assets/www/phonegap-${version}.js">
 <fileset dir="assets/js" includes="phonegap.js.base" />
 <fileset dir="assets/js" includes="*.js" />
</concat>

插件机制对应的java代码,主要在com.phonegap.api这个包里,所有的api对应模块的java实现都扩展了Plugin类,并且在src/com/phonegap/api/PluginManager.java中有public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async);方法,此方法里面调用plugin.execute方法,相应的plugin插件实现了execute方法,进行具体操作。对应js代码,插件机制以及公有基础的东西主要phonegap.js.base文件,每个单独的模块文件实现具体的操作。js代码里也有相应定义,
/**
* Execute a PhoneGap command. It is up to the native side whether this action is synch or async.
* The native side can return:
* Synchronous: PluginResult object as a JSON string
* Asynchrounous: Empty string ""
* If async, the native side will PhoneGap.callbackSuccess or PhoneGap.callbackError,
* depending upon the result of the action.
*/
public String exec(final String service, final String action, final String callbackId, final String jsonArgs, final boolean async);
可以看到api操作还提供了同步异步两种模式。这里的一些东西到这里可能还不是很明朗,稍后了解了java和js互掉的原理后就清楚了。

但是这里,特别的对于Events有些特别,java与js交互上是不同于其它模块的方法且相对简单的,所以先说这个。在src/com/phonegap/DroidGap.java文件中可以看到,所有js的回调事件都是通过loadUrl然后执行一段javascript脚本来实现的,如

生命周期回调:this.appView.loadUrl("javascript:try{PhoneGap.fireDocumentEvent('resume');}catch(e){};");
按钮响应:this.appView.loadUrl("javascript:PhoneGap.fireDocumentEvent('backbutton');");

assets/js/phonegap.js.base相应代码为:

PhoneGap.fireDocumentEvent = function(type, data) {
    var e = document.createEvent('Events');
    e.initEvent(type);
    if (data) {
        for (var i in data) {
            e[i] = data[i];
        }
    }
    document.dispatchEvent(e);
};

好了,开始最重要的部分了。phonegap使用的java与js互相调用的原理。phonegap实现的模型刚也说了,有同步和异步两种。js实现的api,所以是js先会调用java代码,然后再返回给js。对于同步的而言,就是js调用java,然后java返回一个结果作为返回值。对于异步的而言,可能js掉了很多java代码,但是立即返回,然后java代码执行结束后再回调js代码,这里就涉及到js调java,然后java再调用js。

对于js调用java:

js调用java的入口是通过在js中调用prompt方法,这很奇怪吧,这个方法本来是让浏览器弹出个输入框的。我当初找了好久也没发现phonegap到底怎么搞得的让js调用java的代码,后来看到一会觉得该是这个方法,但是这是一个浏览器的客户端自己的东西,而且怪异的是浏览器并没有弹出输入框,后来终于发现。

在DroidGap.java中有个hack,重载了WebviewClient的onJsPrompt方法,然后执行了自己的逻辑。 也就是js调用prompt的时候,java端浏览器代码接受到这个,然后在响应的处理函数中根据传过来的参数,实现了一些特别的逻辑。可以从这个方法的注释上看出一二。

/**
* Tell the client to display a prompt dialog to the user.
* If the client returns true, WebView will assume that the client will handle the prompt dialog
* and call the appropriate JsPromptResult method.
* Since we are hacking prompts for our own purposes, we should not be using them for this
* purpose, perhaps we should hack console.log to do this instead!
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
...
}

方法里面的代码就如刚所说会根据传过来的参数,做相应处理,它会先判断是不是本地网页的请求,如果是,然后分几种情况。

// Calling PluginManager.exec() to call a native service using
prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]));
gap:
// Polling for JavaScript messages
gap_poll:
// Calling into CallbackServer
gap_callbackServer:
// PhoneGap JS has initialized, so show webview(This solves white flash seen when rendering HTML)
gap_init:

分别是,如果是prompt传过来的是gap:这样开头的字符串,那么就执行相应的java调用,Calling PluginManager.exec() to call a native service using prompt(this.stringify(args), "gap:"+this.stringify([service, action, callbackId, true]))。gap_poll:和gap_callbackServer:是稍后要说到的java回调js使用的,gap_init:初始化处理相关的代码。如果其它情况,则构造一个Android的AlertDialog显示。

然后phonegap就是这样,通过设置setWebChromeClient和setWebViewClient,重载了一些实现,控制了浏览器行为,实现了自己的很多逻辑。

对于java回调js:

phonegap实现了一个回调服务器,服务器就是负责回调js代码的,服务器有一个js代码的队列,在src/com/phonegap/CallbackServer.java文件中

/**
* The list of JavaScript statements to be sent to JavaScript.
*/
private LinkedList javascript;

服务器保存要回调的js的代码,供js客户端取回,这里java端是服务器端,js端是客户端,服务器端不可能请求客户端做啥,是b/s模型,所以phonegap实现了两种服务模型,一种是轮询,一种是XHR异步回调,也就是Ajax的模型。src/com/phonegap/CallbackServer.java是回调服务器的代码所在处。从类的注释中可以看到。

This class provides a way for Java to run JavaScript in the web page that has loaded PhoneGap.
The CallbackServer class implements an XHR server and a polling server with a list of JavaScript statements
that are to be executed on the web page.

CallbackServer提供的这两种模型,一种是XHR,一种是轮询,轮询很简单了,callbackserver服务器端,有一个保存回调js的列表,前面所说,然后每隔一段时间客户端的js会询问一次服务器,是否有需要回调的js,如果有则调用,然后每隔一段时再查询一次服务器。而基于XHR的,其实这个就是ajax用的机制了,js发起一个异步请求,然后服务器会在返回数据之前保持住这个连接,当返回数据就位后,服务器给请求客户端返回数据,然后关闭连接。然后客户端接受并且处理。

刚说了服务器端的代码实现,现在来看一下客户端js的相关代码。

/**
* Internal function that uses XHR to call into PhoneGap Java code and retrieve any JavaScript
* code that needs to be run. This is used for callbacks from Java to JavaScript.
*/
PhoneGap.JSCallback = function() {
...
xmlhttp.open("GET", "http://127.0.0.1:"+PhoneGap.JSCallbackPort+"/"+PhoneGap.JSCallbackToken , true);
xmlhttp.send();
}

这个是XHR模型的代码,客户端js使用xhr请求服务器来获取js代码,进行回调。

/**
 * Internal function that uses polling to call into PhoneGap Java code and retrieve
 * any JavaScript code that needs to be run.  This is used for callbacks from Java to JavaScript.
 */
PhoneGap.JSCallbackPolling = function() {
...
    var msg = prompt("", "gap_poll:");
    if (msg) {
        setTimeout(function() {
            try {
                var t = eval(""+msg);
            }
            catch (e) {
                console.log("JSCallbackPolling: Message from Server: " + msg);
                console.log("JSCallbackPolling Error: "+e);
            }
        }, 1);
        setTimeout(PhoneGap.JSCallbackPolling, 1);
    }
    else {
        setTimeout(PhoneGap.JSCallbackPolling, PhoneGap.JSCallbackPollingPeriod);
    }
}

这个是轮询方式的,可以看到客户端每隔PhoneGap.JSCallbackPollingPeriod段时间,就请求一次服务器(通过prompt("", "gap_poll:");)。

 

至此js和java互调用,phonegap的plugin插件机制和api的实现原理就清楚了。另外phonegap源码的注释是很不错的。

日期:2012.01.28
标签: phonegap Android 源码解析
分类: why
0 Comments

PhoneGap,Web Application,反编译,代码阅读器——4in1游戏卡,寻觅童年游戏机快感

这篇文有点杂了,说了四部分,破折号后面纯扯了,如标题所示,分别是,title='PhoneGap,Web Application,代码阅读器,反编译——4in1游戏卡,寻觅童年游戏机快感'; title[:title.index('—')].split(',')

PhoneGap
phonegap,我想搞手机开发的人应该都知道,使用phonegap可以用web开发的前端技术开发应用,也就是html,css,js开发应用,然后可以部署到多个主流平台,并且phonegap根据各个平台封装了统一的一套和手机交互的api。API包含Accelerometer,Camera,Capture,Compass,Connection,Contacts,Device,File,Geolocation,Media,Notification,Storage等。然后就是js那套事了。

android的activity的生命周期算是android学习的第一课,那么关于phonegap的生命周期呢,分别是onDOMContentLoaded, window.onload,onNativeReady,onPhoneGapInit,onPhoneGapReady,onPhoneGapInfoReady,onDeviceReady,onResume,onPause,onDestroy。其中只有deviceready,pause,resume是提供给用户处理的,deviceready是java代码部分初始化完毕全部初始化完成,状态就绪触发,pause,resume是和android的onPause和onResume一样周期。

phonegap的问题是性能问题,还是会卡,照原生应用差很多,而且对于有大量后台逻辑的很不适合,Services,线程啥的还是很麻烦,官网说像Dropbox这种,大量上传下载,同步逻辑的应用不适合搞。而且虽说是phonegap是跨平台,但是按照http://phonegap.com/apps应用列表来看,大部分都是只编译了ios平台的,只用phonegap确实有很多限制,之前看到有部分嵌入phonegap的,当前这种模型可能更多也更适合些。

对于部分采用phonegap的,可能需要和其它原生Activity交互,传送数据什么的,phonegap提供了插件机制,github有维护插件列表,有个webintent,phonegap默认没有用js打开本地activity的方法,用别的activity启动phonegap的activity的时候也不能传参给js代码,这个可以方便做这些操作。最近版本的phonegap这个webintent插件失效了,phonegap插件机制有所更改,需要做一点更改,可以看这里https://github.com/phonegap/phonegap-plugins/pull/335。关于phonegap plugin,其实大部分的api都是基于插件机制做的,但是关于plugin的相关文档很不好,如果想写phonegap插件,还是看别的插件和源码中插件那部分,我看了下其实不复杂。

Web Application
分四部分,内容大部分来自android dev guide,其实Web Application就是应用里面嵌入个浏览器,用浏览器呈现网页罢了,不过是文艺的说法。

1. Targeting Screens from Web Apps
又是屏幕问题,Android的设备多种多样,重要的是dpi也不一样,你说电脑显示器也很多,各种各样,但是dpi是一致的。
对于Web Application,Android系统提供了一些对于分辨率的支持,html代码定义一些meta,webview会识别,然后做相应调整。

<meta name="viewport"
      content="
          height = [pixel_value | device-height] ,
          width = [pixel_value | device-width ] ,
          initial-scale = float_value ,
          minimum-scale = float_value ,
          maximum-scale = float_value ,
          user-scalable = [yes | no] ,
          target-densitydpi = [dpi_value | device-dpi |
                               high-dpi | medium-dpi | low-dpi]
          " />

简要说明,默认viewport的宽是800像素,如果设置了,设置多少就是多少,如果设置成device-width(height)就是手机分辨率的像素数。user-scalable是否允许用户缩放。另外js中可以通过window.devicePixelRatio取得设备像素密度比值。css可以通过media的-webkit-device-pixel-ratio属性来加载相应的css。

2. Building Web Apps in WebView
总结起来一句话用WebView,这个类仔细看看其实挺好玩,涉及到另两个WebViewClient和WebChromeClient,也很好玩。

3. Debugging Web Apps
Debuging好说,就是用console.log之类的,会在Logcat上打印。

4. Best Practices for Web Apps
其实这也没啥东西。

总结起来其实没啥东西。

反编译
------
http://code.google.com/p/android-apktool/
主要用来看反编译出来的资源文件。

http://code.google.com/p/dex2jar/
配合JD(Java decompiler),主要用来看反编译出来的代码。代码被混淆过的话,看了也看不出来啥,有的时候可以看看它用了什么库。

用法都很简单,另外,可以用hierarchyviewer来看Activity的布局,需要手机是Debug模式的,这个不是说手机root后就可以用。手机要是Debug模式的。

5分钟构建代码阅读器

刚看到一条微博,《简讯:为庆祝 Vim 编辑器的20周年,Applidium 项目团队把 Vim 移植到 iOS 了》。
然后有人回复:放过程序员吧!别人买一ipad开心玩游戏,我们买一个ipad到处写程序啊!

~~~~

代码阅读器,这其实是一个需求。

最基础的需求是代码高亮,这个其实巨简单,可以写成web application,可以用phonegap,现成的基于js的代码高亮工具有很多,搞技术博客的人肯定知道一堆这种js脚本,我看了几个简单的代码阅读器,都是基于google的prettify的。

读取文件内容到html,然后js高亮。读取文件可以java读取然后给html,也可以用phonegap的File API,用了下File API,很简单也好用。如果想要文件浏览器之类的,可以用OpenIntents的OI文件管理器,http://www.openintents.org/en/,然后就完了。可以说是5分钟完成代码阅读器应用。

另外,通过反编译,看到有的原生实现的用到了RSyntaxTextArea这个库,关于Android重点在MultiAutoCompleteTextView.Tokenizer这个东西,大概看了一眼。

但是我觉得,代码阅读的关键是,交叉引用的跳转,管有代码高亮只实现了一半,研究了半天没找到什么解决方案。过程中找到ace editor这个玩应,挺强大,但是对平板触摸设备不兼容,虽然有ipad branch,但是不好用。

结:这篇博文有点扯了,写的很粗,过年Happy下~

日期:2012.01.25
标签: phonegap web app Android
分类: when
0 Comments