Appearance
JavaScript 与 C++ 双向通信
如何在页面上执行自己的 JS
使用 mbRunJs
在之前的快速开始中,我们使用了 mbRunJs(webView, frameId, "alert(1);", true, nullptr, nullptr, nullptr); 直接执行 JS 代码片段 alert(1);。
注意,直接使用 JS 字符串可能需要处理一些转义。
使用本地 js
TIP
132 版本无法使用这个方法, 因为安全策略中没有放开本地 file 协议文件, 可以自己读取文件内容并 mbRunJs, 或者拦截网络请求
假如我们有一个 JS 文件,想引入到一个页面,如何操作呢?利用一个简单的 JS 技巧就可以完成:
cpp
mbRunJs(webView, frameId, "var script = document.createElement('script');script.src = 'file:///C:/xx_dir/test.js';document.getElementsByTagName('body')[0].appendChild(script);", true, nullptr, nullptr, nullptr);里面的 JS 代码格式化之后就是:
javascript
var script = document.createElement('script');
script.src = 'file:///C:/xx_dir/test.js';
document.getElementsByTagName('body')[0].appendChild(script);其中 src 可以修改为一个合法的本地路径,网络路径也可。
拦截网络请求并设置数据
javascript
mbOnLoadUrlBegin(mbView, onLoadUrlBegin, nullptr);javascript
BOOL MB_CALL_TYPE onLoadUrlBegin(mbWebView webView, void* param, const char* url, void* job)
{
if (0 == strcmp(url, "http://xx/xx.js")) {
// ... 这里 arr 数据也可以来自本地文件
char arr[] = "alert(12)";
std::vector<char> buffer(arr, arr + std::strlen(arr)); // 132 版本不需要 '\0'
// ...
mbNetSetData(job, &buffer[0], buffer.size());
mbNetSetMIMEType(job, "text/javascript");
mbNetSetHTTPHeaderFieldUtf8(job, "Content-Type", "application/javascript", TRUE);
return true;
}
return false;
}mbNetSetData 用于设置数据
mbNetSetMIMEType 用于设置 MIME
mbNetSetHTTPHeaderFieldUtf8 用于设置头信息 Content-Type
http://xx/xx.js 是网络请求的 url,自己用 mbRunJs 发出的请求也可以拦截
通过以上几个 API,不止是执行 JS,其实也可以实现另外一种 JS 和 C++ 通信的方式,比如 JS 发出一个具有独特路径的 URL,然后 C++ 拦截这个独特的 URL 并获取数据,然后给 JS 发送数据
JS 获得数据之后如何与 C++ 通信
mbRunJs 执行代码片段获得 JS 数据
首先,mbRunJs 可以配置参数 mbRunJsCallback 设置回调,案例如下:
调用 mbRunJs:
cpp
mbRunJs(webView, frameId, "return 999 + 1;", true, onRunJsCallback, nullptr, nullptr);onRunJsCallback 如下:
cpp
void MB_CALL_TYPE onRunJsCallback(mbWebView webView, void* param, mbJsExecState es, mbJsValue v)
{
double value = mbJsToDouble(es, v);
}此时 value 值为 1000.0,注意需要调用 mbJsToDouble、mbJsToBoolean,mbJsToString 等函数从 JS 获取值,如果不确定是什么类型,可以使用 mbGetJsValueType。
JS 在任意时刻与 C++ 通信
对于异步或者一些单页面网页,执行完 JS 片段不能立即返回所需结果,或者我们使用了插入 script 标签的办法执行 JS,这要求 JS 能在任意时刻与 C++ 通信。
使用 mbOnJsQuery 注册 JS 通知的回调
cpp
mbOnJsQuery(mbView, onJsQueryCallback, nullptr);onJsQueryCallback 为:
cpp
void MB_CALL_TYPE onJsQueryCallback(mbWebView webView, void* param, mbJsExecState es, int64_t queryId, int customMsg, const utf8* request)
{
constexpr int postForSomething = 0;
if (customMsg == postForSomething)
{
std::string requestStr(request);
// do someting
mbResponseQuery(webView, queryId, postForSomething, "responseData");
}
}利用上一节的办法加载一个 JS 文件进入网页,内容为:
javascript
var POST_FOR_SOMETHING = 0;
setTimeout(function() {
window.mbQuery(POST_FOR_SOMETHING, "requestData", function(customMsg, response) {
// do something
});
}, 2000);这里模拟了一个异步操作,2秒之后 JS 使用 window.mbQuery 调用 C++ 。注意,window.mbQuery 为 MB 注入进页面的函数,直接调用即可。
此时 onJsQueryCallback 接收到参数,其中 customMsg 为 0,request 为字符串 "requestData"。如果要传结构体,可以使用 JSON,两边各自解析处理即可。
类似的,mbResponseQuery 也可以向 JS 的回调返回内容。
如果想深入了解如何实现 C++ 与 JS 绑定,可以参考 Javascript 和 C++ 绑定如何实现(WIP)