方案
- WKWebView – 拦截URL
- WKWebView – MessageHandler
MessageHandler 方案虽然更加优雅,但是考虑与 Android 兼容的问题,我们采用 WKWebView – 拦截URL 方案。
使用场景/需求
场景 A
H5 页面点击按钮后,App 只需要完成操作。
场景 B
H5 页面点击按钮后,App需要操作之后,把操作结果通知H5。
场景 A,场景 B 两个场景都涉及 H5 与 App 之间的通信,不过场景 B 多了一个回调操作。
回调操作其实就是 App 调用 JS 函数
App H5 通信基础
App 通知 JS
var js = "App.callJS()"
webView.evaluateJavaScript(js) { (response, error) in
}
复制代码
JS 通知 App
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "");
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
复制代码
设想
H5 发出指令拍照,App 接收到并执行拍照,拍照完成之后把图片发送给 H5
那么我们在 H5 页面是这么使用的
// 此处参数可以不填,没任何意义
App.takePicture("参数", function(data) {
// 成功,展示图片
}, function(data) {
// 失败,错误信息
});
复制代码
思路
H5 用 ID 来标识指令的唯一性,ID 关联当前指令的名称,参数,回调。
App 用 ID 来获取名称,参数,执行回调。
通过 ID 获取回调函数,使用 setTimeout 来完成 JS 函数调用。
// 执行函数,效果相同
setTimeout("App.callJS()", 0);
App.callJS()
复制代码
实现
H5 核心代码
var AppServer = {
ID_COUNTER: 0,
COMMAND_NAME_SET: {},
COMMAND_ARGS_SET: {},
COMMAND_SUCCESS_COMPLETION_SET: {},
COMMAND_FAIL_COMPLETION_SET: {},
// JS调用App
callNative: function (cmd_name, cmd_args, cmd_success, cmd_fail) {
var key = this.ID_COUNTER++; // 指令唯一标识
this.COMMAND_NAME_SET[key] = cmd_name;
this.COMMAND_ARGS_SET[key] = cmd_args;
if (typeof cmd_success != 'undefined') this.COMMAND_SUCCESS_COMPLETION_SET[key] = cmd_success;
if (typeof cmd_fail != 'undefined') this.COMMAND_FAIL_COMPLETION_SET[key] = cmd_fail;
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "DEMO://AppServer?id=" + key);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
},
// 指令名称
getCommandName: function(key) {
return this.COMMAND_NAME_SET[key];
},
// 指令参数
getCommandArgs: function(key) {
return this.COMMAND_ARGS_SET[key];
},
// App调用JS
callJS: function (key, args) {
if (typeof args == "undefined") {
args = JSON.stringify({});
args = JSON.parse(args);
}
var data = args.data;
try {
data = JSON.stringify(data);
} catch(e) {
alert(e.message);
}
// 回调
var status = args.status;
if (status == 1) {
// 成功
if (typeof this.COMMAND_SUCCESS_COMPLETION_SET[key] == "undefined") return;
setTimeout("AppServer.COMMAND_SUCCESS_COMPLETION_SET['" + key + "']('" + data + "')", 0);
}
else if (status == 0) {
// 失败
if (typeof this.COMMAND_FAIL_COMPLETION_SET[key] == "undefined") return;
setTimeout("AppServer.COMMAND_FAIL_COMPLETION_SET['" + key + "']('" + data + "')", 0);
}
}
};
复制代码
App 核心代码
// 指令名称
func getCommandName(_ commandID: String) {
let JS = "AppServer.getCommandName(\"\(commandID)\")"
webView.evaluateJavaScript(JS) { (response, error) in
}
}
// 指令参数
func getCommandArguments(_ commandID: String) {
let JS = "AppServer.getCommandArgs(\"\(commandID)\")"
webView.evaluateJavaScript(JS) { (response, error) in
}
}
// App调用JS
func callJS(_ commandID: String, data: String) {
let JS = "AppServer.callJS(\"\(commandID)\"," + data + ")"
webView.evaluateJavaScript(JS) { (response, error) in
}
}
复制代码
实现效果
Demo
觉得不错的,star 一下?
App 使用的 H5 是打包编译好的,H5 项目在 my-project 目录下。
实际项目使用,H5 只需引入 AppServer.js 文件,与 App 约定好指令名称和参数即可。
补充
如果想测试自定义指令的话,可以自行修改 H5 项目。
H5 Demo 使用 Vue 写的,修改后直接编译打包。
Xcode 清理(shift + command + k)之后,重新运行就可以看到修改之后的效果。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END