PhoneGap开发拾遗




最近在和朋友一起写一个mobile app。用native code编写app实在费时费力,难于同时针对不同平台开发,debug也不容易。再者,我们对JavaScript的熟悉程度也远高于Java。于是,PhoneGap就成了我们的选择。

总的来说,利用PhoneGap,使用HTML/CSS/JavaScript进行一次开发,稍作改动,就可以伪装为原生应用部署至六个平台(Android、iOS、BlackBerry、WebOS、symbian、Bada等)。按照Adobe原本的说法应该是七个平台,只可惜WP7使用的是IE内核而不是WebKit,所以……你懂的。

一切都是异步回调


PhoneGap使用了一套plugin的机制,可以在JavaScript端调用Native Code实现的功能。

PhoneGap的“另一个名字”,Apache Cordova,原先是叫做Apache Callback的,所以正如其名,在PhoneGap里,一切plugin都是通过异步回调完成的。甚至数据库和文件读写也是如此(因为它们也是通过plugin实现)。

尽管有的文章里说PhoneGap的plugin是可以实现同步调用的,但我很多次尝试,似乎都只能异步调用。在Adobe官方的文章里,似乎也证明了这一点:PhoneGap所有的插件都只能通过异步回调来回传数据。

实际上在Android版的PhoneGap中,所有的plugin从Java端回传数据是通过Ajax实现的(PhoneGap在Java端架设了一个HTTP服务器)。而既然是通过Ajax,插件的同步调用就是有可能实现的。但是实现同步调用可能需要大量更改原有的PhoneGap代码,进而带来不便后续更新的问题,因此只能放弃这样的打算。

动画带来的麻烦


由于PhoneGap本质是在移动应用中嵌入了一个WebView,最终渲染页面使用的是系统自带的浏览器内核。

在移动浏览器上实现动画,就曾经让人头疼过一阵子。使用setTimeout/setInterval的方法实现动画,效果极其糟糕,存在严重的卡帧;而使用requestAnimationFrame的方法,兼容性非常差(直到Android 4.0的自带浏览器都不支持)。使用CSS keyframe操作非常繁琐不便,难以实现复杂的效果。

最终我们选择的方法是使用JavaScript操作CSS的transition-duration属性实现相对复杂的动画;再使用CSS keyframe实现简单的动画。这个方案效果非常好,配合CSS matrix3d实现炫丽的三维效果都可以流畅运行。

加速debug


使用PhoneGap开发的人一般都知道两个工具:其一是Ripple,可以在PC的浏览器模拟手机上的效果,可惜没法模拟涉及plugin的部分。其二是debug.phonegap.com提供的remote debugging,可惜功能相当有限,基本只能使用inspect element的功能,console是个残废。

于是对PhoneGap应用进行debug也并不轻松。

Remote debugging的console无法log下对象,只能log字符串这样的原生变量类型,很不方便。但是也确实能找到walkaround,比如自己写一个log方法,或是将其它类型先json_encode再log。

最重要的一点还是需要避免不停地build。刚开始时,我们便是每次修改完代码就build为一个apk安装到手机上,效率极其低下。后来便有了较高效的方案:将所有HTML、JavaScript统统放到一个web服务器上。build出一个安装完所有插件的Java端的apk包,该包index.html中只有一句话:跳转到我们web服务器上的页面。而PhoneGap的plugin机制是允许这么操作的,调用插件也完全正常。于是此后只需修改服务器上的页面即可,无需再重新build。于是我们debug时就节省了大量的时间,协同开发也简单不少。

FileTransfer时的header


官方文档里没有提到上传文件时如何附加HTTP header,但实际上是可以的。在FileTransfer.java里其实有这么一段。
// Handle the other headers
try {
JSONObject headers = params.getJSONObject("headers");
for (Iterator iter = headers.keys(); iter.hasNext();)
{
String headerKey = iter.next().toString();
conn.setRequestProperty(headerKey, headers.getString(headerKey));
}
} catch (JSONException e1) {
// No headers to be manipulated!
}

也就是说,在additional post parameters里加一个叫做"headers"的数组就可以完成往请求里附加header的操作。

若还有可补充的 以后加上

评论

Velanlee 2012-06-12 22:13:01
终于见你更新了,你学的是什么专业?
kmxz 2012-06-20 15:58:16
@Velanlee
总是太忙或者太懒,没有闲心整理自己的情绪,一直没更新。
我现在专业是机械,虽然整天不务正业。
恋羽 2012-06-20 22:43:03
还在学习javascript,哎
月蚀 2013-04-01 17:42:31
亲,请问一下你现在调试phonegap plugin时找到什么合适的方法了没,分享一下也. 还有就是分享一下你们用html5开发native app的一些经验, 怎样调试才能更快更方便呢
Peter 2013-12-08 17:39:26
新版的3.1,能支持remote html吗?请问你用的是什么版本的phone gap
徐强 2014-08-12 11:24:08
向您请教一下:“build出一个安装完所有插件的Java端的apk包,该包index.html中只有一句话:跳转到我们web服务器上的页面。而PhoneGap的plugin机制是允许这么操作的,调用插件也完全正常。于是此后只需修改服务器上的页面即可,无需再重新build。”这个是如何做到 从index页面跳转到另外一个domain页面还能访问到index页面的cordova对象从而访问cordova提供的插件的?我也面对过这个问题,使用redirect 到另外一个页面却因为cordova 为undefined等原因而失败了。 忘您百忙之中能抽空解答一下好么~~