随着前端技术的发展,现在国内外都涌现出了许多移动应用混合开发框架。比如国外的 PhoneGap / Cordova, Ionic, Meteor, 微软收购的 Xamarin 和 国内的 MUI, APICloud, WeX5, 以及最近阿里刚发布的 Weex 等等。

当然这些框架各有特点,但是目前比较成熟的解决方案个人认为还是 Ionic + PhoneGap / Cordova。

因为目前 Cordova 是在 Apache 旗下,技术实力可以得到保证,并且已经发展多年,有很多的框架都兼容 Cordova,例如上面提到的 Ionic , Meteor 和 WeX5 都可以使用 Cordova 插件。在开发工具方面,微软已经在 Visual Studio 中增加了对 Cordova 开发的支持,JetBrains 的 WebStorm 也默认可以开发 Cordova 应用,这也是看好 Cordova 前景的一种表现吧。

我也尝试了一下 Cordova 开发,其中当然免不了的要踩坑,所以在这里列出一些当时比较头疼的问题和心得来供大家参考:

在使用第三方插件时,如果自行扩展了插件,在用命令行工具编译时要使用 cordova compile 而不要用 cordova build 命令,因为 cordova build 命令其实是 cordova prepare + cordova compile,而 cordova prepare 命令做的就是根据插件中的 config.xml 将插件文件复制到项目中,这样就会把你修改了的插件文件替换掉,所以如果只是想编译项目,就只使用 cordova compile 命令吧。

插件中 Java 端返回运行结果给 JavaScript 代码:
在用 JS 代码调用原生代码的方法中,我们需要传入运行成功的回调函数和运行失败的回调函数,原生代码的运行结果就是通过这两个函数来返回的。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// JS 调用 Java 代码。
cordova.exec(successCallback, errorCallback, 'JavaClassName', 'functionName', args);

// 在 Java 代码中,返回运行结果。
void functionName(JSONArray data, CallbackContext callback) {
if() { // 运行成功
callback.success('运行成功的返回结果');
} else {
callback.error('运行失败的返回结果');
}
}

// 回调函数
var successCallback = function(result) {
// result 就是 '运行成功的返回结果';
};

复杂的返回结果,推荐使用 JSONObject 来组织返回对象。

在 Android 端的开发中,如果想在插件的 Java 代码中来和 JavaScript 代码交互,由于 Android 的 WebView 是运行在主线程中,所以在运行过程中可能会产生阻塞问题。通常会有以下两种情况:

如果当前你插件中的原生代码正在和 UI 界面交互,或者你就希望某个方法运行在 UI 线程中,可以用下面的代码:

1
2
3
4
5
6
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
// 你要执行的代码
}
});

如果当前你的插件代码没有和 UI 进行交互,或者有耗时的操作希望能运行在独立线程中,可以使用下面的代码:

1
2
3
4
5
6
cordova.getThreadPool().execute(new Runnable() {
@Override
public void run() {
// 你要执行的代码
}
});

在 Java 代码中如果想调用 js 方法,并且想要传递一个 Json 格式的数据到 js 的方法,当 Json 格式数据中包含引号时,如果不注意的话,很有可能会导致数据传递错误。具体解决方法如下:

1
2
3
4
5
6
7
8
9
// 注意 %s 不要再加引号。
String format = "window.plugins.yourPlugin.function(%s)";
final String js = String.format(format, jsonData.toString());
cordova.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
webView.loadUrl("javascript:" + js);
}
});
1
2
3
// 然后在 js 端的解析调用:
jsonStr = JSON.stringify(jsonStr);
var obj = JSON.parse(jsonStr);

Android 中的 CallbackContext.success() 方法默认只会执行一次回调,如果想通过一个 CallbackContext 重复发送回调结果就会失败。
这时我们可以自定义 PluginResult 对象,并调用 setKeepCallback(true); 方法保持 CallbackContext:

1
2
3
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, value);
pluginResult.setKeepCallback(true);
mCallback.sendPluginResult(pluginResult);

因为 Cordova 的开源性质和产品定位,使得每个人都可以开发自己的 Cordova 插件,这也就导致了目前的 Cordova 插件质量参差不齐。
因此在选用 Cordova 插件时一定要擦亮眼睛 = =。在这里也讲一下我用过的一些还不错的插件:
首先,和硬件交互相关的场景,最好使用 Cordova 的官方插件,这些插件都是经过了实践检验的,基本是不会有什么太大的问题的,具体的插件列表可以去 Apache 的 Github 主页搜索 cordova 关键字查看,也可以在这里查看 Cordova 发布日志。
推送功能由于具体国情,推荐选用国内自己的推送服务,而目前国内只有极光推送官方推出了 Cordova 插件,还是蛮好用的,有 issue 解决的也很快,推荐使用。项目地址:https://github.com/jpush/jpush-phonegap-plugin