1.CEF3使用多進程模式,Browser與Render分別處於兩個獨立進程之中;一般而言,Browser進程與我們的窗口進程一致,Render進程是一個獨立的進程。
2.Browser進程和Render進程都包含browser和frame對象;
3.在CEF提供的例子中,主要是通過繼承CefV8Handler,實現其
bool CefV8HandlerEx::Execute(const CefString &name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList &arguments,
CefRefPtr<CefV8Value> &retval,
CefString &exception)
方法來實現js對C++函數的調用。
如果這個函數調用是一個簡單的調用,即當函數調用發生時,如果我們能夠快速的返回結果,那么我們可以通過更改retval的值來返回函數調用結果。
因為這個函數調用是發生在Render進程中的,如果函數調用時,我們想獲取Browser進程內的信息,那我們就需要通過進程間通訊(方式:調用Frame的SendProcessMessage(PID_Browser,msg))告訴Browser進程,但是此時的問題就是,進程間通訊是個異步操作,我們無法通過這個方式獲得結果,所以會導致整個調用不再是連續的,因此js函數調用的結果將不可知,那該如何解決?
我們可以借助於js的異步調用來完成這一點,具體的思路如下:
1.js發起函數調用Func(需要注意這個Func是需要在Render_App的OnContextCreated方法中綁定到Context上,具體可參考https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-window-binding,且有一個CefV8Handler與Func綁定),這個Func傳遞一個回調函數(callback)作為參數;
2.Render進程中的CefV8Handler的Execute檢測到該函數,取得callback參數,將其放入到函數調用緩存中,可以參考https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-asynchronous-javascript-bindings
3.發送一個進程間消息告訴Browser進程,Browser進程需要實現OnProcessMessageReceived方法。Browser接受到該消息以后,完成相應的操作,並發送一個進程間消息告訴Render進程,Render進程同樣也需要實現OnProcessMessageReceived方法;
4.Render進程接受到特定消息以后,檢索出message中包含的參數信息,並從函數調用緩存中查找特定的callback函數;
5.當從在對應的callback時,調用該callback
6.js在Func中傳遞的callback中接收參數信息,並完成后續工作。
需要注意的是:
1.這個RenderApp進程,如果在加載的page中存在多個iframe,則這個OnContextCreated會被調用多次,如果不想再每個iframe中注冊這個Func函數,則將其寫入OnWebKitInitialed中,這個也是Render的一個接口。
2.如果存在多個iframe,並不在同一個域,則有可能會出現有些iframe無法接收消息的情況;
3.CefV8Handler最好實在RenderAPP的構造中初始化一次,不然在存在多個iframe的情況下,可能會出現函數緩存為空的情況,具體原因未知。