cef和js相互调用方法

目录

 

1 cef调用js

2 js调用Cef

2.1 窗口绑定

2.1.1 绑定变量

2.1.2 绑定存储对象

2.1.3 绑定函数

2.2 拓展

2.2.1 注册变量

2.2.2 注册函数



1 cef调用js

CefFrame::ExecuteJavaScript执行JavaScript() 函数。但是这个方法没有返回值。

c++:

    std::list<CefRefPtr<CefBrowser> > cefBrowerList = m_browserEvent->getCefBrowerList();
    CefRefPtr<CefBrowser> Browser = cefBrowerList.back();
    CefRefPtr<CefFrame>  frame = Browser->GetMainFrame();
    frame->ExecuteJavaScript("input.value = '12';",frame->GetURL(), 0);

Js:

 <input id="input">cef调用js</input>

c++调用后,js界面会将input的值改为12,结果:

2 js调用Cef

js调用cef有两种方法,窗口绑定(Window Binding)和js扩展( Extensions)。窗口绑定是在CefRenderProcessHandler::OnContextCreated闯将V8对象,将V8对象注册到上下文中;js拓展是在CefRenderProcessHandler::OnWebKitInitialized中注册新的V8扩展关联指定的js。

2.1 窗口绑定

将函数或对象绑定到CefFrame相应的window对象上。JS代码通过window对象访问native代码导出的函数或对象

1)simpleApp继承CefRenderProcessHandler,重写GetRenderProcessHandler和OnContextCreated方法。

#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;

    //通过返回值获取render线程,必须重写
	virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE;

    //上下文对象创建后,进入这个函数
	virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE;

    //webkit初始化
	virtual void OnWebKitInitialized()OVERRIDE;

protected:
	IMPLEMENT_REFCOUNTING(SimpleApp);
};

2)在 OnContextCreated中,将函数或者对象绑定到frame。oncontextCreated方法是在context上下文创建的时候进入的的,他在render线程中,不能在主线程中加断点。

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

	//QMessageBox::information(NULL, "OnContextCreated", QString::number(num11++), QMessageBox::Yes);
	// The var type can accept all object or variable
	CefRefPtr<CefV8Value> window = context->GetGlobal();

	// bind value into window[or you can bind value into window sub node]
	//1.绑定变量
	CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString("say yes");
	window->SetValue("say_yes", strValue, V8_PROPERTY_ATTRIBUTE_NONE);

	//2.绑定变量对象,可以在js中设置和获取
	CefRefPtr<CefV8Accessor> accessor = new MyV8Accessor();
	CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor, nullptr);
	obj->SetValue("myval", V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE);
	window->SetValue("MyValObj", obj, V8_PROPERTY_ATTRIBUTE_NONE);

	//3.绑定函数
	// 创建函数处理器
	CefRefPtr<CV8JsHandler> pJsHandler(new CV8JsHandler());
	//创建函数
	CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction("addFunction", pJsHandler);
	//将函数绑定为 window 的 add_Function 属性,供js使用
	window->SetValue("add_Function", myFunc, V8_PROPERTY_ATTRIBUTE_NONE);

	//4.绑定函数
	CefRefPtr<CefV8Handler> handler1 = new CV8JsHandler();
	window->SetValue("register",
		CefV8Value::CreateFunction("register", handler1),
		V8_PROPERTY_ATTRIBUTE_NONE);
}

3) js中调用cef中的对象方法

