基于 wke 的浏览器:如何实现 js 和 c++ 的互相调用
一、引言
最近,老大给了我一个学习研讨任务,也就是如何让 js 和 C++ 进行互调使用。比如我可以在网页中,使用 js 代码调用 c++ 函数,也可以在 c++ 函数中调用 js 对于界面进行控制。
这是为后期的软件接入 Html5 做技术调研。
那么如何实现呢?
这里需要感谢 Redrain 的博客给Webkit内核的浏览器控件增加互交功能,通过参考他的博客,加之我自己的探索,一步一坑终于完成了这个 demo。
如果想要直接看大神的博客可以点击上面那个链接,如果你是个跟我一样在之间一无所知的小白,那就可以看看我作为小白的一步一步的探索吧,应该会比上面大神的博客详细一些。
二、基于 SOUI 的浏览器控件
我这个浏览器 demo 是基于 SOUI 界面库,而 Redrain 的 demo 是基于 duilib 的。其中 SOUI 界面库是我工作中接触到的第一个开源的界面库,功能非常强大,感兴趣的同学可以点击这里 UI神奇-SOUI。
其实用的什么界面库在这里真的没有什么大的影响,因为都是同样封装了 wke 的浏览器内核来调用而已。那么 wke 是什么呢? wke 是 BlzFans (国内大神)对于 webkit 浏览器内核的一个小巧而又强大的封装库,可以实现浏览器内核的相关功能。
那么,怎么开始呢?我们就假设你已经有了一个可以访问网页的浏览器 demo 了,并且使用的是 wke 内核。接下来我们就一步一步的实现 js 和 c++ 之间的交互吧。
三、c++ 调用 js
首先,我们来实现稍微简单点的,c++ 调用 js。
如何实现呢?其实我们仔细翻看 wke.h 文件,就可以看到其实 blzFans 已经封装好了。我们打开 wke.h 文件,可以看到以下的两行代码:
virtual jsValue runJS(const utf8* script) = 0;
virtual jsValue runJS(const wchar_t* script) = 0;
通过函数名称,我们就可以推测这是调用 js 的方法,那么我们只需要在封装浏览器控件的地方,封装一个函数方法,调用 runJS()
方法即可。
这里我使用的是 SOUI 界面库,在 demo 里面已经封装好了一个基本成型的浏览器控件,这里直接在 SWkeWebkit
类中添加 RunJS()
方法即可:
SStringW SWkeWebkit::RunJS(SStringW strValue)
{if (m_pWebView == NULL) return SStringW(L"wke 对象为空");jsValue jsRet = m_pWebView->runJS(strValue);return jsToStringW(m_pWebView->globalExec(), jsRet);
}
这里需要解释一下,SStringW
是 SOUI 界面库封装的字符串类,我们将 wke 对象设置为 SWkeWebkit
类的私有变量进行存储,这里由 m_pWebView
就可以来调用 runJS()
方法调用 js 代码了。
值得一说的是最后的 return 句,这里是参考 Redrain 的代码写的,刚开始也不知道是什么含义,经过多次测试后发现,这一句可以用来返回可能需要返回的 js 代码结果,比如寻找一个元素后返回某些属性值什么的。
比如说,我在 demo 里面写了一个 index.html ,其中有这么一句代码:
<img id="img_track_event_id" name="img_track_event_name" class="" src="data:images/bd_logo.png" width="300" height="128" onmousedown="CallCPlusPlus()" />
这个 img 元素的 id 值为 img_track_event_id
,name 值为 img_track_event_name
,然后我们可以尝试用 c++ 调用 js 代码:
document.getElementById("img_track_event_id").name
来返回我们需要返回的 img 控件的 name 值。
这里可以看到,我在浏览器地址栏输入了 js 代码,并点击 run js 后,响应按钮信息,从地址栏获取到了 js 代码,运行后获取到了 js 返回的值,并以弹框形式显示出来。
这里我感觉我已经讲述的非常详细了,其中关于如何自己在本地建立一个静态的 html 文件进行测试还没有细说,下一节将会讲到,其他如果还有不懂的地方,可以参看我的 demo。
四、js 调用 c++
在之前,我们已经实现了 c++ 调用 js 的功能,是通过 wke 封装好的 runJS
方法实现的。那么 js 调用 c++ 应该如何实现呢?
甚至有些人会问, js 调用 c++ 应该如何测试呢?
1. 创建测试网页
其实在上一节,我漏了很重要的一点没有讲述,那就是如何建立本地的网页测试。为什么要建立呢?因为我们要让 js 与 c++ 交互,就必定需要一个本地的可以测试的界面。
这里我在软件运行路径下,建立了一个文件夹 Html
,在这个文件夹中建立了文件 index.html
,这个 html 文件里面主要就是有一个 img 元素,用来响应指定的 js 方法。
<img id="img_track_event_id" name="img_track_event_name" class="" src="data:images/bd_logo.png" width="300" height="128" onmousedown="CallCPlusPlus()" />
至于这个 index.html
文件如何书写,可以参看我的 demo 项目,这里就不再赘述了(其实作为一个小白,这一块我也是遇到坑了的,不过可以看代码解决的问题,就不在博客里说了,代码里一切都有)。
需要说一下的是,如何使用 wke 载入本地的 html 文件呢:
webView->loadFile(_T("Html/index.html"));
bool b = webView->isLoaded();
只需要让 wke 对象调用 loadFile
方法即可,注意这里的路径设置,需要将 Html 文件夹放到程序的当前运行目录下(或许有些人会问,怎么知道程序的当前运行目录呢?一般都是 sln 的同级目录,不过也可以使用 GetCurrentDirectory
函数来获取,我就是这么获取到的)。
到了现在,我们已经创建了测试的环境,并编写好了测试的网页元素,那么让我们开始吧!
2. 查看 wke 相关接口
首先,让我们看看 wke 提供的接口函数:
WKE_API void jsBindFunction(const char* name, jsNativeFunction fn, unsigned int argCount);
WKE_API void jsBindGetter(const char* name, jsNativeFunction fn); /*get property*/
WKE_API void jsBindSetter(const char* name, jsNativeFunction fn); /*set property*/
这里 jsBindFunction
就是用来绑定 c++ 函数的方法。那么回调函数应该怎么写呢?
#define JS_CALL __fastcall
typedef jsValue (JS_CALL *jsNativeFunction) (jsExecState es);
Got it!
我们现在有了绑定的函数,有了回调函数,只要琢磨清除用法就可以使用了!
那么该如何使用呢?
首先,在 index.html
中写好我们触发的 js 函数:
<script type="text/javascript">function CallCPlusPlus() {msgBox("点击图片由 js 调用 C++ 弹窗", "提示");}
</script>
这里需要解释下的就是,msgBox
我理解为就是一个标签,是一个什么标签呢?是用来在绑定的时候,让 wke 知道,哦,我在 js 中看到了 msgBox
我就把它与某个 c++ 函数绑定起来,然后 msgBox
函数里面自然可以传入参数。这样,通过这个标签,就完成了 js 和 c++ 对于同一个函数的认定响应。
然后,我们在 html 中编写能够触发我们这个 js 函数的元素:
<img id="img_track_event_id" name="img_track_event_name" class="" src="data:images/bd_logo.png" width="300" height="128" onmousedown="CallCPlusPlus()" />
注意这里选择了 onmousedown
也就是鼠标单击行为触发此 js 函数,至此,我们已经完成了界面上需要做的事情。
再然后,我们到调用处,编写我们需要绑定的全局的 c++ 函数:
// 全局的 js 调用 c++ 的函数
jsValue JS_CALL jsMsgBox(jsExecState es)
{const wchar_t *text = jsToStringW(es, jsArg(es, 0));const wchar_t *title = jsToStringW(es, jsArg(es, 1));SOUI::SMessageBox(NULL, text, title, MB_OK);return jsUndefined();
}
这里需要解释下,jsMsgBox
并不是我们之前在 js 函数中写的那个标签 msgBox
。我们在 js 函数里的只是一个绑定时 c++ 和 js 双方都认定的一个标签而已,c++ 函数的名称是可以随便取的,但是函数返回值和参数必须与 wke 声明一致。
另外,传入的参数只有一个es
,wke 通过 jsToStringW(es, jsArg(es, 0))
来解析出函数所需要的参数。这里我们解析出来了两个参数,并使用 SMessageBox
函数显示出来,这里的 SMessageBox
是 SOUI 封装的弹框类。
最后,我们将 js 中的标签 msgBox
与 全局函数 jsMsgBox
绑定起来即可:
// 绑定 js 函数,让 js 主动调用 C++ 函数
jsBindFunction("msgBox", jsMsgBox, 2);
这里 jsBindFunction
函数,第一个参数的含义就是 js 函数中使用到的标签,第二个参数是需要绑定的 c++ 函数名,第三个参数是参数个数。
至此,我们完成了 c++ 部分的编写。
现在,我们运行程序,点击 run c++
,进入测试界面,点击图片,触发 js 方法,调用 c++ 方法,弹框:
成功撒花!!!
五、总结
这些实现的方法都不是我做的。
SOUI 界面库 是 SOUI 作者启程写的;
wke 浏览器内核是 BlzFans 写的;
js 和 c++ 互调方法是 Redrain 写的;
这里我只是摸索着他们的后路,将自己同样实现后的经验和感想分享。
最后,附上我的 demo 代码的 github 地址,希望能对有需要的同学有点启发,JsCplusplusInteractons。
基于 wke 的浏览器:如何实现 js 和 c++ 的互相调用相关推荐
- 基于asp.net + easyui框架,js实现上传图片之前判断图片格式,同时实现预览,兼容各种浏览器+下载...
2019独角兽企业重金招聘Python工程师标准>>> 最近在做图片上传的一个前台页面,上传图片功能虽然很简单,但是需要我们学习的地方很多.在上传图片之前验证图片的格式,并同时实现预 ...
- 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
最近发现有不少介绍JS单线程运行机制的文章,但是发现很多都仅仅是介绍某一部分的知识,而且各个地方的说法还不统一,容易造成困惑. 因此准备梳理这块知识点,结合已有的认知,基于网上的大量参考资料,从浏览器 ...
- js中当等于最小值是让代码不执行_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理...
前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...
- 原来浏览器原生支持JS Base64编码解码
原来浏览器原生支持JS Base64编码解码 转载来源:https://www.zhangxinxu.com/wordpress/2018/08/js-base64-atob-btoa-encode- ...
- 基于Spring Boot 2 和 Vue.js 2 的 食品科学与工程学院网站的设计与实现
摘要 互联网具有传播信息容量大.形态多样.迅速方便.自由和交互等特点,已经发展成为新的传播媒体,现在很多的大学和社会其他部门都已经建立了网站,通过计算机网络实现宣传.交流及资源的整合.建立学校网站有以 ...
- Firefox Profilemaker 基于Web的浏览器配置编辑器
相信不少Firefox用户都有自己的浏览器配置习惯,但是在迁移或重装后的重配置过程却是一件费时费力的事情.不过本文介绍的Firefox Profilemaker,则是一款基于Web的浏览器配置编辑工具 ...
- 浏览器内核及js引擎
找到一篇好文,mark一下: http://www.cnblogs.com/xiyangbaixue/archive/2014/10/22/4042548.html 摘要: 面试一个大公司的时候问到了 ...
- 浏览器内核与js引擎
浏览器内核与js渲染引擎: 简介: 在维基百科上是这样介绍浏览器内核的,网页浏览器的排版引擎(Layout Engine或Rendering Engine)也被称为浏览器内核.页面渲染引擎或模板引擎, ...
- 浏览器内核和js引擎
摘要: 面试一个大公司的时候问到了一个问题,让我谈谈主要的浏览器内核以及他们的特点,当时并没有详细的回答,回来之后自己在网上找了找资料,总结了下分享给大家. 简介: 在维基百科上是这样介绍浏览器内核的 ...
- JavaCV音视频开发宝典:无需流媒体服务也无需转码,使用JavaCV和springBoot实现http-flv转封装直播服务,浏览器网页flv.js直接播放rtp、rtsp、rtmp实时视频
<JavaCV音视频开发宝典>专栏目录导航 <JavaCV音视频开发宝典>专栏介绍和目录 前言 本章代码除了在<JavaCV音视频开发宝典:使用JavaCV和spring ...
最新文章
- C++中explicit关键字的使用
- 批量探测工具fpingping常用命令集合大学霸IT达人
- vueRouter-命名视图
- 在一个数组中删除另一个数组存在的值
- Linux包系列的知识(附:Ubuntu16.04升级到18.04的案例)
- Linux设备模型:kset, kobj, ktype
- pytorch torchvision.transforms.Resize
- 保护你的眼睛,把电脑屏幕由白色改为淡绿
- 使用 paddle来进行文本生成
- Canon600D入手记
- openGL实现太阳系行星系统
- 【给量化行情插上翅膀】天翼云电脑上实践纯Python通过LMDB加速股票行情读写速度
- 计算机中的数学【费马大定理】 数学史上最著名的定理: x^n + y^n = z^n(n 2时,没有正整数解)...
- 【CV系列】颜色恒常性理论及应用
- Mixly 数码管时钟
- 蓝牙芯片NRF51822入门学习:时间管理
- maya拆完uv,画好贴图后导入,模型上贴图显示混乱
- 如何在2小时内用1块钱赚到100块钱?
- 西门子 s7-1200和V90伺服3轴PTO
- 华为文件Android可以删吗,原来华为手机里这些文件夹都可以删!删完立马多出几个G!真棒...
热门文章
- 评《Word排版艺术》-----佐岸
- C语言电影院售票系统
- cad残留卸载清理工具,强力清理CAD注册表残留
- 职称计算机考试excel内容,2020年职称计算机考试EXCEL试题练习
- 韩顺平JAVA学习笔记(入门自用)
- 17-基于51单片机的银行排队叫号系统设计
- Vue - 超详细最新 WangEditor V5 富文本编辑器安装引入及使用教程(内含在 Nuxt.js 项目中引入的解决方案)
- Hive Sql 安装
- Maya: Motion Graphics Workflow with MASH Maya教程:运动图形工作流程与MASH Lynda课程中文字幕
- 超详细的80个Python入门实例,代码清晰拿来即用,学习提升必备