更新日期:2015年10月27日
维护:Aitter
版本:v1.0.0
参考:http://www.infoq.com/cn/articles/hybrid-app?utm_source=tuicool
原理
Web调用Native的实现过程
- Web端调用
Hybrid.callByJS({name:'actionName', callback: function()}, param:{}})
,由Hybrid根据特定“Web调用Native”方式通知Native执行相应方法。 - Native执行完毕后通过“Native调用Web”的方式调用
Hybrid.callByNative({token: 't99' })
。 - 其中JavaScript回调函数会映射为字符串型的token,通过这个方式来保证最终触发JavaScript的回调函数(包括匿名函数和通过闭包实现的私有函数)。
Native调用Web实现过程
- Native端调用
Hybrid.callByNative({token:'t93', script: 'js代码'})
, 由Hybrid根据特定“Native调用Web”方式通知Web执行相应的脚本。 - Web执行完毕后通过“Web调用Native”的方式调用
Hybrid. callByJS({token: 't93',result:{} })
将结果返回给Native。
// Android调用JavaScript |
// IOS调用JavaScript |
Native 请求处理
Android
重写WebChromeClient.onJsPromptpublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result){
// 从地址中 截取出参数
// 反序列化JSON对象
// 获取action操作名称 和 参数
// 执行相应的Native代码
// Native调用JS的方式返回结果
webView.loadUrl("javascript:Hybrid.callByNative({token:'t93', result:{}})");
result.confirm("");
return false;
}
IOS
iOS中可用的方式类似Android中的WebViewClient.shouldOverrideUrlLoading, 通过监控WebView的URL变化实现Web调用Native- (BOOL)webView:(UIWebView *) webView shouldStartLoadWithRequest:
(NSURLRequest *)request
navigationType: (UIWebViewNavigationType)navigationType {
// 从地址中 截取出参数
// 反序列化JSON对象
// 获取action操作名称 和 参数
// 执行相应的Native代码
// Native调用JS的方式返回结果
[webView stringByEvaluatingJavaScriptFromString: @"Hybrid.callByNative({token:'t93', result:{}})" ];
}
URL约定
URL地址:qiakr://
+ JSON序列化的参数
例如 个人导购 主页拍照片请求Url如下:qiakr://{"name":"photograph","token":1,"param":{"basePath":"http://static.qiakr.com/evluate/","themeImg":"sales_boy_1.png"}}
JS调Native 请求的参数说明:{
name: '操作名称', //string
token: 'callback映射的id', //string
param: '{ 传给Native的参数 }', //JSON
version: '0.0.1' //JS版本号,每次修改JS 会改变
}
Hybrid.js的内容;(function(window){
var DEBUG = true;
var callbacks = {};
var guid = 0;
var ua = navigator.userAgent;
// 平台判断
var ANDROID = /android/i.test(ua);
var IOS = /iphone|ipad/i.test(ua);
var WP = /windows phone/i.test(ua);
// 日志记录
function log() {
if (DEBUG) {
console.log.call(console, Array.prototype.join.call(arguments, ' '));
}
}
/**
* 平台相关的Web与Native单向通信方法
*/
function invoke(cmd) {
log('invoke', cmd);
if (ANDROID) {
prompt(cmd);
}
else if (IOS) {
location.href = 'qiakr://' + cmd;
}
else if (WP) {
// TODO ...
}
}
var Hybrid = {
callByJS: function(opt) {
log('callByJS', JSON.stringify(opt));
var pms = {};
pms.name = opt.name;
pms.token = ++guid;
pms.param = opt.param || {};
callbacks['t'+pms.token] = opt.callback;
invoke(JSON.stringify(pms));
},
callByNative: function(opt) {
log('callByNative', JSON.stringify(opt));
var callback = callbacks[opt.token];
var result = opt.result || {};
var script = opt.script || '';
// Native主动调用Web
if (script) {
log('callByNative script', script);
try {
invoke(JSON.stringify({
token: opt.token,
result: eval(script)
}));
}catch(e) {
console.error(e);
}
}
// Web主动调用Native,Native被动响应
else if (callback) {
callback(result);
try {
delete callback;
log(callbacks);
} catch (e) {
console.error(e);
}
}
}
};
window.Hybrid = Hybrid;
})(window);