跨平台开发是我们长久以来都在关注的话题,前段时间写了一篇关于React Native的文章《React Native开发初探》。也在公司的项目中部分使用React Native,虽然React Native的出现带来了很多变革,但是光一个环境搭建就把很多人挡在了门外,另外React Native更新的频率过快差不多两周一个版本,所以目前还是处于观望阶段。
Cordova是一个开源的移动应用开发框架,是Adobe贡献给Apache的开源项目,是从PhoneGap中抽出的核心代码,是驱动PhoneGap的核心引擎。Cordova架构如下所示:
从上图可以看出Cordova是基于WebView的,主要是负责Native/OS和Web之间的交互。我们可以使用Cordova的插件机制对Cordova的功能进行扩展,本文主要是介绍Cordova的用法的插件的开发。
在现有项目中集成Cordova
pod 'Cordova'
如果需要引入一些相关的插件,可以加入如下配置,下面的这些插件可以通过pod搜索到:
pod 'CordovaPlugin-console'
pod 'cordova-plugin-camera'
pod 'cordova-plugin-contacts'
pod 'cordova-plugin-device'
pod 'cordova-plugin-device-orientation'
pod 'cordova-plugin-device-motion'
pod 'cordova-plugin-globalization'
pod 'cordova-plugin-geolocation'
pod 'cordova-plugin-file'
pod 'cordova-plugin-media-capture'
pod 'cordova-plugin-network-information'
pod 'cordova-plugin-splashscreen'
pod 'cordova-plugin-inappbrowser'
pod 'cordova-plugin-file-transfer'
pod 'cordova-plugin-statusbar'
pod 'cordova-plugin-vibration'
上面的插件对应着架构图中右边的Plugins,具体的使用方式参考官方的示例。
如何使用Cordova加载网页
建议先下载一份phonegap的示例文件,项目地址是https://github.com/phonegap/phonegap-webview-ios
,可以通过pod查询到(在终端中执行pod search phonegap
):
本人的项目是基于上面的这个模板项目进行开发的,修改的步骤如下:
(1)添加config.xml的配置文件
参见示例项目中的config.xml。
(2)html中引入cordova js库文件
参见示例项目中的js引入。
(3)index.js文件内容:
var app = {
initialize: function () {
this.bindEvents();
},
bindEvents: function () {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function () {
app.receivedEvent('deviceready');
document.getElementById("button").onclick = app.testConnection;
},
receivedEvent: function (id) {
console.log('Received Event: ' + id + ', DEVICE READY FIRED!!!');
},
testConnection: function () {
var networkState = navigator.connection.type;
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.CELL] = 'Cell generic connection';
states[Connection.NONE] = 'No network connection';
console.log('Network Info plugin test - connection type ' + states[networkState]);
}
};
app.initialize();
以上摘自示例项目中的index.js
(4)使用CDVViewController
CDVViewController *viewController = [CDVViewController new];
viewController.wwwFolderName = @"myfolder";
viewController.startPage = @"mypage.html"
其中使用CDVViewController通常需要设置wwwFolderName的目录名称,和startPage首页的名称即可。
Cordova自定义插件开发
(1)创建插件的实现类需要继承CDVPlugin
MyBrowserPlugin.h:
@interface MyBrowserPlugin : CDVPlugin
- (void)open:(CDVInvokedUrlCommand *)command;
@end
MyBrowserPlugin.m:
- (void)open:(CDVInvokedUrlCommand *)command {
CDVPluginResult* pluginResult = nil;
if(!command.arguments || command.arguments.count <= 0) {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
}
else {
NSString* url = [command.arguments objectAtIndex:0];
if (url != nil && url.length > 0) {
//TODO:打开网页浏览器
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
}
else {
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
}
}
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
如果上面的操作需要耗时很长时间可以在后台运行,示例代码如下:
- (void)myPluginMethod:(CDVInvokedUrlCommand*)command {
// Check command.arguments here.
[self.commandDelegate runInBackground:^{
NSString* payload = nil;
// Some blocking logic...
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
// The sendPluginResult method is thread-safe.
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
}
(2)实现插件JS端的代码
cordova.define("com.devzeng.cordova.mybrowser", function(require, exports, module){
var exec = require('cordova/exec');
module.exports = {
open: function(url, callback) {
exec(function(param){callback('success');}, function(){callback('error');}, "MyBrowserPlugin", "open", [url]);
}
};
});
其中上面的exec函数中的第四个参数open是指的MyBrowserPlugin的open方法。使用的时候直接下面的方式调用:
mybrowser.open('url地址', function(message){...});
(3)在web端(cordova_plugin.js)配置插件
{
"file": "plugins/cordova-plugin-mybrowser/www/plugin.js",
"id": "com.devzeng.cordova.mybrowser",
"pluginId": "cordova-plugin-mybrowser",
"clobbers": [
"mybrowser"
]
}
说明:
1)file指的是插件js文件的路径,相对于cordova_plugin.js文件
2)id指的是上面定义的id字符串,pluginId可以设置为插件的名字
3)clobbers中设置的数据是用来自动注册到window中的对象,我们在使用的时候直接使用该命令即可。
(4)在项目中(config.xml)配置插件
<feature name="MyBrowserPlugin">
<param name="ios-package" value="MyBrowserPlugin" />
</feature>
说明:
1)feature中的name对应着前面exec(success, failure, service, action, params)
中的service
2)param中的name在iOS中固定写成ios-package, 后面的value就对应着该插件的入口实现类
参考资料
1、《iOS Plugin Development Guide》