<!DOCTYPE HTML>
<html>
	<head>
		<meta charset="utf-8" />
		<script type="text/javascript" >
			function showValue()
			{
                alert("value:" + window.say_yes);//1. window bing变量say_yes
            }
            function v8Accessor() {//2. window bing变量myval
                alert("myval: " + window.MyValObj.myval);
                window.MyValObj.myval = "js setting";
            }    
			function sayHellow()
			{
				alert(g_value);
			}
            function add()//3. window bing函数
            {
                // add 函数名不能与window对象挂接addFunction相同
                try {
                    var result = window.add_Function(10, 20);// C++提供的接口,bind到window对象上
                    alert("10 + 20 = " + result);
                } catch (err) {
                    alert("add error message is: " + err.message);
                }
			}
			function jsExt()
			{
				alert(test.myfunc());
            }
            function registerfunction( a, b) {

                return a + b + 1;
            }
            function registerCallBack()
            {
               // window.register(registerfunction);
                alert("registerCallBack:" + window.register(registerfunction) );
            }
            function asyregisterfunction(a, b) {

                return a + b + 2;
            }
            function asyregisterCallBack() {
                var asyr = window.asyregister("test",asyregisterfunction)
                alert("registerCallBack:" + asyr);
            }
		</script>
	</head>
	<body style="width:100%;height:100%;background-color:green;">
		<p>这是c++与JS交互测试脚本</p>
        <div>
            <p>
                <input id="input">cef调用js</input>
            </p>
            <p>
                <button onclick="showValue();">window bind 变量say_yes</button>
            </p>

            <p>
                <button onclick="sayHellow();">拓展 g_value</button>
            </p>
            <p>
                <button onclick="v8Accessor();">window bind v8Accessor</button>
            </p>
            <p>
                <button onclick="add();">两个数相加</button>
            </p>
            <p>
                <button onclick="jsExt();">JS扩展</button>
            </p>
            <p>
                <button onclick="registerCallBack();">回调</button>
            </p>
            <p>
                <button onclick="asyregisterCallBack();">异步回调</button>
            </p>

        </div>
	</body>
</html>

2.1.1 绑定变量

//创建字符串say yes 的对象strlue

 CefRefPtr<CefV8Value> strValue = CefV8Value::CreateString("say yes");

//将对象绑定到say_yes的key值。js可以通过window.say_yes访问字符串对象strValue
    window->SetValue("say_yes", strValue, V8_PROPERTY_ATTRIBUTE_NONE);

可以绑定的类型有int,double,string,arry,object。

js调用方式:window.say_yes

2.1.2 绑定存储对象

不同与上面的变量,通过继承MyV8Accessor的对象,自带get和set方法,就是在js中不只是可以对变量进行取值,也可以对cef中的变量进行赋值。

首先继承MyV8Accessor,定义变量myval。

#ifndef MYV8ACCESSOR_H
#define MYV8ACCESSOR_H

#include "include/cef_v8.h"

class MyV8Accessor : public CefV8Accessor
{
public:
  MyV8Accessor();

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

  virtual bool Set(const CefString& name,
                   const CefRefPtr<CefV8Value> object,
                   const CefRefPtr<CefV8Value> value,
                   CefString& exception) OVERRIDE;

private:
  // Variable used for storing the value.
  CefString myval_ = "myvalue";

  // Provide the reference counting implementation for this class.
  IMPLEMENT_REFCOUNTING(MyV8Accessor);
};

#endif // MYV8ACCESSOR_H

然后实现get和set方法

#include "MyV8Accessor.h"

#include <QMessageBox>


MyV8Accessor::MyV8Accessor()
{
}

bool MyV8Accessor::Get(const CefString &name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value> &retval, CefString &exception)
{
    if (name == "myval")
    {
		QMessageBox::information(NULL, "titile_Get", QString(myval_.ToString().c_str()), QMessageBox::Yes);
        retval = CefV8Value::CreateString(myval_);
        return true;
    }
    // Value does not exist.
    return false;
}

bool MyV8Accessor::Set(const CefString &name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString &exception)
{
    if (name == "myval")
    {
        if (value->IsString())
        {
            myval_ = value->GetStringValue();
			QMessageBox::information(NULL, "titile_Set", QString(myval_.ToString().c_str()),QMessageBox::Yes);
        }
		else 
		{
			// Throw an exception.
            exception = "Invalid value type";
        }
        return true;
    }
    // Value does not exist.
    return false;
}

然后声明v8对象

    CefRefPtr<CefV8Accessor> accessor = new MyV8Accessor();
    CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor, nullptr);

设置对象的变量名称

   obj->SetValue("myval", V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE);

最后v8对象绑定key值

window->SetValue("MyValObj", obj, V8_PROPERTY_ATTRIBUTE_NONE);

js的调用方式:

取值:    window.MyValObj.myval;

设值:     window.MyValObj.myval = "js setting";
 

2.1.3 绑定函数

