Hybrid APP 交互文档 v1.0.0

整理Native App 与 Web 交互实现文档!

更新日期: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
webView.loadUrl("javascript:Hybrid.callByNative({token:'t93', script:'alert(123)'})");
// IOS调用JavaScript
[webView stringByEvaluatingJavaScriptFromString: @"Hybrid.callByNative({token:'t93', script:'alert(123)'})" ];

Native 请求处理

Android

重写WebChromeClient.onJsPrompt

public 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);