CEF:C++和JS互動
阿新 • • 發佈:2018-12-27
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);
}