顾名思义就是js可以直接调用cef中的函数。

首先需要创建一个函数处理器,他继承CefV8Handler类,需要实现Execute方法,在这个方法中定义函数的实现和返回值。

#pragma once
#include "include/cef_v8.h"

class CV8JsHandler : public CefV8Handler
{
public:
	CV8JsHandler(void);
    virtual ~CV8JsHandler() OVERRIDE;

public:
	virtual bool Execute(const CefString& name,//函数名称
						  CefRefPtr<CefV8Value> object,//调用对象
						  const CefV8ValueList& arguments,//函数参数
						  CefRefPtr<CefV8Value>& retval,//返回值
						  CefString& exception) OVERRIDE;//异常信息

	IMPLEMENT_REFCOUNTING(CV8JsHandler);
};

 然后实现addFuntion函数,这里我们实现了一个整数的加法运算。

#include "V8JsHandler.h"

#include<./qmessagebox.h>
CV8JsHandler::CV8JsHandler(void)
{
}

CV8JsHandler::~CV8JsHandler(void)
{

}

bool CV8JsHandler::Execute(const CefString& funcName,
							 CefRefPtr<CefV8Value> object,
							 const CefV8ValueList& arguments,
							 CefRefPtr<CefV8Value>& retval,
							 CefString& exception)
{
    if (funcName == "addFunction")
	{
		int32 nSum = 0;
		for (size_t i = 0; i < arguments.size(); ++i)
		{
			if(!arguments[i]->IsInt())
				return false;
			nSum += arguments[i]->GetIntValue();
		}
        retval = CefV8Value::CreateInt(nSum);
        return true;
	}
    else if (funcName == "addFunction1")
    {
		retval = CefV8Value::CreateString( "call addFunction1");
        return true;
    }
    else if (funcName == "addFunction3")
    {
        int32 nSum = 0;
        for (size_t i = 0; i < arguments.size(); ++i)
        {
            if(!arguments[i]->IsInt())
                return false;
            nSum += arguments[i]->GetIntValue();
        }
        retval = CefV8Value::CreateInt(nSum);
        exception = "not found!";
        return true;
    }
	if (funcName == "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));

			//retval = callbackFunc->ExecuteFunctionWithContext(callbackContext, object, args);
			retval = callbackFunc->ExecuteFunction(NULL, args);
			QMessageBox::information(nullptr, "title", QString("%1").arg(retval->GetIntValue()));
			return true;
		}
	}
    return false;
}

然后创建函数处理器,创建addFuncion函数对象。

	CefRefPtr<CV8JsHandler> pJsHandler(new CV8JsHandler());
	CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction("addFunction", pJsHandler);

绑定函数对象

window->SetValue("add_Function", myFunc, V8_PROPERTY_ATTRIBUTE_NONE);

js的调用方式:var result = window.add_Function(10, 20);

2.2 拓展

使用CefRegisterExtension()注冊JS扩展,JS直接訪问注冊到JS Context中的对象

拓展同Window Binding类似,但是他相当于直接将字符串写入html中。

2.2.1 注册变量

	std::string extensionCode =
		"var g_value=\"g_value set value\";";
	// Register the extension.  
	CefRegisterExtension("v8/mycode", extensionCode, NULL);

js中的调用方法:直接使用g_value

2.2.2 注册函数

首先需要在函数处理器中定义函数,实现函数addFunction1,同Window Binding。

然后声明test对象,声明test对象函数test.myfunc。关联cef函数addFunction1():native functon addFunction1。

然后声明函数处理器对象handler

最后将代码和注册到js中。需要注意的是,CefRegisterExtension第一个参数不能与其他的CefRegisterExtension重复,不然后注册的不起作用。

	std::string extensionCode1 =
		"var test;"
		"if (!test)"
		"  test = {};"
		"(function() {"
		"  test.myfunc = function() {"
		"    native function addFunction1();"
		"    return addFunction1();"
		"  };"
		"})();";
	// Create an instance of my CefV8Handler object.  
	CefRefPtr<CefV8Handler> handler = new CV8JsHandler();
	// Register the extension.  
	CefRegisterExtension("v8/mycode1", extensionCode1, handler);

js中调用方法:test.myfunc()

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值