Cef3中js与C++交互(五)—— JS简单回调

Native code can execute JS functions by using the ExecuteFunction()
and ExecuteFunctionWithContext() methods. The ExecuteFunction() method
should only be used if V8 is already inside a context as described in
the “Working with Contexts” section. The ExecuteFunctionWithContext()
method allows the application to specify the context that will be
entered for execution.

本地代码可以通过ExecuteFunction()和ExecuteFunctionWithContext()执行JS函数。ExecuteFunction()方法只能在V8对象已经在一个context中时才能进行调用,ExecuteFunctionWithContext()允许程序指定context进入并且执行该函数。

https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md

套路

(1)在 OnJSBinding()中创建一个"register"函数

void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  CefRefPtr<CefV8Handler> handler = new MyV8Handler(this);
  object->SetValue("register",
                   CefV8Value::CreateFunction("register", handler),
                   V8_PROPERTY_ATTRIBUTE_NONE);
}

(2)在MyV8Handler::Execute()的实现中对"register"的context和function保存引用

bool MyV8Handler::Execute(const CefString& name,
                          CefRefPtr<CefV8Value> object,
                          const CefV8ValueList& arguments,
                          CefRefPtr<CefV8Value>& retval,
                          CefString& exception) {
  if (name == "register") {
    if (arguments.size() == 1 && arguments[0]->IsFunction()) {
      callback_func_ = arguments[0];
      callback_context_ = CefV8Context::GetCurrentContext();
      return true;
    }
  }

  return false;
}

(3)通过JavaScript注册JS callback

<script language="JavaScript">
function myFunc() {
  // do something in JS.
}
window.register(myFunc);
</script>

(4)在随后的某个时候执行JS callback

CefV8ValueList args;
CefRefPtr<CefV8Value> retval;
CefRefPtr<CefV8Exception> exception;
if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) {
  if (exception.get()) {
    // Execution threw an exception.
  } else {
    // Execution succeeded.
  }
}

关于JS注册回调,在Asynchronous JavaScript Bindings章节会有更多详细介绍。

public virtual CefRefPtr< CefV8Value > 
ExecuteFunctionWithContext( CefRefPtr< CefV8Context > context,
 							CefRefPtr< CefV8Value > object, 
 							const CefV8ValueList& arguments )= 0;

Execute the function using the specified V8 context. |object| is the
receiver (‘this’ object) of the function. If |object| is empty the
specified context’s global object will be used. |arguments| is the
list of arguments that will be passed to the function. Returns the
function return value on success. Returns NULL if this method is
called incorrectly or an exception is thrown.

返回值如果为NULL,则说明引发了一个错误或者异常。
object表示是receiver 对象,如果该值为空,则用context的全局object将会被使用,context这里就不用多说了,理解为一个上下文环境就行。arguments是参数列表。

为了弄清这些,我用一个简单的例子进行验证:

MyV8Handler.h

#ifndef MYV8HANDLER_H
#define MYV8HANDLER_H

#include "include/cef_v8.h"

class MyV8Handler : public CefV8Handler
{
public:
    MyV8Handler();
    virtual ~MyV8Handler() OVERRIDE;

    virtual bool Execute(const CefString& name,
                         CefRefPtr<CefV8Value> object,
                         const CefV8ValueList& arguments,
                         CefRefPtr<CefV8Value>& retval,
                         CefString& exception) OVERRIDE;

    IMPLEMENT_REFCOUNTING(MyV8Handler);
};

#endif // MYV8HANDLER_H

MyV8Handler.cpp

#include "MyV8Handler.h"
#include <QMessageBox>

MyV8Handler::MyV8Handler()
{
}

MyV8Handler::~MyV8Handler()
{
}

bool MyV8Handler::Execute(const CefString &name,
                          CefRefPtr<CefV8Value> object,
                          const CefV8ValueList &arguments,
                          CefRefPtr<CefV8Value> &retval, CefString &exception)
{
    if (name == "register")
    {
        if (arguments.size() == 1 && arguments[0]->IsFunction())
        {
            CefRefPtr<CefV8Value> callbackFunc = arguments[0];
            CefRefPtr<CefV8Context> callbackContext = CefV8Context::GetCurrentContext();

            CefV8ValueList args;
            args.push_back(CefV8Value::CreateInt(3));
            args.push_back(CefV8Value::CreateInt(4));

            CefRefPtr<CefV8Value> ret = callbackFunc->ExecuteFunctionWithContext(callbackContext, object, args);

            if (ret == nullptr)
            {
                QMessageBox::information(nullptr, "title", QString("is NULL"));
            }
            else
            {
                QMessageBox::information(nullptr, "title", QString("%1").arg(ret->GetIntValue()));
            }
            return true;
        }
     }

     return false;
}

simple_app.h

#pragma once

#include "include/cef_app.h"

class SimpleApp
    : public CefApp
    , public CefBrowserProcessHandler
    , public CefRenderProcessHandler
{
public:
    SimpleApp(void);
    virtual ~SimpleApp() OVERRIDE;

public:
    virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() OVERRIDE;
    virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE;
    virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,CefRefPtr<CefV8Context> context) OVERRIDE;

protected:
    IMPLEMENT_REFCOUNTING(SimpleApp);
};

simple_app.cc

// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

#include "simple_app.h"

#include <string>

#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "simple_handler.h"

#include "MyV8Handler.h"

SimpleApp::SimpleApp()
{
}

SimpleApp::~SimpleApp()
{
}

CefRefPtr<CefBrowserProcessHandler> SimpleApp::GetBrowserProcessHandler()
{
    return this;
}

CefRefPtr<CefRenderProcessHandler> SimpleApp::GetRenderProcessHandler()
{
    return this;
}

void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
    CEF_REQUIRE_RENDERER_THREAD()

    CefRefPtr<CefV8Value> window = context->GetGlobal();

    CefRefPtr<CefV8Handler> handler = new MyV8Handler();
    window->SetValue("register",
                   CefV8Value::CreateFunction("register", handler),
                   V8_PROPERTY_ATTRIBUTE_NONE);
}

index.html

<!DOCTYPE HTML>
<html>
	<head>
		<meta charset="utf-8" />
		<script type="text/javascript" >
			function registerCallBack()
			{
				try{
					function add(a, b) {
						alert("a + b: " + (a + b));
						return (a+b);
					}
					window.register(add)
				}catch(err){
					alert("error message: " + err.message);
				}
			}
		</script>
	</head>
	<body style="width:100%;height:100%;background-color:green;">
		<p>这是c++与JS交互测试脚本</p>
		<div >
			<button onclick="registerCallBack();">Js中注册回调</button>
		</div>
	</body>
</html>

在这里插入图片描述

在这里插入图片描述

OnContextCreated中绑定了一个register函数在window对象上,这里也可以用JS扩展的方式。
具体可以参考 Cef3中js与C++交互(三)——JS扩展

这里没有保存context和JS函数,进行异步回调,只演示了最简单的JS回调。接下来会介绍复杂一些的JS异步回调。

链接:https://pan.baidu.com/s/1OnVsx18GnaT73Sx8zxNvwg
提取码:wjkq

参考:
CEF:注册JS回调

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值