cocos webview js和c++交互

简介: cocos webview js和c++交互

cocos自带了webview组件,对于使用者来说,lua层接口非常简单:

local webView = ccexp.WebView:create()
webView:loadURL(url)
复制代码

2dx仓库中关于webview-win32的pr,但是好像并未完善webview js和c++的交互功能,仅仅实现了一个简单的webview展示。

关于win32 web browser的资料网上的晦涩难懂,找到的一个WebBrowser2-Demo

C++接口的实现代码review

class IDispatch{
  virtual  HRESULT invoke(...);// 
}
class DWebBrowserEvents2:public IDispatch{
}
class Win32WebControl:public DWebBrowserEvents2{
}
复制代码
  • createWebView的实现
CAxWindow _winContainer; // 窗口对象的句柄
IWebBrowser2 *_webBrowser2;// webview控件
Win32WebControl::createWebView(){
  HWND hwnd = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
  _winContainer.Create(hwnd, NULL, NULL, WS_CHILD | WS_VISIBLE);
  // 创建 ActiveX 控件,初始化它并在指定窗口中承载它。
  auto hr = _winContainer.CreateControl(L"shell.Explorer.2"); 
  // 查询指定的控件
  hr = _winContainer.QueryControl(__uuidof(IWebBrowser2), (void **)&_webBrowser2);
}
复制代码
  • loadURL实现
void Win32WebControl::loadURL(BSTR url) const
{
    VARIANT var;
    VariantInit(&var);
    var.vt = VT_BSTR;
    var.bstrVal = url;
    _webBrowser2->Navigate2(&var, NULL, NULL, NULL, NULL);
    VariantClear(&var);
}
复制代码

从c++的实现上观察到,核心在CAxWindow上,从网上找到的一些参考资料来看,win32平台的webview调用了ie的内核进行网页的加载渲染。

js调用c++

webview中的js代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>test</title>
</head>
<body>
    <div id="btn">call cpp</div>
    <script type="text/javascript" charset="UTF-8">
        var btn = document.getElementById('btn')
        btn.addEventListener('click', function() {
            window.external.testFunction(10,'hello test!');
        });
    </script>
</body>
</html>
复制代码

ie内核不支持js es6的特性,比如箭头函数()=>{}等...

js调用c++是通过window.external实现的,而window.external是一个逐渐被废弃的标准,早期是用来实现js和外部程序进行交互的。 以上的网页在普通浏览器运行,点击call cpp是会报错的,提示没有testFunction函数。 在shell.Explorer.2的环境中,是可以正常的。

js call cpp 核心逻辑流程:

1.设置js层window.external.xxx调用到c++层的目标对象。这一步非常重要,是建立通讯的一个桥梁。所有js external的函数调用,都会派发到设置的实例。

// 参数只要是IDispatch的实例即可
_winContainer.SetExternalDispatch(this);
复制代码

2.当js发生external调用时,会先回调步骤1设置的对象的GetIDsOfNames方法,在这一步,我们需要将调用的js函数名映射为一个id

至于为什么要将函数名映射为ID,猜测可能要和事件机制统一流程。

HRESULT STDMETHODCALLTYPE Win32WebControl::GetIDsOfNames(
    REFIID riid, 
    LPOLESTR *rgszNames, // js external 调用的函数名
    UINT cNames, 
    LCID lcid, 
    DISPID *rgDispId)
{
    if(wcscmp(rgszNames[0], L"testFunction") == 0){
        // 注意这里的rgDispId,将作为invoke的dispIdMember的入参
        // 从指针参数可以大概推测出,就是希望开发者控制改写这个参数
        *rgDispId = 199;
        return S_OK;
    }
    return E_NOTIMPL; // 这个返回值将不会调用invoke
}
复制代码
  1. 在这一步,才是我们真正要处理某个js调用真正逻辑的地方。也只有这里,我们才能拿到js传递的参数。
HRESULT STDMETHODCALLTYPE Win32WebControl::Invoke(
  DISPID dispIdMember,
  REFIID riid,
  LCID lcid,
  WORD wFlags,
  DISPPARAMS *pDispParams,
  VARIANT *pVarResult,
  EXCEPINFO *pExcepInfo,
  UINT *puArgErr)
{
    switch(dispIdMember)
    {
        case 199:{
            if (pDispParams->cArgs == 2)
            {
                VARIANTARG rgvarg0 = pDispParams->rgvarg[0];
                VARIANTARG rgvarg1 = pDispParams->rgvarg[1];
                // 参数是倒叙的,rgvarg包含一个union,需要根据type,检索正确的union类型
                rgvarg0.bstrVal; // hello test
                rgvarg1.intVal; // 10
                // todo testFunction logic
                return S_OK;
            }
            break;
        }
    }
}
复制代码

从整体设计上思考,将js的每一个external函数调用都视为了事件,在invoke汇总分发处理,所以在做js函数名id映射时,是否需要注意id和原有的发生冲突? 比如:DISPID_NAVIGATECOMPLETE2DISPID_COMMANDSTATECHANGE ...

关于js函数名和dispId的映射,可以参考思路

