1. 程式人生 > >CEF和JS交互

CEF和JS交互

itl setting 代碼 js調用 ear object 事件 分享圖片 handle

技術分享圖片

CefClient提供所有瀏覽器事件處理的接口,重寫CefClient類中的方法處理瀏覽器事件:包括Browser的生命周期,右鍵菜單,對話框,狀態通知顯示,下載事件,拖曳事件,焦點事件,鍵盤事件,離屏渲染事件等,對Cef進行行為控制的方法一般都集中在這些接口。

/*

註冊瀏覽器生命周期的事件類CefLifeSpanHandler的實例。

重寫CefLifeSpanHandler接口類中的方法實現對browser對象周期回調事件的處理:

*/

virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() { return NULL;}

//當新browser對象被創建後馬上觸發,重寫此方法保存所有創建的browser對象的指針。

void OnAfterCreated(CefRefPtr<CefBrowser> browser)

//當調用CloseBrowser函數後觸發

bool DoClose(CefRefPtr<CefBrowser> browser)

//當browser對象被銷毀前觸發,必須重寫此方法且完成釋放對所有browser對象的指針。

void OnBeforeClose(CefRefPtr<CefBrowser> browser)

//當window render無法完成時采用離屏渲染,重寫CefRenderHandler類中的方法實現離屏渲染回調事件的處理:

virtual CefRefPtr<CefRenderHandler> GetRenderHandler() { return NULL; }

//根窗口創建後觸發,通過此接口可獲取根窗口在屏幕的位置坐標。

bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) { return false; }

//當browser對象初始化或者大小改變時觸發,通過此接口獲取browser對象在窗口的位置坐標。

bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect)=0

virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() {return NULL;}

Browser對象顯示狀態的事件處理。

virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() { return NULL;}

與JavaScript dialogs相關的回調事件的處理,CefJSDialogHandler接口類中的方法在UI線程中調用。

virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefProcessId source_process,CefRefPtr<CefProcessMessage> message) {return false;}

進程間通信接口,實現browser進程和render進程間的通信。當收到其他進程的消息時觸發,當消息被處理後返回true。此回調函數外不可使用其他進程的消息或此消息的引用。

其他瀏覽器的回調事件(拖拽、下載、查找、焦點、鍵盤等)都在CefClient類中有對應的註冊接口。

CefApp負責進程的實例化及退出。重寫Cef類中的GetBrowserProcessHandler()及GetRenderProcessHandler()方法創建browser進程及render進程的實例。

CefBrowser及CefFrame為不可實例化的抽象類。其中,CefBrowser類表示一個瀏覽器窗口,CefFrame類表示瀏覽器窗口中的一塊區域,一個瀏覽器窗口可包含多個Frame塊。兩者中的方法在browser進程中使用時一般可在所有線程中使用,在render進程中一般只能在主線程中使用。

啟動Render進程:

1) 單一執行:browser主進程調用CefExcuteProcess()方法之後創建render子進程。分析CefExcuteProcess()方法的代碼:首先根據命令行參數的type參數,如果為NULL,說明為主進程,返回-1,回到主程序,執行創建窗口等主進程代碼。如果不為NULL,會在chrome代碼裏創建render進程。

2) 獨立子進程執行:需要兩個分開的工程和分開的入口函數。在主程序中的CefSettings settings中增加CefString(&settings.browser_subprocess_path)=子進程執行路徑。

JS加載及與Cef的交互由Render進程處理,因此CefApp的GetRenderProcessHandler()方法必須提供實現,否則OnContextCreate()和OnWebktiInitialized()接口無法被調用。定義類繼承自CefApp和CefRenderProcessHandler,重寫CefApp中的GetRenderProcessHandler()方法並返回render進程實例的指針。CefRenderProcessHandler中的OnContextCreate()接口會在Frame的context創建後被調用,提供js與Cef代碼交互的功能。

Cef基於Chrome,Chrome使用v8jsEngine執行內部的js。根據v8的規範,執行一段js代碼必須顯式指定context,因此在調用js代碼的時候必須先進入context,而每一個Frame有屬於自己的context,每一次Frame加載都會調用OnContextCreate()方法。

1) Cef調用JS:

Cef代碼可以通過調用CefFrame::ExecuteJavaScript()方法執行js代碼。

frame->ExecuteJavaScript(const CefString& jsCode,const CefString& frame->GetURL(), int startLine);

context所在的CefRefPtr<CefFrame> frame和CefRefPtr<CefBrowser> browser在OnContextCreate()接口中獲取。

2) JS調用Cef

①重寫OnContextCreate()方法,從OnContextCreate()接口提供的context中通過context-GetGlobal()獲取window對象,window對象聲明為cefV8Value類型(相當於js中所有對象和值都以var聲明)。通過window-> SetValue(const CefString& key, CefRefPtr<CefV8Value> value, PropertyAttribute attribute)方法實現綁定該窗口對象下某一個CefV8Value類型對象(方法中參數value)和一特定標識符(方法中參數key)。

用來綁定的CefV8Value類型對象包含js基本數據類型(int,double,string,bool等)用CefV8Value::Create靜態方法創建,例如string類型用CefV8Value::CreateString創建;以及js數組和對象類型,用靜態方法CefV8Value::CreateArray()或CefV8Value::CreateObject ()創建。

②用來綁定的CefV8Value類型對象可以是函數對象定義一個類(例如MyCefV8Handler)繼承自CefV8Handler,

利用

CefRefPtr<MyCefV8Handler> handler (new MyCefV8Handler());

CefV8Value func=CefV8Value::CreateFunction(const CefString& name, CefRefPtr<CefV8Handler> handler) 方法創建函數對象並調用window-> SetValue()進行綁定。CreateFunction傳入的參數為函數名和實例化的MyCefV8Handler對象,並且在MyCefV8Handler類中必須重寫CefV8Handler中的Execute()方法判斷js調用的Cef方法並接收參數及傳遞返回值。

JS調用Cef中的方法示例代碼:

//自定義SimRender類繼承CefApp類和CefRenderProcessHandler類

class simpleRender :public CefApp, public CefRenderProcessHandler

{

public:

//重寫GetRenderProcessHandler方法,render進程啟動時被喚醒來創建render進程的示例

void CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE

{

return this;

}

//重寫OnContextCreated方法,每一次Frame加載都會調用OnContextCreate()方法,綁定window對象

void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE

{

//獲取window對象

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

//創建MyCefV8Handler對象實例

CefRefPtr<MyCefV8Handler> handler(new MyCefV8Handler());

//創建函數對象myFunc

CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction(_T("func"), handler);

//綁定函數對象myFunc和以標識符“func”,js通過window.func調用Cef代碼

window->SetValue(_T("func"), myFunc, V8_PROPERTY_ATTRIBUTE_NONE);

}

}

//自定義MyCefV8Handler類繼承CefV8Handler類

class MyCefV8Handler :public CefV8Handler

{

public:

//重寫Execute方法判斷js調用的Cef方法

bool Execute(const CefString& func_name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)

{

if (func_name == _T("func"))

{

retval = CefV8Value::CreateString(_T("func: C++!"));

return true;

}

return false;

}

}

js中:

<script type="text/javascript">

Function f()

{

var retval=window.func();

window.alert(retval);

}

</script>

CEF和JS交互