1. 程式人生 > >CEF:C++和JS互動

CEF:C++和JS互動

CEF 中的JavaScript

  • CEF 利用 V8 JS 引擎來實現 JS。
  • 瀏覽器中的每一個 frame 都有自己的 JS 上下文,JS 只能在該上下文中執行。
  • JS 只能在渲染程序中的 TID_RENDERER 執行緒中執行。
  • 有關 JS 回撥的介面都包含在 CefRenderProcessHandler 中,因此我們要實現這個介面來對 JS 進行擴充套件。這個介面一般由 CefApp 實現。

C++呼叫JS

事實上cef本身支援直接執行js(js程式碼或者js函式)的介面,原型如下:

  ///
  // Execute a string of JavaScript code in this frame. The |script_url|
  // parameter is the URL where the script in question can be found, if any.
  // The renderer may request this URL to show the developer the source of the
  // error.  The |start_line| parameter is the base line number to use for error
  // reporting.
  ///
  /*--cef(optional_param=script_url)--*/
  virtual void ExecuteJavaScript(const CefString& code,
                                 const CefString& script_url,
                                 int start_line) = 0;

所以我們可以封裝該函式,以提供自己直接呼叫:

//@param js js程式碼或者函式,
//eg:js="add(1,2)"
void CBrowserHandler::ExeJs(const CefString &js)
{
	...
	browser->GetMainFrame()->ExecuteJavaScript(js, L"", 0);
	...
}

#######################################C++呼叫JS測試,直接通過ExeJs("add(10,20)")呼叫JS函式####################
//JS:
function call_add(val1,val2)
{
	alert(window.add(val1,val2));
}

//C++
...
if (m_browser_app)
	m_browser_app->ExeJs(L"call_add(10,20)");
...

在這裡插入圖片描述

JS呼叫C++(Render程序實現)

繫結值到Window物件

在CefRenderProcessHandler::OnContextCreated() 中繫結一些值給 JS 的 window 物件。

class CRenderApp :public CefApp, public CefRenderProcessHandler
void CRenderApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
	CefRefPtr<CefFrame> frame,
	CefRefPtr<CefV8Context> context)
{
 	CEF_REQUIRE_RENDERER_THREAD();
 	
	//GetGlobal獲取的是window物件,所以該值則直接繫結到windows物件上面
	CefRefPtr<CefV8Value> object = context->GetGlobal();
	CefRefPtr<CefV8Value> v8Value = CefV8Value::CreateString("c++ value");
	object->SetValue("MyValue", v8Value, V8_PROPERTY_ATTRIBUTE_NONE);
}


#######################################JS測試,直接通過window.MyValue訪問####################
<script>
function show(){
	alert(window.MyValue);
}
</script>

在這裡插入圖片描述

繫結函式到Window物件

原理類似繫結物件到Window物件,只是建立的物件是Function,然後通過繼承CefV8Handler重寫Execute 實現具體的Function功能。

//函式處理器,處理add函式
bool CJSAdd::Execute(const CefString& name,
	CefRefPtr<CefV8Value> object,
	const CefV8ValueList& arguments,
	CefRefPtr<CefV8Value>& retval,
	CefString& exception)
{
	if (name == "add")
	{
		int32  val1 = arguments[0]->GetIntValue();
		int32  val2 = arguments[1]->GetIntValue();
		int32 sum = val1 + val2;
		retval = CefV8Value::CreateInt(sum);
		return true;
	}
	return false;
}

//繫結add函式到windows物件
void CRenderApp::OnContextCreated(CefRefPtr<CefBrowser> browser,
	CefRefPtr<CefFrame> frame,
	CefRefPtr<CefV8Context> context)
{
	 CEF_REQUIRE_RENDERER_THREAD();
	 
	//新增全域性函式
	//建立函式處理器
	CefRefPtr<CefV8Handler> add_handler = new CJSAdd();
	
	 // 建立函式
	CefRefPtr<CefV8Value> add_func = CefV8Value::CreateFunction("add", add_handler);
	
	 // 將函式繫結為 window 的 add 屬性
	object->SetValue("add", add_func, V8_PROPERTY_ATTRIBUTE_NONE);
}

#######################################JS測試,直接通過window.add呼叫函式####################
	function call_add(val1,val2)
	{
		//直接通過window,呼叫add函式
		alert(window.add(val1,val2));
	}

在這裡插入圖片描述

擴充套件JS

在 CefRenderProcessHandler::OnWebKitInitialized() 中將 JS 指令碼注入到 V8 中。
只能被Render 程序的主執行緒呼叫

擴充套件值和函式

更詳細的demo可以參考CefRegisterExtension 類的說明

void CRenderApp::OnWebKitInitialized()
{
	CEF_REQUIRE_RENDERER_THREAD();

	// Define the extension contents.
	std::string extensionCode =
		"var MyMath;"
		"if (!MyMath)"//如果沒有MyMath物件,則定義一個MyMath物件
		"  MyMath = {};"
		"(function() {"
		"  MyMath.add = function(num1, num2) {"//定義一個MyMath的add函式
		"    native function add(num1, num2);"
		"    return add(num1, num2);"//add在CefV8Handler具體實現
		"  };"
		"  MyMath.hellow = 'Hello JS!';"//定義一個MyMath的成員變數
		"})();";

	CefRefPtr<CefV8Handler> add_handler = new CJSAdd();
	// Register the extension.
	CefRegisterExtension("v8/test", extensionCode, add_handler);
}

###################JS測試,直接通過MyMath.add呼叫函式,MyMath.hellow獲取成員變數####################
function CallMyMathAdd()
	{
		v1 = document.getElementById('num1').value;
		v2 = document.getElementById('num2').value;
		alert(MyMath.add(Number(v1),Number(v2)));
	}
	
	function ShowMyMathHellow()
	{
		alert(MyMath.hellow);
	}

在這裡插入圖片描述

在這裡插入圖片描述