IDispatch.invoke详细参数

  • dispIdMember 标识成员。使用 GetIDsOfNames 或对象的文档来获取调度标识符。 在 ActiveX 客户端中,应使用 Invoke 来获取和设置属性值,或调用 ActiveX 对象的方法。dispIdMember 参数标识要调用的成员
  • wFlag
wFlag/value 参数含义
DISPATCH_METHOD/0x1 成员作为方法调用。如果属性具有相同的名称,则可以设置 this 和 DISPATCH_PROPERTYGET 标志。
DISPATCH_PROPERTYGET/0x2 该成员作为属性或数据成员进行检索。
DISPATCH_PROPERTYPUT/0x4 成员被更改为属性或数据成员。
DISPATCH_PROPERTYPUTREF/0x8 成员通过引用分配而不是值分配进行更改。此标志仅在属性接受对对象的引用时才有效。
  • pDispParams 指向包含参数数组、命名参数的参数 DISPID 数组以及数组中元素数的 DISPIDAMS 结构的指针。
  • pVarResult 指向要存储结果的位置的指针,如果调用者不期望结果,则为 NULL。如果指定了 DISPATCH_PROPERTYPUT 或 DISPATCH_PROPERTYPUTREF,则忽略此参数。 简单说:设置js external调用的返回值。
  • pExcepInfo 指向包含异常信息的结构的指针。如果返回 DISP_E_EXCEPTION,则应填写此结构。可以为 NULL。
  • puArgErr rgvarg 中第一个有错误的参数的索引。参数以相反的顺序存储在 pDispParams->rgvarg 中,因此第一个参数是数组中索引最高的参数。仅当结果返回值为 DISP_E_TYPEMISMATCH 或 DISP_E_PARAMNOTFOUND 时才返回此参数。该参数可以设置为空



目录
相关文章
|
6月前
|
数据采集 人工智能 自然语言处理
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
Midscene.js 是一款基于 AI 技术的 UI 自动化测试框架,通过自然语言交互简化测试流程,支持动作执行、数据查询和页面断言,提供可视化报告,适用于多种应用场景。
1750 1
Midscene.js:AI 驱动的 UI 自动化测试框架,支持自然语言交互,生成可视化报告
|
7月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
219 5
|
7月前
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
150 4
|
8月前
|
存储 JavaScript 前端开发
【JavaScript】网页交互的灵魂舞者
本文介绍了 JavaScript 的三种引入方式(行内、内部、外部)和基础语法,包括变量、数据类型、运算符、数组、函数和对象等内容。同时,文章还详细讲解了 jQuery 的基本语法和常用方法,如 `text()`、`html()`、`val()`、`attr()` 和 `css()` 等,以及如何插入和删除元素。通过示例代码和图解,帮助读者更好地理解和应用这些知识。
96 1
【JavaScript】网页交互的灵魂舞者
|
7月前
|
设计模式 前端开发 JavaScript
揭秘!前端大牛们如何巧妙利用JavaScript,打造智能交互体验!
【10月更文挑战第30天】前端开发领域充满了无限可能与创意,JavaScript作为核心语言,凭借强大的功能和灵活性,成为打造智能交互体验的重要工具。本文介绍前端大牛如何利用JavaScript实现平滑滚动、复杂动画、实时数据更新和智能表单验证等效果,展示了JavaScript的多样性和强大能力。
173 4
|
9月前
|
JavaScript 前端开发
JavaScript 与 DOM 交互
【9月更文挑战第01天】
66 2
|
10月前
|
JavaScript 前端开发 UED
Vue.js动画魔法:解锁流畅过渡,让每一次交互都成为用户心中的小确幸!
【8月更文挑战第30天】在Vue.js中,动画与过渡效果不仅是视觉点缀,更是提升用户体验的关键。通过流畅的动态效果,应用的互动性和吸引力得以增强,从而提高用户满意度和参与度。`&lt;transition&gt;`和`&lt;transition-group&gt;`组件结合CSS过渡,可轻松实现元素的进入、离开及列表变化动画。合理的性能优化,如使用硬件加速,能避免页面卡顿,确保动画既美观又高效。下面是一个简单的淡入淡出效果示例,展示了如何利用Vue.js实现平滑的动画过渡。总之,恰当的动画设计能显著提升应用的用户体验。
171 0
Vue.js动画魔法:解锁流畅过渡,让每一次交互都成为用户心中的小确幸!
|
9月前
|
C++ Windows
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
HTML+JavaScript构建C++类代码一键转换MASM32代码平台
|
9月前
|
C++
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具
|
10月前
|
Devops 持续交付 测试技术
JSF遇上DevOps:开发流程将迎巨变?一篇文章带你领略高效协同的魅力!
【8月更文挑战第31天】本文探讨了如何在JavaServer Faces(JSF)开发中融入DevOps文化,通过持续集成与部署、自动化测试、监控与日志记录及反馈机制,提升软件交付速度与质量。文中详细介绍了使用Jenkins进行自动化部署、JUnit与Selenium进行自动化测试、ELK Stack进行日志监控的具体方法,并强调了持续改进的重要性。
92 0

热门文章

最新文章