自己開(kāi)發(fā)了一個(gè)股票智能分析軟件,功能很強(qiáng)大,需要的點(diǎn)擊下面的鏈接獲?。?/strong> https://www.cnblogs.com/bclshuai/p/11380657.html CEF使用說(shuō)明書 目錄 1 前言 1.1 CEF的作用 1.2 CEF的下載和編譯 1.3 CEF結(jié)構(gòu) 1.3.1 CEF進(jìn)程和窗口之間的結(jié)構(gòu)關(guān)系 1.3.2 Renderer進(jìn)程的實(shí)現(xiàn)結(jié)構(gòu) 1.3.3 browser進(jìn)程的實(shí)現(xiàn)結(jié)構(gòu) 1.4 CEF多進(jìn)程和多線程 1.4.1 進(jìn)程 1.4.2 線程 1.5 網(wǎng)頁(yè)嵌入應(yīng)用程序結(jié)構(gòu) 1.5.1 入口函數(shù) 1.5.2 CEF單實(shí)例進(jìn)程 1.5.3 主子進(jìn)程的模式 1.6 CefBrowser 瀏覽器窗口類 1.7 CefBrowserHost瀏覽器操作控制類 1.8 CefFrame網(wǎng)頁(yè)界面類 1.9 CefApp應(yīng)用程序類 1.10 CEF引用計(jì)數(shù) 1.11 CEF自定義字符串 1.11.1 為什么自定義字符串類型 1.11.2 字符串操作函數(shù)CefString 1.11.3 CEF與String的轉(zhuǎn)換 2 Cef常用接口類介紹 2.1 CefClient 2.2 CefContextMenuHandler右鍵菜單處理類 2.3 CefDisplayHandler網(wǎng)頁(yè)顯示處理類 2.4 CefDownloadHandler網(wǎng)頁(yè)下載處理類 2.5 CefDragHandler鼠標(biāo)拖動(dòng)到網(wǎng)頁(yè)處理類 2.6 CefKeyboardHandler鍵盤事件響應(yīng)處理類 2.7 CefLifeSpanHandler生命周期處理類 2.7.1 DoClose標(biāo)準(zhǔn)關(guān)閉處理 2.7.2 DoClose非標(biāo)準(zhǔn)關(guān)閉處理 2.8 CefLoadHandler網(wǎng)頁(yè)加載處理類 2.9 CefRequestHandler網(wǎng)絡(luò)請(qǐng)求處理類 3 CEF高級(jí)應(yīng)用 3.1 CEF和JavaScript交互 3.1.1 在CEF執(zhí)行JavaScript腳本 3.1.2 Extension方式實(shí)現(xiàn)JavaScript執(zhí)行CEF中的函數(shù) 3.2 CEF進(jìn)程間通訊 3.2.1 進(jìn)程間通訊函數(shù) 3.2.2 進(jìn)程通訊實(shí)例 3.2.3 CEF指定frame通訊
1 前言1.1 CEF的作用CEF全稱Chromium Embedded Framework,是一個(gè)基于Google Chromium 的開(kāi)源項(xiàng)目。Google Chromium項(xiàng)目主要是為Google Chrome應(yīng)用開(kāi)發(fā)的,而CEF的目標(biāo)則是為第三方應(yīng)用提供可嵌入瀏覽器支持。CEF作用是在客戶端嵌入網(wǎng)頁(yè)界面。
1.2 CEF的下載和編譯https://blog.csdn.net/csdnyonghu123/article/details/87982333
如圖所示,CefClient工程是一個(gè)簡(jiǎn)單版的網(wǎng)頁(yè)瀏覽器demo,有網(wǎng)址輸入、前進(jìn)后退等。 CefSimple更簡(jiǎn)單的網(wǎng)頁(yè)工程,網(wǎng)址在代碼設(shè)置,打開(kāi) 直接渲染網(wǎng)頁(yè)。 CefTest測(cè)試工程。 AllBuild是一個(gè)偽工程,用來(lái)執(zhí)行編譯其他工程。
libcef_dll_wrapper是cef的動(dòng)態(tài)庫(kù)工程,。 include是頭文件 Release文件夾包含輸出的庫(kù)文件和依賴庫(kù)文件,自己開(kāi)發(fā)項(xiàng)目時(shí)將include和release文件復(fù)制到工程即可。參考CefSimple和CefClient代碼實(shí)例。
1.3 CEF結(jié)構(gòu)1.3.1 CEF進(jìn)程和窗口之間的結(jié)構(gòu)關(guān)系一個(gè)瀏覽器有很多個(gè)CefBrowser窗口,這些窗口都是在Browser進(jìn)程中創(chuàng)建。browser進(jìn)程用來(lái)管理和處理回調(diào)函數(shù)消息。 Renderer進(jìn)程用來(lái)實(shí)現(xiàn)網(wǎng)頁(yè)的渲染,每個(gè)renderer進(jìn)程包含有一個(gè)主網(wǎng)頁(yè)mainframe和多個(gè)子網(wǎng)頁(yè)subframe,。
1.3.2 Renderer進(jìn)程的實(shí)現(xiàn)結(jié)構(gòu)renderer程序繼承CefApp和CefRenderProcessHandler類,在main函數(shù)中初始化。通過(guò)CefSettings.browser_subprocess_path配置render可執(zhí)行程序路徑。browser進(jìn)程就會(huì)去啟動(dòng)這個(gè)進(jìn)程去渲染網(wǎng)頁(yè)。
1.3.3 browser進(jìn)程的實(shí)現(xiàn)結(jié)構(gòu)browserapp要繼承CefApp和CefBrowserProcessHandler類。實(shí)現(xiàn)browserapp的定義。同時(shí)要新建clienthandler類實(shí)現(xiàn)圖中的回調(diào)函數(shù)接口類,用來(lái)處理攔截響應(yīng)請(qǐng)求、管理生命周期、下載、顯示加載、右鍵菜單等。在mian函數(shù)中初始化、啟動(dòng)消息循環(huán)。調(diào)用CefBrowserHost的靜態(tài)方法創(chuàng)建browser窗口對(duì)象,在render進(jìn)程的Frame中加載渲染內(nèi)容。
1.4 CEF多進(jìn)程和多線程1.4.1 進(jìn)程CEF3是多進(jìn)程架構(gòu)的,CEF3進(jìn)程主要有一個(gè)Browser(瀏覽器)進(jìn)程和多個(gè)Renderer(渲染)進(jìn)程。Browser被定義為主進(jìn)程,負(fù)責(zé)窗口管理,網(wǎng)絡(luò)請(qǐng)求,網(wǎng)頁(yè)管理 、網(wǎng)絡(luò)交互。browser從服務(wù)器器請(qǐng)求到了響應(yīng),將html文本發(fā)送給Renderer 進(jìn)程,render進(jìn)程加載html,進(jìn)行渲染,展示網(wǎng)頁(yè)的內(nèi)容;除此之外,Renderer進(jìn)程還負(fù)責(zé)Js Binding和對(duì)Dom節(jié)點(diǎn)的訪問(wèn)。Browser和Renderer進(jìn)程可以通過(guò)發(fā)送異步消息進(jìn)行雙向通信。主應(yīng)用程序很大,加載時(shí)間比較長(zhǎng),或者不能在非瀏覽器進(jìn)程里使用,則宿主程序可使用獨(dú)立的可執(zhí)行文件去運(yùn)行這些Renderer進(jìn)程。這可以通過(guò)配置CefSettings.browser_subprocess_path變量做到。 1.4.2 線程Browser進(jìn)程中包含如下主要的線程:
1.5 網(wǎng)頁(yè)嵌入應(yīng)用程序代碼構(gòu)成和實(shí)例每個(gè)CEF3應(yīng)用程序都是相同的結(jié)構(gòu)
1.5.1 入口函數(shù)需要在程序的入口函數(shù)執(zhí)行cef對(duì)象創(chuàng)建,初始化,命令行參數(shù)解析,CEF屬性設(shè)置,和CEF消息循環(huán)開(kāi)啟等。CEF需要啟動(dòng)一個(gè)主進(jìn)程來(lái)管理網(wǎng)頁(yè)見(jiàn)面。這個(gè)主進(jìn)程就是在man函數(shù)中啟動(dòng),進(jìn)入消息循環(huán),直到程序結(jié)束,才退出main函數(shù)。 1.5.2 CEF單實(shí)例進(jìn)程單例進(jìn)程模式就是CEF的啟動(dòng),網(wǎng)頁(yè)的打開(kāi)都在 int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface. CefRefPtr<MyApp> app(new MyApp);
// Execute the sub-process logic, if any. This will either return immediately for the browser // process or block until the sub-process should exit. int exit_code = CefExecuteProcess(main_args, app.get()); if (exit_code >= 0) { // The sub-process terminated, exit now. return exit_code; }
// Populate this structure to customize CEF behavior. CefSettings settings;
// Initialize CEF in the main process. CefInitialize(main_args, settings, app.get());
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called. CefRunMessageLoop();
// Shut down CEF. CefShutdown();
return 0; } 1.5.3 主子進(jìn)程的模式主進(jìn)程和子進(jìn)程分開(kāi)的模式,主進(jìn)程運(yùn)行browser進(jìn)程,網(wǎng)頁(yè)加載放在子進(jìn)程render進(jìn)程中。這是需要?jiǎng)?chuàng)建兩個(gè)進(jìn)程和兩個(gè)主函數(shù)。 主程序的入口函數(shù): // Program entry-point function. // 程序入口函數(shù) int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. // 傳遞命令行參數(shù)的結(jié)構(gòu)體。 // 這個(gè)結(jié)構(gòu)體的定義與平臺(tái)相關(guān)。 CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface. // 可選擇性地實(shí)現(xiàn)CefApp接口 CefRefPtr<MyApp> app(new MyApp);
// Populate this structure to customize CEF behavior. // 填充這個(gè)結(jié)構(gòu)體,用于定制CEF的行為。 CefSettings settings;
// Specify the path for the sub-process executable. // 指定子進(jìn)程的執(zhí)行路徑 CefString(&settings.browser_subprocess_path).FromASCII(“/path/to/subprocess”);
// Initialize CEF in the main process. // 在主進(jìn)程中初始化CEF CefInitialize(main_args, settings, app.get());
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called. // 執(zhí)行消息循環(huán),此時(shí)會(huì)堵塞,直到CefQuitMessageLoop()函數(shù)被調(diào)用。 CefRunMessageLoop();
// Shut down CEF. // 關(guān)閉CEF CefShutdown();
return 0; } 子進(jìn)程程序的入口函數(shù):
// Program entry-point function. // 程序入口函數(shù) int main(int argc, char* argv[]) { // Structure for passing command-line arguments. // The definition of this structure is platform-specific. // 傳遞命令行參數(shù)的結(jié)構(gòu)體。 // 這個(gè)結(jié)構(gòu)體的定義與平臺(tái)相關(guān)。 CefMainArgs main_args(argc, argv);
// Optional implementation of the CefApp interface. // 可選擇性地實(shí)現(xiàn)CefApp接口 CefRefPtr<MyApp> app(new MyApp);
// Execute the sub-process logic. This will block until the sub-process should exit. // 執(zhí)行子進(jìn)程邏輯,此時(shí)會(huì)堵塞直到子進(jìn)程退出。 return CefExecuteProcess(main_args, app.get()); } 1.6 CefBrowser 瀏覽器窗口類CefBrowser是瀏覽器窗口類,相當(dāng)于瀏覽器的外殼框架窗口,包含向前、向后、加載、獲取內(nèi)部frame的等方法。調(diào)用CefBrowserHost的靜態(tài)方法創(chuàng)建一個(gè)CefBrowser對(duì)象,表示一個(gè)網(wǎng)頁(yè)窗口。 /// // Class used to represent a browser window. When used in the browser process // the methods of this class may be called on any thread unless otherwise // indicated in the comments. When used in the render process the methods of // this class may only be called on the main thread. /// /*--cef(source=library)--*/ class CefBrowser : public virtual CefBaseRefCounted { public: /// // Returns the browser host object. This method can only be called in the // browser process. /// /*--cef()--*/ virtual CefRefPtr<CefBrowserHost> GetHost() = 0;
/// // Returns true if the browser can navigate backwards. /// /*--cef()--*/ virtual bool CanGoBack() = 0;
/// // Navigate backwards. /// /*--cef()--*/ virtual void GoBack() = 0;
/// // Returns true if the browser can navigate forwards. /// /*--cef()--*/ virtual bool CanGoForward() = 0;
/// // Navigate forwards. /// /*--cef()--*/ virtual void GoForward() = 0;
/// // Returns true if the browser is currently loading. /// /*--cef()--*/ virtual bool IsLoading() = 0;
/// // Reload the current page. /// /*--cef()--*/ virtual void Reload() = 0;
/// // Reload the current page ignoring any cached data. /// /*--cef()--*/ virtual void ReloadIgnoreCache() = 0;
/// // Stop loading the page. /// /*--cef()--*/ virtual void StopLoad() = 0;
/// // Returns the globally unique identifier for this browser. This value is also // used as the tabId for extension APIs. /// /*--cef()--*/ virtual int GetIdentifier() = 0;
/// // Returns true if this object is pointing to the same handle as |that| // object. /// /*--cef()--*/ virtual bool IsSame(CefRefPtr<CefBrowser> that) = 0;
/// // Returns true if the window is a popup window. /// /*--cef()--*/ virtual bool IsPopup() = 0;
/// // Returns true if a document has been loaded in the browser. /// /*--cef()--*/ virtual bool HasDocument() = 0;
/// // Returns the main (top-level) frame for the browser window. /// /*--cef()--*/ virtual CefRefPtr<CefFrame> GetMainFrame() = 0;
/// // Returns the focused frame for the browser window. /// /*--cef()--*/ virtual CefRefPtr<CefFrame> GetFocusedFrame() = 0;
/// // Returns the frame with the specified identifier, or NULL if not found. /// /*--cef(capi_name=get_frame_byident)--*/ virtual CefRefPtr<CefFrame> GetFrame(int64 identifier) = 0;
/// // Returns the frame with the specified name, or NULL if not found. /// /*--cef(optional_param=name)--*/ virtual CefRefPtr<CefFrame> GetFrame(const CefString& name) = 0;
/// // Returns the number of frames that currently exist. /// /*--cef()--*/ virtual size_t GetFrameCount() = 0;
/// // Returns the identifiers of all existing frames. /// /*--cef(count_func=identifiers:GetFrameCount)--*/ virtual void GetFrameIdentifiers(std::vector<int64>& identifiers) = 0;
/// // Returns the names of all existing frames. /// /*--cef()--*/ virtual void GetFrameNames(std::vector<CefString>& names) = 0;
/// // Send a message to the specified |target_process|. Returns true if the // message was sent successfully. /// /*--cef()--*/ virtual bool SendProcessMessage(CefProcessId target_process, CefRefPtr<CefProcessMessage> message) = 0; }; 1.7 CefBrowserHost瀏覽器操作控制類CefBrowserHost是CefBrowser的一個(gè)主對(duì)象,CefBrowser中有方法virtual CefRefPtr<CefBrowserHost> GetHost() = 0;返回CefBrowser的主CefBrowserHost對(duì)象。然而CefBrowser對(duì)象又是通過(guò)CefBrowserHost類的靜態(tài)方法來(lái)創(chuàng)建的。CefBrowserHost類包含一些CefBrowser操作方法,相當(dāng)于是控制類,可以控制CefBrowser的創(chuàng)建、獲取、關(guān)閉;獲取打開(kāi)CefBrowser窗口的窗口句柄、請(qǐng)求上下文(RequestContext);下載、查找、鼠標(biāo)、鍵盤觸發(fā)事件、焦點(diǎn)控制、拖拽事件等。 class CefBrowserHost : public virtual CefBaseRefCounted { public: typedef cef_drag_operations_mask_t DragOperationsMask; typedef cef_file_dialog_mode_t FileDialogMode; typedef cef_mouse_button_type_t MouseButtonType; typedef cef_paint_element_type_t PaintElementType;
/// // Create a new browser window using the window parameters specified by // |windowInfo|. All values will be copied internally and the actual window // will be created on the UI thread. If |request_context| is empty the // global request context will be used. This method can be called on any // browser process thread and will not block. /// /*--cef(optional_param=client,optional_param=url, optional_param=request_context)--*/ static bool CreateBrowser(const CefWindowInfo& windowInfo, CefRefPtr<CefClient> client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr<CefRequestContext> request_context);
/// // Create a new browser window using the window parameters specified by // |windowInfo|. If |request_context| is empty the global request context // will be used. This method can only be called on the browser process UI // thread. /// /*--cef(optional_param=client,optional_param=url, optional_param=request_context)--*/ static CefRefPtr<CefBrowser> CreateBrowserSync( const CefWindowInfo& windowInfo, CefRefPtr<CefClient> client, const CefString& url, const CefBrowserSettings& settings, CefRefPtr<CefRequestContext> request_context);
/// // Returns the hosted browser object. /// /*--cef()--*/ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
/// // Request that the browser close. The JavaScript 'onbeforeunload' event will // be fired. If |force_close| is false the event handler, if any, will be // allowed to prompt the user and the user can optionally cancel the close. // If |force_close| is true the prompt will not be displayed and the close // will proceed. Results in a call to CefLifeSpanHandler::DoClose() if the // event handler allows the close or if |force_close| is true. See // CefLifeSpanHandler::DoClose() documentation for additional usage // information. /// /*--cef()--*/ virtual void CloseBrowser(bool force_close) = 0;
/// // Helper for closing a browser. Call this method from the top-level window // close handler. Internally this calls CloseBrowser(false) if the close has // not yet been initiated. This method returns false while the close is // pending and true after the close has completed. See CloseBrowser() and // CefLifeSpanHandler::DoClose() documentation for additional usage // information. This method must be called on the browser process UI thread. /// /*--cef()--*/ virtual bool TryCloseBrowser() = 0;
/// // Set whether the browser is focused. /// /*--cef()--*/ virtual void SetFocus(bool focus) = 0;
/// // Retrieve the window handle for this browser. If this browser is wrapped in // a CefBrowserView this method should be called on the browser process UI // thread and it will return the handle for the top-level native window. /// /*--cef()--*/ virtual CefWindowHandle GetWindowHandle() = 0;
/// // Retrieve the window handle of the browser that opened this browser. Will // return NULL for non-popup windows or if this browser is wrapped in a // CefBrowserView. This method can be used in combination with custom handling // of modal windows. /// /*--cef()--*/ virtual CefWindowHandle GetOpenerWindowHandle() = 0; //…………………… } 1.8 CefFrame網(wǎng)頁(yè)界面類每個(gè)CefBrowser窗口包含一個(gè)主CefFrame對(duì)象和若干個(gè)子Frame對(duì)象。主CefFrame相當(dāng)于網(wǎng)頁(yè)的主界面,子CefFrame相當(dāng)于主頁(yè)面的子頁(yè)面。CefFrame包含獲取網(wǎng)頁(yè)上的文字、HTML源碼字符串、網(wǎng)頁(yè)名字標(biāo)題、加載的url、所屬的CefBrowser指針、V8Context等。還可以用LoadURL或LoadRequest加載頁(yè)面。 // Class used to represent a frame in the browser window. When used in the // browser process the methods of this class may be called on any thread unless // otherwise indicated in the comments. When used in the render process the // methods of this class may only be called on the main thread. /// /*--cef(source=library)--*/ class CefFrame : public virtual CefBaseRefCounted { public: /// // True if this object is currently attached to a valid frame. /// /*--cef()--*/ virtual bool IsValid() = 0;
/// // Execute undo in this frame. /// /*--cef()--*/ virtual void Undo() = 0;
/// // Execute redo in this frame. /// /*--cef()--*/ virtual void Redo() = 0;
/// // Execute cut in this frame. /// /*--cef()--*/ virtual void Cut() = 0;
/// // Execute copy in this frame. /// /*--cef()--*/ virtual void Copy() = 0;
/// // Execute paste in this frame. /// /*--cef()--*/ virtual void Paste() = 0;
/// // Execute delete in this frame. /// /*--cef(capi_name=del)--*/ virtual void Delete() = 0;
/// // Execute select all in this frame. /// /*--cef()--*/ virtual void SelectAll() = 0;
/// // Save this frame's HTML source to a temporary file and open it in the // default text viewing application. This method can only be called from the // browser process. /// /*--cef()--*/ virtual void ViewSource() = 0;
/// // Retrieve this frame's HTML source as a string sent to the specified // visitor. /// /*--cef()--*/ virtual void GetSource(CefRefPtr<CefStringVisitor> visitor) = 0;
/// // Retrieve this frame's display text as a string sent to the specified // visitor. /// /*--cef()--*/ virtual void GetText(CefRefPtr<CefStringVisitor> visitor) = 0;
/// // Load the request represented by the |request| object. /// /*--cef()--*/ virtual void LoadRequest(CefRefPtr<CefRequest> request) = 0;
/// // Load the specified |url|. /// /*--cef()--*/ virtual void LoadURL(const CefString& url) = 0;
/// // Load the contents of |string_val| with the specified dummy |url|. |url| // should have a standard scheme (for example, http scheme) or behaviors like // link clicks and web security restrictions may not behave as expected. /// /*--cef()--*/ virtual void LoadString(const CefString& string_val, const CefString& url) = 0;
/// // 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;
/// // Returns true if this is the main (top-level) frame. /// /*--cef()--*/ virtual bool IsMain() = 0;
/// // Returns true if this is the focused frame. /// /*--cef()--*/ virtual bool IsFocused() = 0;
/// // Returns the name for this frame. If the frame has an assigned name (for // example, set via the iframe "name" attribute) then that value will be // returned. Otherwise a unique name will be constructed based on the frame // parent hierarchy. The main (top-level) frame will always have an empty name // value. /// /*--cef()--*/ virtual CefString GetName() = 0;
/// // Returns the globally unique identifier for this frame or < 0 if the // underlying frame does not yet exist. /// /*--cef()--*/ virtual int64 GetIdentifier() = 0;
/// // Returns the parent of this frame or NULL if this is the main (top-level) // frame. /// /*--cef()--*/ virtual CefRefPtr<CefFrame> GetParent() = 0;
/// // Returns the URL currently loaded in this frame. /// /*--cef()--*/ virtual CefString GetURL() = 0;
/// // Returns the browser that this frame belongs to. /// /*--cef()--*/ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
/// // Get the V8 context associated with the frame. This method can only be // called from the render process. /// /*--cef()--*/ virtual CefRefPtr<CefV8Context> GetV8Context() = 0;
/// // Visit the DOM document. This method can only be called from the render // process. /// /*--cef()--*/ virtual void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) = 0; };
1.9 CefApp應(yīng)用程序類CefApp是應(yīng)用程序類,網(wǎng)頁(yè)嵌入程序都要實(shí)現(xiàn)這樣一個(gè)應(yīng)用程序類。提供了一些簡(jiǎn)單的接口:命令行參數(shù)修改,主題修改,獲取進(jìn)程句柄等。還有很多的子類,例如SimpleApp、ClientApp等,clientapp又有很多子類ClientAppBrowser、ClientAppRenderer、ClientAppOther,表示不同的應(yīng)用類型:應(yīng)用程序類定義如下: class CefApp : public virtual CefBaseRefCounted { public: ///對(duì)命令行參數(shù)修改 // Provides an opportunity to view and/or modify command-line arguments before // processing by CEF and Chromium. The |process_type| value will be empty for // the browser process. Do not keep a reference to the CefCommandLine object // passed to this method. The CefSettings.command_line_args_disabled value // can be used to start with an empty command-line object. Any values // specified in CefSettings that equate to command-line arguments will be set // before this method is called. Be cautious when using this method to modify // command-line arguments for non-browser processes as this may result in // undefined behavior including crashes. /// /*--cef(optional_param=process_type)--*/ virtual void OnBeforeCommandLineProcessing( const CefString& process_type, CefRefPtr<CefCommandLine> command_line) {}
/// // Provides an opportunity to register custom schemes. Do not keep a reference // to the |registrar| object. This method is called on the main thread for // each process and the registered schemes should be the same across all // processes. /// /*--cef()--*/注冊(cè)自定義主題 virtual void OnRegisterCustomSchemes( CefRawPtr<CefSchemeRegistrar> registrar) {}
/// // Return the handler for resource bundle events. If // CefSettings.pack_loading_disabled is true a handler must be returned. If no // handler is returned resources will be loaded from pack files. This method // is called by the browser and render processes on multiple threads. /// /*--cef()--*/ virtual CefRefPtr<CefResourceBundleHandler> GetResourceBundleHandler() { return NULL; }
/// // Return the handler for functionality specific to the browser process. This // method is called on multiple threads in the browser process. /// /*--cef()--*/ virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() { return NULL; }
/// // Return the handler for functionality specific to the render process. This // method is called on the render process main thread. /// /*--cef()--*/ virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() { return NULL; } }; 1.10 CEF引用計(jì)數(shù)CEF創(chuàng)建對(duì)象形式如CefRefPtr<SimpleApp> app(new SimpleApp);或者CefRefPtr<SimpleApp> app = new SimpleApp();創(chuàng)建的指針引用計(jì)數(shù)由CefRefPtr管理,CefRefPtr通過(guò)調(diào)用AddRef()和Release()方法自動(dòng)管理引用計(jì)數(shù)。CefRefPtr定義如下: using CefRefPtr = scoped_refptr<T>; template <class T> class scoped_refptr { public: typedef T element_type;
scoped_refptr() : ptr_(NULL) {}
scoped_refptr(T* p) : ptr_(p) { if (ptr_) ptr_->AddRef(); }
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { if (ptr_) ptr_->AddRef(); }
template <typename U> scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { if (ptr_) ptr_->AddRef(); }
~scoped_refptr() { if (ptr_) ptr_->Release(); }
T* get() const { return ptr_; }
// Allow scoped_refptr<C> to be used in boolean // and comparison operations. operator T*() const { return ptr_; }
T* operator->() const { assert(ptr_ != NULL); return ptr_; }
scoped_refptr<T>& operator=(T* p) { // AddRef first so that self assignment should work if (p) p->AddRef(); T* old_ptr = ptr_; ptr_ = p; if (old_ptr) old_ptr->Release(); return *this; }
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { return *this = r.ptr_; }
template <typename U> scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { return *this = r.get(); }
void swap(T** pp) { T* p = ptr_; ptr_ = *pp; *pp = p; }
void swap(scoped_refptr<T>& r) { swap(&r.ptr_); }
protected: T* ptr_; }; 1.11 CEF自定義字符串1.11.1 為什么自定義字符串類型libcef包和宿主程序可能使用不同的運(yùn)行時(shí),對(duì)堆管理的方式也不同。所有的對(duì)象,包括字符串,需要確保和申請(qǐng)堆內(nèi)存使用相同的運(yùn)行時(shí)環(huán)境。所以需要自定義字符串類型。 1.11.2 字符串操作函數(shù)CefStringCEF提供了一批C語(yǔ)言的方法來(lái)操作字符串(通過(guò)#define的方式來(lái)適應(yīng)不同的字符編碼) cef_string_set 對(duì)制定的字符串變量賦值(支持深拷貝或淺拷貝)。 cef_string_clear 清空字符串。 cef_string_cmp 比較兩個(gè)字符串。 1.11.3 CEF與String的轉(zhuǎn)換CefString支持與std::string(UTF8)、std::wstring(wide)類型的相互轉(zhuǎn)換。也可以用來(lái)包裹一個(gè)cef_string_t結(jié)構(gòu)來(lái)對(duì)其進(jìn)行賦值。 (1)string轉(zhuǎn)CefString 單字節(jié) std::string str = “Some UTF8 string”; CefString cef_str(str); cef_str = str; cef_str.FromString(str); 寬字節(jié) std::wstring str = “Some wide string”; CefString cef_str(str); cef_str = str; cef_str.FromWString(str); ASCII碼 const char* cstr = “Some ASCII string”; CefString cef_str; cef_str.FromASCII(cstr); (2)CefString轉(zhuǎn)string 單字節(jié) str = cef_str; str = cef_str.ToString(); 寬字節(jié) str = cef_str; str = cef_str.ToWString();
2 Cef常用接口類介紹Cef是一個(gè)網(wǎng)頁(yè)嵌入外殼,要獲取網(wǎng)頁(yè)的響應(yīng),攔截網(wǎng)頁(yè)中的事件消息,CEF提供了一系列的接口回調(diào)類,提供各種事件回調(diào)函數(shù),例如攔截獲取鍵盤、鼠標(biāo)、加載、顯示、右鍵菜單、提示消息、狀態(tài)變化、窗口打開(kāi)關(guān)閉等,CEF都可以從網(wǎng)頁(yè)上攔截捕捉消息事件,并通過(guò)回調(diào)函數(shù)傳給應(yīng)用程序進(jìn)行處理。 2.1 CefClientCefClient提供了獲取各種handler的接口,例如上下文菜單handler、對(duì)話框handler、顯示狀態(tài)handler,下載事件handler、拖動(dòng)事件handler、查找事件handler、鍵盤handler、生命周期事件handler、加載頁(yè)面事件handler、離屏render進(jìn)程handler、請(qǐng)求事件handler等。但是只是返回事件的handle。每個(gè)handler的具體的回調(diào)函數(shù)不在CefClient類中,需要繼承各個(gè)handler類,才可以實(shí)現(xiàn)回調(diào)。CefClient類只有一個(gè)回調(diào)函數(shù)OnProcessMessageReceived用來(lái)處理進(jìn)程間的通訊消息。CefClient的定義如下: class CefClient : public virtual CefBaseRefCounted { public: /// // Return the handler for context menus. If no handler is provided the default // implementation will be used. /// /*--cef()--*/ virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() { return NULL; }
/// // Return the handler for dialogs. If no handler is provided the default // implementation will be used. /// /*--cef()--*/ virtual CefRefPtr<CefDialogHandler> GetDialogHandler() { return NULL; }
/// // Return the handler for browser display state events. /// /*--cef()--*/ virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() { return NULL; }
/// // Return the handler for download events. If no handler is returned downloads // will not be allowed. /// /*--cef()--*/ virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() { return NULL; }
/// // Return the handler for drag events. /// /*--cef()--*/ virtual CefRefPtr<CefDragHandler> GetDragHandler() { return NULL; }
/// // Return the handler for find result events. /// /*--cef()--*/ virtual CefRefPtr<CefFindHandler> GetFindHandler() { return NULL; }
/// // Return the handler for focus events. /// /*--cef()--*/ virtual CefRefPtr<CefFocusHandler> GetFocusHandler() { return NULL; }
/// // Return the handler for JavaScript dialogs. If no handler is provided the // default implementation will be used. /// /*--cef()--*/ virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() { return NULL; }
/// // Return the handler for keyboard events. /// /*--cef()--*/ virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() { return NULL; }
/// // Return the handler for browser life span events. /// /*--cef()--*/ virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() { return NULL; }
/// // Return the handler for browser load status events. /// /*--cef()--*/ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() { return NULL; }
/// // Return the handler for off-screen rendering events. /// /*--cef()--*/ virtual CefRefPtr<CefRenderHandler> GetRenderHandler() { return NULL; }
/// // Return the handler for browser request events. /// /*--cef()--*/ virtual CefRefPtr<CefRequestHandler> GetRequestHandler() { return NULL; }
/// // Called when a new message is received from a different process. Return true // if the message was handled or false otherwise. Do not keep a reference to // or attempt to access the message outside of this callback. /// /*--cef()--*/ virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { return false; } }; 2.2 CefContextMenuHandler右鍵菜單處理類CefContextMenuHandler是網(wǎng)頁(yè)上的右鍵菜單事件回調(diào)函數(shù)類,提供OnBeforeContextMenu回調(diào)函數(shù),在右鍵菜單彈出之前修改或者禁用右鍵菜單。右鍵菜單按鈕響應(yīng)回調(diào)RunContextMenu、右鍵菜單命令回調(diào)OnContextMenuCommand菜單禁用回調(diào)函數(shù)OnContextMenuDismissed等??梢詳r截右鍵菜單響應(yīng),進(jìn)行自定義的處理。 class CefContextMenuHandler : public virtual CefBaseRefCounted { public: typedef cef_event_flags_t EventFlags;
/// // Called before a context menu is displayed. |params| provides information // about the context menu state. |model| initially contains the default // context menu. The |model| can be cleared to show no context menu or // modified to show a custom menu. Do not keep references to |params| or // |model| outside of this callback. /// /*--cef()--*/ virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model) {}
/// // Called to allow custom display of the context menu. |params| provides // information about the context menu state. |model| contains the context menu // model resulting from OnBeforeContextMenu. For custom display return true // and execute |callback| either synchronously or asynchronously with the // selected command ID. For default display return false. Do not keep // references to |params| or |model| outside of this callback. /// /*--cef()--*/ virtual bool RunContextMenu(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, CefRefPtr<CefMenuModel> model, CefRefPtr<CefRunContextMenuCallback> callback) { return false; }
/// // Called to execute a command selected from the context menu. Return true if // the command was handled or false for the default implementation. See // cef_menu_id_t for the command ids that have default implementations. All // user-defined command ids should be between MENU_ID_USER_FIRST and // MENU_ID_USER_LAST. |params| will have the same values as what was passed to // OnBeforeContextMenu(). Do not keep a reference to |params| outside of this // callback. /// /*--cef()--*/ virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefContextMenuParams> params, int command_id, EventFlags event_flags) { return false; } /// // Called when the context menu is dismissed irregardless of whether the menu // was empty or a command was selected. /// /*--cef()--*/ virtual void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {} };
2.3 CefDisplayHandler網(wǎng)頁(yè)顯示處理類CefDisplayHandler提供了一些頁(yè)面顯示回調(diào)函數(shù),例如網(wǎng)址發(fā)送變化OnAddressChange,網(wǎng)頁(yè)標(biāo)題OnTitleChange發(fā)生變化,網(wǎng)頁(yè)圖標(biāo)發(fā)生變化OnFaviconURLChange,全屏變化OnFullscreenModeChange,顯示提示消息OnTooltip,狀態(tài)欄消息顯示OnStatusMessage,控制臺(tái)消息回調(diào)OnConsoleMessage,設(shè)置了自動(dòng)調(diào)整大小回調(diào)OnAutoResize,加載進(jìn)程變化回調(diào)OnLoadingProgressChange,CefDisplayHandler類定義如下 class CefDisplayHandler : public virtual CefBaseRefCounted { public: /// // Called when a frame's address has changed. /// /*--cef()--*/ virtual void OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url) {}
/// // Called when the page title changes. /// /*--cef(optional_param=title)--*/ virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) {}
/// // Called when the page icon changes. /// /*--cef(optional_param=icon_urls)--*/ virtual void OnFaviconURLChange(CefRefPtr<CefBrowser> browser, const std::vector<CefString>& icon_urls) {}
/// // Called when web content in the page has toggled fullscreen mode. If // |fullscreen| is true the content will automatically be sized to fill the // browser content area. If |fullscreen| is false the content will // automatically return to its original size and position. The client is // responsible for resizing the browser if desired. /// /*--cef()--*/ virtual void OnFullscreenModeChange(CefRefPtr<CefBrowser> browser, bool fullscreen) {}
/// // Called when the browser is about to display a tooltip. |text| contains the // text that will be displayed in the tooltip. To handle the display of the // tooltip yourself return true. Otherwise, you can optionally modify |text| // and then return false to allow the browser to display the tooltip. // When window rendering is disabled the application is responsible for // drawing tooltips and the return value is ignored. /// /*--cef(optional_param=text)--*/ virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) { return false; }
/// // Called when the browser receives a status message. |value| contains the // text that will be displayed in the status message. /// /*--cef(optional_param=value)--*/ virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser, const CefString& value) {}
/// // Called to display a console message. Return true to stop the message from // being output to the console. /// /*--cef(optional_param=message,optional_param=source)--*/ virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser, cef_log_severity_t level, const CefString& message, const CefString& source, int line) { return false; }
/// // Called when auto-resize is enabled via CefBrowserHost::SetAutoResizeEnabled // and the contents have auto-resized. |new_size| will be the desired size in // view coordinates. Return true if the resize was handled or false for // default handling. /// /*--cef()--*/ virtual bool OnAutoResize(CefRefPtr<CefBrowser> browser, const CefSize& new_size) { return false; }
/// // Called when the overall page loading progress has changed. |progress| // ranges from 0.0 to 1.0. /// /*--cef()--*/ virtual void OnLoadingProgressChange(CefRefPtr<CefBrowser> browser, double progress) {} }; 2.4 CefDownloadHandler網(wǎng)頁(yè)下載處理類CefDownloadHandler網(wǎng)頁(yè)上下載文件類,提供開(kāi)始從網(wǎng)頁(yè)下載文件回調(diào)函數(shù)OnBeforeDownload,下載文件進(jìn)度更新回調(diào)函數(shù)OnDownloadUpdated。 class CefDownloadHandler : public virtual CefBaseRefCounted { public: /// // Called before a download begins. |suggested_name| is the suggested name for // the download file. By default the download will be canceled. Execute // |callback| either asynchronously or in this method to continue the download // if desired. Do not keep a reference to |download_item| outside of this // method. /// /*--cef()--*/ virtual void OnBeforeDownload( CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback) = 0;
/// // Called when a download's status or progress information has been updated. // This may be called multiple times before and after OnBeforeDownload(). // Execute |callback| either asynchronously or in this method to cancel the // download if desired. Do not keep a reference to |download_item| outside of // this method. /// /*--cef()--*/ virtual void OnDownloadUpdated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, CefRefPtr<CefDownloadItemCallback> callback) {} };
2.5 CefDragHandler鼠標(biāo)拖動(dòng)到網(wǎng)頁(yè)處理類CefDragHandler處理鼠標(biāo)拖動(dòng)事件,提供鼠標(biāo)拖動(dòng)進(jìn)入網(wǎng)頁(yè)回調(diào)函數(shù)OnDragEnter,網(wǎng)頁(yè)中可以拖動(dòng)放入的區(qū)域發(fā)生變化回調(diào)函數(shù)OnDraggableRegionsChanged。 // Implement this interface to handle events related to dragging. The methods of // this class will be called on the UI thread. /// /*--cef(source=client)--*/ class CefDragHandler : public virtual CefBaseRefCounted { public: typedef cef_drag_operations_mask_t DragOperationsMask;
/// // Called when an external drag event enters the browser window. |dragData| // contains the drag event data and |mask| represents the type of drag // operation. Return false for default drag handling behavior or true to // cancel the drag event. /// /*--cef()--*/ virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> dragData, DragOperationsMask mask) { return false; }
/// // Called whenever draggable regions for the browser window change. These can // be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If // draggable regions are never defined in a document this method will also // never be called. If the last draggable region is removed from a document // this method will be called with an empty vector. /// /*--cef()--*/ virtual void OnDraggableRegionsChanged( CefRefPtr<CefBrowser> browser, const std::vector<CefDraggableRegion>& regions) {} };
2.6 CefKeyboardHandler鍵盤事件響應(yīng)處理類CefKeyboardHandler處理鍵盤響應(yīng)事件,提供鍵盤按鍵響應(yīng)回調(diào)函數(shù)。攔截鍵盤消息。 // Implement this interface to handle events related to keyboard input. The // methods of this class will be called on the UI thread. /// /*--cef(source=client)--*/ class CefKeyboardHandler : public virtual CefBaseRefCounted { public: /// // Called before a keyboard event is sent to the renderer. |event| contains // information about the keyboard event. |os_event| is the operating system // event message, if any. Return true if the event was handled or false // otherwise. If the event will be handled in OnKeyEvent() as a keyboard // shortcut set |is_keyboard_shortcut| to true and return false. /// /*--cef()--*/ virtual bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser, const CefKeyEvent& event, CefEventHandle os_event, bool* is_keyboard_shortcut) { return false; }
/// // Called after the renderer and JavaScript in the page has had a chance to // handle the event. |event| contains information about the keyboard event. // |os_event| is the operating system event message, if any. Return true if // the keyboard event was handled or false otherwise. /// /*--cef()--*/ virtual bool OnKeyEvent(CefRefPtr<CefBrowser> browser, const CefKeyEvent& event, CefEventHandle os_event) { return false; } }; 2.7 CefLifeSpanHandler生命周期處理類CefLifeSpanHandler是生命周期處理類,新打開(kāi)一個(gè)網(wǎng)頁(yè)或者關(guān)閉一個(gè)網(wǎng)頁(yè)時(shí),會(huì)觸發(fā)回調(diào)函數(shù)。OnBeforePopup這個(gè)只能在創(chuàng)建一個(gè)新的彈出式網(wǎng)頁(yè)時(shí),才會(huì)觸發(fā),如果是在一個(gè)網(wǎng)頁(yè)中打開(kāi)一個(gè)子網(wǎng)頁(yè),回調(diào)函數(shù)是攔截不到消息的。OnAfterCreated網(wǎng)頁(yè)創(chuàng)建完成后的回調(diào)函數(shù)。browser銷毀之前會(huì)觸發(fā)回調(diào)函數(shù)OnBeforeClose。還有一個(gè)關(guān)閉回調(diào)函數(shù)DoClose有點(diǎn)復(fù)雜,當(dāng)調(diào)用CefBrowserHost::*CloseBrowser()函數(shù)關(guān)閉browser,或者browser是CEF創(chuàng)建的頂層窗口的子窗口,當(dāng)頂層窗口關(guān)閉時(shí),也會(huì)觸發(fā)關(guān)閉DoClose回調(diào)函數(shù)。點(diǎn)擊網(wǎng)頁(yè)的關(guān)閉按鈕后,網(wǎng)頁(yè)不會(huì)立刻關(guān)閉,而是會(huì)調(diào)用兩次CloseBrowser()或TryCloseBrowser(),提供了一個(gè)讓CEF處理JS的onbeforeunload事件和選擇性取消關(guān)閉網(wǎng)頁(yè)的機(jī)會(huì)。CefLifeSpanHandler類定義如下:
// Implement this interface to handle events related to browser life span. The // methods of this class will be called on the UI thread unless otherwise // indicated. /// /*--cef(source=client)--*/ class CefLifeSpanHandler : public virtual CefBaseRefCounted { public: typedef cef_window_open_disposition_t WindowOpenDisposition;
/// // Called on the UI thread before a new popup browser is created. The // |browser| and |frame| values represent the source of the popup request. The // |target_url| and |target_frame_name| values indicate where the popup // browser should navigate and may be empty if not specified with the request. // The |target_disposition| value indicates where the user intended to open // the popup (e.g. current tab, new tab, etc). The |user_gesture| value will // be true if the popup was opened via explicit user gesture (e.g. clicking a // link) or false if the popup opened automatically (e.g. via the // DomContentLoaded event). The |popupFeatures| structure contains additional // information about the requested popup window. To allow creation of the // popup browser optionally modify |windowInfo|, |client|, |settings| and // |no_javascript_access| and return false. To cancel creation of the popup // browser return true. The |client| and |settings| values will default to the // source browser's values. If the |no_javascript_access| value is set to // false the new browser will not be scriptable and may not be hosted in the // same renderer process as the source browser. Any modifications to // |windowInfo| will be ignored if the parent browser is wrapped in a // CefBrowserView. Popup browser creation will be canceled if the parent // browser is destroyed before the popup browser creation completes (indicated // by a call to OnAfterCreated for the popup browser). /// /*--cef(optional_param=target_url,optional_param=target_frame_name)--*/ virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& target_url, const CefString& target_frame_name, WindowOpenDisposition target_disposition, bool user_gesture, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr<CefClient>& client, CefBrowserSettings& settings, bool* no_javascript_access) { return false; }
/// // Called after a new browser is created. This callback will be the first // notification that references |browser|. /// /*--cef()--*/ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) {}
/// // Called when a browser has recieved a request to close. This may result // directly from a call to CefBrowserHost::*CloseBrowser() or indirectly if // the browser is parented to a top-level window created by CEF and the user // attempts to close that window (by clicking the 'X', for example). The // DoClose() method will be called after the JavaScript 'onunload' event has // been fired. // // An application should handle top-level owner window close notifications by // calling CefBrowserHost::TryCloseBrowser() or // CefBrowserHost::CloseBrowser(false) instead of allowing the window to close // immediately (see the examples below). This gives CEF an opportunity to // process the 'onbeforeunload' event and optionally cancel the close before // DoClose() is called. // // When windowed rendering is enabled CEF will internally create a window or // view to host the browser. In that case returning false from DoClose() will // send the standard close notification to the browser's top-level owner // window (e.g. WM_CLOSE on Windows, performClose: on OS X, "delete_event" on // Linux or CefWindowDelegate::CanClose() callback from Views). If the // browser's host window/view has already been destroyed (via view hierarchy // tear-down, for example) then DoClose() will not be called for that browser // since is no longer possible to cancel the close. // // When windowed rendering is disabled returning false from DoClose() will // cause the browser object to be destroyed immediately. // // If the browser's top-level owner window requires a non-standard close // notification then send that notification from DoClose() and return true. // // The CefLifeSpanHandler::OnBeforeClose() method will be called after // DoClose() (if DoClose() is called) and immediately before the browser // object is destroyed. The application should only exit after OnBeforeClose() // has been called for all existing browsers. // // The below examples describe what should happen during window close when the // browser is parented to an application-provided top-level window. // // Example 1: Using CefBrowserHost::TryCloseBrowser(). This is recommended for // clients using standard close handling and windows created on the browser // process UI thread. // 1. User clicks the window close button which sends a close notification to // the application's top-level window. // 2. Application's top-level window receives the close notification and // calls TryCloseBrowser() (which internally calls CloseBrowser(false)). // TryCloseBrowser() returns false so the client cancels the window close. // 3. JavaScript 'onbeforeunload' handler executes and shows the close // confirmation dialog (which can be overridden via // CefJSDialogHandler::OnBeforeUnloadDialog()). // 4. User approves the close. // 5. JavaScript 'onunload' handler executes. // 6. CEF sends a close notification to the application's top-level window // (because DoClose() returned false by default). // 7. Application's top-level window receives the close notification and // calls TryCloseBrowser(). TryCloseBrowser() returns true so the client // allows the window close. // 8. Application's top-level window is destroyed. // 9. Application's OnBeforeClose() handler is called and the browser object // is destroyed. // 10. Application exits by calling CefQuitMessageLoop() if no other browsers // exist. // // Example 2: Using CefBrowserHost::CloseBrowser(false) and implementing the // DoClose() callback. This is recommended for clients using non-standard // close handling or windows that were not created on the browser process UI // thread. // 1. User clicks the window close button which sends a close notification to // the application's top-level window. // 2. Application's top-level window receives the close notification and: // A. Calls CefBrowserHost::CloseBrowser(false). // B. Cancels the window close. // 3. JavaScript 'onbeforeunload' handler executes and shows the close // confirmation dialog (which can be overridden via // CefJSDialogHandler::OnBeforeUnloadDialog()). // 4. User approves the close. // 5. JavaScript 'onunload' handler executes. // 6. Application's DoClose() handler is called. Application will: // A. Set a flag to indicate that the next close attempt will be allowed. // B. Return false. // 7. CEF sends an close notification to the application's top-level window. // 8. Application's top-level window receives the close notification and // allows the window to close based on the flag from #6B. // 9. Application's top-level window is destroyed. // 10. Application's OnBeforeClose() handler is called and the browser object // is destroyed. // 11. Application exits by calling CefQuitMessageLoop() if no other browsers // exist. /// /*--cef()--*/ virtual bool DoClose(CefRefPtr<CefBrowser> browser) { return false; }
/// // Called just before a browser is destroyed. Release all references to the // browser object and do not attempt to execute any methods on the browser // object after this callback returns. This callback will be the last // notification that references |browser|. See DoClose() documentation for // additional usage information. /// /*--cef()--*/ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) {} };
2.7.1 DoClose標(biāo)準(zhǔn)關(guān)閉處理當(dāng)窗口創(chuàng)建是在browser進(jìn)程的UI線程創(chuàng)建時(shí),采用標(biāo)準(zhǔn)的關(guān)閉處理,使用CefBrowserHost::TryCloseBrowser()。不實(shí)現(xiàn)DoClose回調(diào),默認(rèn)返回false。具體步驟: (1) 點(diǎn)擊窗口的關(guān)閉按鈕,發(fā)送一個(gè)關(guān)閉通知給頂層窗口。 (2) 頂層窗口接收到關(guān)閉通知,調(diào)用TryCloseBrowser()函數(shù),返回false; (3) JS的onbeforeunload處理句柄執(zhí)行顯示關(guān)閉確認(rèn)對(duì)話框。 (4) 用戶點(diǎn)擊按鈕同意關(guān)閉; (5) JS的onunload處理句柄執(zhí)行; (6) CEF發(fā)送一個(gè)close通知給頂層窗口; (7) 定鞥窗口接收到關(guān)閉通知,調(diào)用TryCloseBrowser,返回true,表示允許關(guān)閉。 (8) 頂層窗口銷毀 (9) 程序的OnBeforeClose處理回調(diào)函數(shù)執(zhí)行,browser銷毀. (10)如果不存在其他browser,則調(diào)用CefQuitMessageLoop退出程序。 2.7.2 DoClose非標(biāo)準(zhǔn)關(guān)閉處理當(dāng)窗口不是在browser進(jìn)程的UI線程中創(chuàng)建時(shí),采用非標(biāo)準(zhǔn)的關(guān)閉處理,使用函數(shù)CefBrowserHost::CloseBrowser(false),并且實(shí)現(xiàn)DoClose函數(shù)。 (1) 用戶點(diǎn)擊窗口的關(guān)閉按鈕,發(fā)送一個(gè)關(guān)閉通知給頂層窗口。 (2) 頂層窗口接收到關(guān)閉通知,調(diào)用CefBrowserHost::CloseBrowser(false)函數(shù),取消關(guān)閉; (3) JS的onbeforeunload處理句柄執(zhí)行顯示關(guān)閉確認(rèn)對(duì)話框。 (4) 用戶點(diǎn)擊按鈕同意關(guān)閉; (5) JS的onunload處理句柄執(zhí)行; (6) 程序的DoClose()回調(diào)函數(shù)被調(diào)用,設(shè)置一個(gè)flag表明下次關(guān)閉嘗試會(huì)被允許,返回false; (7) CEF發(fā)送一個(gè)close通知給頂層窗口; (8) 頂層窗口接收到關(guān)閉通知,根據(jù)之前設(shè)置的flag判斷是否關(guān)閉窗口。 (9) 頂層窗口銷毀; (10)程序的OnBeforeClose處理回調(diào)函數(shù)執(zhí)行,browser銷毀. (11)如果不存在其他browser,則調(diào)用CefQuitMessageLoop退出程序。
2.8 CefLoadHandler網(wǎng)頁(yè)加載處理類在一個(gè)網(wǎng)頁(yè)中加載內(nèi)容,或者在網(wǎng)頁(yè)中打開(kāi)一個(gè)子frame,都可以攔截到iframe打開(kāi)時(shí)的消息以及url等信息??梢詳r截子網(wǎng)頁(yè)url (1) 開(kāi)始加載OnLoadStart,navigation執(zhí)行網(wǎng)之后,開(kāi)始加載內(nèi)容之前,回調(diào)此函數(shù),多frame的進(jìn)程會(huì)同時(shí)加載。同頁(yè)面巡航不會(huì)調(diào)用。 (2) 加載結(jié)束OnLoadEnd,加載結(jié)束時(shí)回調(diào),sub-frame在主frame加載結(jié)束后, 會(huì)繼續(xù)開(kāi)始加載或繼續(xù)進(jìn)行加載,同頁(yè)面巡航不會(huì)調(diào)用。 (3) 加載錯(cuò)誤OnLoadError,navigation失敗或者取消是回調(diào)。 (4) 加載狀態(tài)發(fā)生變化OnLoadingStateChange,加載初始化和加載結(jié)束時(shí)各調(diào)用一次,在OnLoadStart之前調(diào)用一次,OnLoadEnd或OnLoadError之后調(diào)用一次。
// Implement this interface to handle events related to browser load status. The // methods of this class will be called on the browser process UI thread or // render process main thread (TID_RENDERER). /// /*--cef(source=client)--*/ class CefLoadHandler : public virtual CefBaseRefCounted { public: typedef cef_errorcode_t ErrorCode; typedef cef_transition_type_t TransitionType;
/// // Called when the loading state has changed. This callback will be executed // twice -- once when loading is initiated either programmatically or by user // action, and once when loading is terminated due to completion, cancellation // of failure. It will be called before any calls to OnLoadStart and after all // calls to OnLoadError and/or OnLoadEnd. /// /*--cef()--*/ virtual void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, bool isLoading, bool canGoBack, bool canGoForward) {}
/// // Called after a navigation has been committed and before the browser begins // loading contents in the frame. The |frame| value will never be empty -- // call the IsMain() method to check if this frame is the main frame. // |transition_type| provides information about the source of the navigation // and an accurate value is only available in the browser process. Multiple // frames may be loading at the same time. Sub-frames may start or continue // loading after the main frame load has ended. This method will not be called // for same page navigations (fragments, history state, etc.) or for // navigations that fail or are canceled before commit. For notification of // overall browser load status use OnLoadingStateChange instead. /// /*--cef()--*/ virtual void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, TransitionType transition_type) {}
/// // Called when the browser is done loading a frame. The |frame| value will // never be empty -- call the IsMain() method to check if this frame is the // main frame. Multiple frames may be loading at the same time. Sub-frames may // start or continue loading after the main frame load has ended. This method // will not be called for same page navigations (fragments, history state, // etc.) or for navigations that fail or are canceled before commit. For // notification of overall browser load status use OnLoadingStateChange // instead. /// /*--cef()--*/ virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) {}
/// // Called when a navigation fails or is canceled. This method may be called // by itself if before commit or in combination with OnLoadStart/OnLoadEnd if // after commit. |errorCode| is the error code number, |errorText| is the // error text and |failedUrl| is the URL that failed to load. // See net\base\net_error_list.h for complete descriptions of the error codes. /// /*--cef(optional_param=errorText)--*/ virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) {} };
2.9 CefRequestHandler網(wǎng)絡(luò)請(qǐng)求處理類當(dāng)打開(kāi)一個(gè)網(wǎng)頁(yè), CefRequestHandler的OnBeforeBrowser可以攔截網(wǎng)絡(luò)請(qǐng)求,只有在新打開(kāi)網(wǎng)頁(yè)的時(shí)候,才會(huì)觸發(fā),如果網(wǎng)頁(yè)已經(jīng)打開(kāi),在網(wǎng)頁(yè)內(nèi)部點(diǎn)擊查詢按鈕,查詢內(nèi)容,雖然也有request請(qǐng)求,但是OnBeforeBrowser攔截不到獲取請(qǐng)求的URL,post請(qǐng)求的參數(shù)都可以獲取到。OnResourceRedirect還可以攔截重定向請(qǐng)求。CefLoadHandler也可以攔截request請(qǐng)求,而且頁(yè)面加載中調(diào)用很多的GET和POST請(qǐng)求都可以攔截到。測(cè)試發(fā)現(xiàn)CefRequestHandler頁(yè)面內(nèi)部的加載變化是獲取不到的,只有打開(kāi)頁(yè)面的請(qǐng)求能獲取到。而另外一個(gè)函數(shù)OnBeforeResourceLoad則可以攔截所有的請(qǐng)求,在瀏覽器中F12顯示的所有請(qǐng)求,包括圖片下載等請(qǐng)求都能一一獲取。所以CefLoadHandler攔截的請(qǐng)求更詳細(xì)一些,點(diǎn)擊查詢查詢,OnLoadStart和OnLoadEnd 攔截不到,但是OnLoadingStateChange 可以攔截的到請(qǐng)求。
各回調(diào)函的調(diào)用的先后順序是 OnLoadingStateChange->OnBeforeBrowser->OnLoadStart->OnLoadEnd->OnLoadingStateChange。 // Implement this interface to handle events related to browser requests. The // methods of this class will be called on the thread indicated. /// /*--cef(source=client)--*/ class CefRequestHandler : public virtual CefBaseRefCounted { public: typedef cef_return_value_t ReturnValue; typedef cef_termination_status_t TerminationStatus; typedef cef_urlrequest_status_t URLRequestStatus; typedef cef_window_open_disposition_t WindowOpenDisposition; typedef std::vector<CefRefPtr<CefX509Certificate>> X509CertificateList;
/// // Called on the UI thread before browser navigation. Return true to cancel // the navigation or false to allow the navigation to proceed. The |request| // object cannot be modified in this callback. // CefLoadHandler::OnLoadingStateChange will be called twice in all cases. // If the navigation is allowed CefLoadHandler::OnLoadStart and // CefLoadHandler::OnLoadEnd will be called. If the navigation is canceled // CefLoadHandler::OnLoadError will be called with an |errorCode| value of // ERR_ABORTED. The |user_gesture| value will be true if the browser // navigated via explicit user gesture (e.g. clicking a link) or false if it // navigated automatically (e.g. via the DomContentLoaded event). /// /*--cef()--*/ (1)OnBeforeBrowse,在瀏覽器巡航前調(diào)用。 virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool user_gesture, bool is_redirect) { return false; }
/// // Called on the UI thread before OnBeforeBrowse in certain limited cases // where navigating a new or different browser might be desirable. This // includes user-initiated navigation that might open in a special way (e.g. // links clicked via middle-click or ctrl + left-click) and certain types of // cross-origin navigation initiated from the renderer process (e.g. // navigating the top-level frame to/from a file URL). The |browser| and // |frame| values represent the source of the navigation. The // |target_disposition| value indicates where the user intended to navigate // the browser based on standard Chromium behaviors (e.g. current tab, // new tab, etc). The |user_gesture| value will be true if the browser // navigated via explicit user gesture (e.g. clicking a link) or false if it // navigated automatically (e.g. via the DomContentLoaded event). Return true // to cancel the navigation or false to allow the navigation to proceed in the // source browser's top-level frame. /// /*--cef()--*/ (2)OnOpenURLFromTab,以特殊的方式打開(kāi)的網(wǎng)頁(yè),例如鼠標(biāo)中間按鈕,快捷鍵等,一些很少的應(yīng)用場(chǎng)景。 virtual bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& target_url, WindowOpenDisposition target_disposition, bool user_gesture) { return false; }
/// // Called on the IO thread before a resource request is loaded. The |request| // object may be modified. Return RV_CONTINUE to continue the request // immediately. Return RV_CONTINUE_ASYNC and call CefRequestCallback:: // Continue() at a later time to continue or cancel the request // asynchronously. Return RV_CANCEL to cancel the request immediately. // /// /*--cef(default_retval=RV_CONTINUE)--*/ (3)OnBeforeResourceLoad網(wǎng)頁(yè)開(kāi)始加載資源時(shí)調(diào)用,可以攔截所有的請(qǐng)求,最為詳細(xì)。 virtual ReturnValue OnBeforeResourceLoad( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefRequestCallback> callback) { return RV_CONTINUE; } }; /// // Called on the IO thread before a resource is loaded. To allow the resource // to load normally return NULL. To specify a handler for the resource return // a CefResourceHandler object. The |request| object should not be modified in // this callback. /// /*--cef()--*/ virtual CefRefPtr<CefResourceHandler> GetResourceHandler( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request) { return NULL; }
/// // Called on the IO thread when a resource load is redirected. The |request| // parameter will contain the old URL and other request-related information. // The |response| parameter will contain the response that resulted in the // redirect. The |new_url| parameter will contain the new URL and can be // changed if desired. The |request| object cannot be modified in this // callback. /// /*--cef()--*/ (4)OnResourceRedirect重定向請(qǐng)求攔截 virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefResponse> response, CefString& new_url) {}
/// // Called on the IO thread when a resource response is received. To allow the // resource to load normally return false. To redirect or retry the resource // modify |request| (url, headers or post body) and return true. The // |response| object cannot be modified in this callback. /// /*--cef()--*/ (5)OnResourceResponse請(qǐng)求響應(yīng)后的回調(diào)函數(shù) virtual bool OnResourceResponse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefResponse> response) { return false; }
/// // Called on the IO thread to optionally filter resource response content. // |request| and |response| represent the request and response respectively // and cannot be modified in this callback. /// /*--cef()--*/ virtual CefRefPtr<CefResponseFilter> GetResourceResponseFilter( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefResponse> response) { return NULL; } /// // Called on the IO thread when a resource load has completed. |request| and // |response| represent the request and response respectively and cannot be // modified in this callback. |status| indicates the load completion status. // |received_content_length| is the number of response bytes actually read. /// /*--cef()--*/ (6)OnResourceLoadComplete資源加載結(jié)束時(shí)的回調(diào) virtual void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefResponse> response, URLRequestStatus status, int64 received_content_length) {}
/// // Called on the IO thread when the browser needs credentials from the user. // |isProxy| indicates whether the host is a proxy server. |host| contains the // hostname and |port| contains the port number. |realm| is the realm of the // challenge and may be empty. |scheme| is the authentication scheme used, // such as "basic" or "digest", and will be empty if the source of the request // is an FTP server. Return true to continue the request and call // CefAuthCallback::Continue() either in this method or at a later time when // the authentication information is available. Return false to cancel the // request immediately. /// /*--cef(optional_param=realm,optional_param=scheme)--*/ virtual bool GetAuthCredentials(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr<CefAuthCallback> callback) { return false; }
/// // Called on the IO thread before sending a network request with a "Cookie" // request header. Return true to allow cookies to be included in the network // request or false to block cookies. The |request| object should not be // modified in this callback. /// /*--cef()--*/ virtual bool CanGetCookies(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request) { return true; }
/// // Called on the IO thread when receiving a network request with a // "Set-Cookie" response header value represented by |cookie|. Return true to // allow the cookie to be stored or false to block the cookie. The |request| // object should not be modified in this callback. /// /*--cef()--*/ virtual bool CanSetCookie(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, const CefCookie& cookie) { return true; }
/// // Called on the IO thread when JavaScript requests a specific storage quota // size via the webkitStorageInfo.requestQuota function. |origin_url| is the // origin of the page making the request. |new_size| is the requested quota // size in bytes. Return true to continue the request and call // CefRequestCallback::Continue() either in this method or at a later time to // grant or deny the request. Return false to cancel the request immediately. /// /*--cef()--*/ virtual bool OnQuotaRequest(CefRefPtr<CefBrowser> browser, const CefString& origin_url, int64 new_size, CefRefPtr<CefRequestCallback> callback) { return false; }
/// // Called on the UI thread to handle requests for URLs with an unknown // protocol component. Set |allow_os_execution| to true to attempt execution // via the registered OS protocol handler, if any. // SECURITY WARNING: YOU SHOULD USE THIS METHOD TO ENFORCE RESTRICTIONS BASED // ON SCHEME, HOST OR OTHER URL ANALYSIS BEFORE ALLOWING OS EXECUTION. /// /*--cef()--*/ virtual void OnProtocolExecution(CefRefPtr<CefBrowser> browser, const CefString& url, bool& allow_os_execution) {}
/// // Called on the UI thread to handle requests for URLs with an invalid // SSL certificate. Return true and call CefRequestCallback::Continue() either // in this method or at a later time to continue or cancel the request. Return // false to cancel the request immediately. If // CefSettings.ignore_certificate_errors is set all invalid certificates will // be accepted without calling this method. /// /*--cef()--*/ virtual bool OnCertificateError(CefRefPtr<CefBrowser> browser, cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr<CefSSLInfo> ssl_info, CefRefPtr<CefRequestCallback> callback) { return false; }
/// // Called on the UI thread when a client certificate is being requested for // authentication. Return false to use the default behavior and automatically // select the first certificate available. Return true and call // CefSelectClientCertificateCallback::Select either in this method or at a // later time to select a certificate. Do not call Select or call it with NULL // to continue without using any certificate. |isProxy| indicates whether the // host is an HTTPS proxy or the origin server. |host| and |port| contains the // hostname and port of the SSL server. |certificates| is the list of // certificates to choose from; this list has already been pruned by Chromium // so that it only contains certificates from issuers that the server trusts. /// /*--cef()--*/ virtual bool OnSelectClientCertificate( CefRefPtr<CefBrowser> browser, bool isProxy, const CefString& host, int port, const X509CertificateList& certificates, CefRefPtr<CefSelectClientCertificateCallback> callback) { return false; }
/// // Called on the browser process UI thread when a plugin has crashed. // |plugin_path| is the path of the plugin that crashed. /// /*--cef()--*/ virtual void OnPluginCrashed(CefRefPtr<CefBrowser> browser, const CefString& plugin_path) {}
/// // Called on the browser process UI thread when the render view associated // with |browser| is ready to receive/handle IPC messages in the render // process. /// /*--cef()--*/ virtual void OnRenderViewReady(CefRefPtr<CefBrowser> browser) {} /// // Called on the browser process UI thread when the render process // terminates unexpectedly. |status| indicates how the process // terminated. /// /*--cef()--*/ virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status) {} };
3 CEF高級(jí)應(yīng)用3.1 CEF和JavaScript交互https:///chromiumembedded/cef/wiki/JavaScriptIntegration.md CEF使用的V8 JavaScript 引擎用于內(nèi)部JavaScript實(shí)現(xiàn),每一個(gè)frame都有JS上下文(context),為JS代碼執(zhí)行提供范圍和安全。CEF暴露了很多JS特性可以和客戶端程序進(jìn)行交互。 3.1.1 在CEF執(zhí)行JavaScript腳本應(yīng)用場(chǎng)景是需要在CEF中攔截一個(gè)URL請(qǐng)求,并把它重定向到另外一個(gè)URL,可以調(diào)用pFrame->ExecuteJavaScript來(lái)執(zhí)行一個(gè)JavaScript腳本,實(shí)現(xiàn)跳轉(zhuǎn)。當(dāng)然也可以實(shí)現(xiàn)其他應(yīng)用功能。 CefRefPtr<CefFrame> pFrame = browser->GetMainFrame(); std::string strurl = pFrame->GetURL().ToString(); std::string strname = pFrame->GetName().ToString(); pFrame->GetName().ToString().c_str()); if (pFrame->GetURL() == "https://10.19.141.75/portal/") { pFrame->ExecuteJavaScript("var param= { url:'https://10.19.141.75/ishelf-web/personalCenter' }; \ window.goToApp(param);\ var paramEx = { isExtend:true };\ window.extendScreen(paramEx);\ ", pFrame->GetURL(), 0); } 3.1.2 窗口綁定方式實(shí)現(xiàn)CEF設(shè)置JavaScript的變量在CEF程序中,創(chuàng)建一個(gè)CefV8Value對(duì)象,獲取上下文的窗口對(duì)象,注入窗口對(duì)象一個(gè)變量值,網(wǎng)頁(yè)中就可以使用JavaScript獲取這個(gè)變量值。窗口綁定在CefRenderProcessHandler::OnContextCreated()函數(shù)中。是上下文創(chuàng)建響應(yīng)函數(shù),窗口綁定方式在每次frame重新加載(context創(chuàng)建)時(shí)都會(huì)加載一遍,CEF程序可以在OnContextCreated()給每一個(gè)frame設(shè)置不同的變量值。 CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) { // Retrieve the context's window object. CefRefPtr<CefV8Value> object = context->GetGlobal();
// Create a new V8 string value. See the "Basic JS Types" section below. CefRefPtr<CefV8Value> str = CefV8Value::CreateString("My Value!");
// Add the string to the window object as "window.myval". See the "JS Objects" section below. object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE); } JavaScript in the frame can then interact with the window bindings.
<script language="JavaScript"> alert(window.myval); // Shows an alert box with "My Value!" </script> 3.1.3 擴(kuò)展方式(Extension)實(shí)現(xiàn)CEF設(shè)置JavaScript的變量Extension方式和窗口綁定方式類似,但是Extension方式是為每一個(gè)frame加載到上下文context,一旦加載變不能在修改,沒(méi)有加載之前,DOM是不存在的,嘗試范圍這個(gè)值的DOM會(huì)出現(xiàn)崩潰。Extension方式是在CefRenderProcessHandler::OnWebKitInitialized()函數(shù)中用CefRegisterExtension() 函數(shù)注冊(cè)的,是在初始化函數(shù)中實(shí)現(xiàn)的,所以對(duì)于每一個(gè)frame都是一樣的。 void MyRenderProcessHandler::OnWebKitInitialized() { // Define the extension contents. std::string extensionCode = "var test;" "if (!test)" " test = {};" "(function() {" " test.myval = 'My Value!';" "})();";
// Register the extension. CefRegisterExtension("v8/test", extensionCode, NULL); } JS中調(diào)用變量值 <script language="JavaScript"> alert(test.myval); // Shows an alert box with "My Value!" </script> 3.1.4 窗口綁定方式實(shí)現(xiàn)CEF給JavaScript提供函數(shù)(1) 自定義類實(shí)現(xiàn)CefV8Handler類,實(shí)現(xiàn)Execute接口,JavaScript執(zhí)行函數(shù)后,會(huì)將函數(shù)名稱、參數(shù)和返回值引用傳遞給Execute函數(shù),Execute函數(shù)根據(jù)函數(shù)名去調(diào)用函數(shù),函數(shù)的具體實(shí)現(xiàn)在Execute中,然后執(zhí)行返回返回值。 class MyV8Handler : public CefV8Handler { public: MyV8Handler() {}
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { if (name == "myfunc") { // Return my string value. retval = CefV8Value::CreateString("My Value!"); return true; }
// Function does not exist. return false; }
// Provide the reference counting implementation for this class. IMPLEMENT_REFCOUNTING(MyV8Handler); }; (2)將函數(shù)名稱設(shè)置到窗口對(duì)象,提供接受調(diào)用的handle void MyRenderProcessHandler::OnContextCreated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) { // Retrieve the context's window object. CefRefPtr<CefV8Value> object = context->GetGlobal();
// Create an instance of my CefV8Handler object. CefRefPtr<CefV8Handler> handler = new MyV8Handler();
// Create the "myfunc" function. CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
// Add the "myfunc" function to the "window" object. object->SetValue("myfunc", func, V8_PROPERTY_ATTRIBUTE_NONE); } (3)JavaScript執(zhí)行函數(shù)調(diào)用,就會(huì)進(jìn)入Execute函數(shù),返回返回值,alert會(huì)以彈窗形式展示結(jié)果。 <script language="JavaScript"> alert(window.myfunc()); // Shows an alert box with "My Value!" </script>
3.1.5 Extension方式實(shí)現(xiàn)CEF給JavaScript提供函數(shù)JavaScript調(diào)用CEF中的函數(shù)步驟: (1)實(shí)現(xiàn)app類,繼承與CefApp,重寫OnWebKitInitialized,在OnWebKitInitialized函數(shù)內(nèi)部使用字符串定義函數(shù)。CEF調(diào)用CefRegisterExtension函數(shù)向JavaScript注冊(cè)函數(shù),并提供處理調(diào)用的handler。 //CefClientApp.h class CCefClientApp : public CefApp, public CefBrowserProcessHandler, CefRenderProcessHandler { public: CCefClientApp(); ~CCefClientApp();
//所有的CEF接口 都需要重載GetXXXHandler,并且return this,才會(huì)有效 virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { return this; }
//===========CefRenderProcessHandler virtual void OnWebKitInitialized() override;
private: CefRefPtr<CCEFV8HandlerEx> v8Handler_; // Include the default reference counting implementation. IMPLEMENT_REFCOUNTING(CCefClientApp);
private:
};
//CefClientApp.cpp
void CCefClientApp::OnWebKitInitialized() { //MessageBox(NULL,L"OnWebKitInitialized\n",0,0); std::string app_code = //----------------------------------- //聲明JavaScript里要調(diào)用的Cpp方法 "var app;" "if (!app)" " app = {};" "(function() {"
// jsInvokeCPlusPlus 實(shí)例函數(shù) " app.jsInvokeCPlusPlus = function(v1, v2) {" " native function jsInvokeCPlusPlus();" " return jsInvokeCPlusPlus(v1, v2);" " };"
//函數(shù) " app.jsTransform = function(v1) {" " native function jsTransform();" " return jsTransform(v1);" " };"
"})();";
// Register app extension module
// JavaScript里調(diào)用app.jsInvokeCPlusPlus時(shí),就會(huì)去通過(guò)CefRegisterExtension注冊(cè)的CefV8Handler列表里查找 // 找到"v8/app"對(duì)應(yīng)的CCEFV8HandlerEx,就調(diào)用它的Execute方法 // 假設(shè)v8Handler_是CCefClientApp的一個(gè)成員變量 //v8Handler_ = new CCEFV8HandlerEx();
CefRegisterExtension("v8/app", app_code, v8Handler_);
} (2)JavaScript調(diào)用函數(shù) <html> <script> app.jsInvokeCPlusPlus("123","xyz"); app.jsTransform("hello world"); </script> </html> (3) handler的Execute函數(shù)接收調(diào)用響應(yīng),根據(jù)函數(shù)名稱判斷是調(diào)用哪個(gè)函數(shù),獲取參數(shù)調(diào)用函數(shù)。 //CEFV8HandlerEx.h
class public:
public:
private:
public:
};
//CEFV8HandlerEx.cpp
//JS調(diào)用C++函數(shù)的回調(diào)
bool {
}
3.2 CefV8Value類實(shí)現(xiàn)定JavaScript數(shù)據(jù)類型上面的實(shí)例中我們已經(jīng)用到CefV8Value類的CreateString("My Value!")創(chuàng)建字符串和CreateFunction創(chuàng)建了函數(shù)。這個(gè)類還可以創(chuàng)建, null, bool, int, double, date string等數(shù)據(jù)類型,都有對(duì)應(yīng)的函數(shù)。static CefRefPtr<CefV8Value> CreateArray(int length)創(chuàng)建JavaScript數(shù)組。下面詳細(xì)講解下給JavaScript提供創(chuàng)建對(duì)象。accessor就是給JavaScript提供調(diào)用的set和get方法設(shè)置或獲取屬性。interceptor是攔截器,攔截set和get方法。 /// // Create a new CefV8Value object of type object with optional accessor and/or // interceptor. This method should only be called from within the scope of a // CefRenderProcessHandler, CefV8Handler or CefV8Accessor callback, or in // combination with calling Enter() and Exit() on a stored CefV8Context // reference. /// /*--cef(optional_param=accessor, optional_param=interceptor)--*/ static CefRefPtr<CefV8Value> CreateObject( CefRefPtr<CefV8Accessor> accessor, CefRefPtr<CefV8Interceptor> interceptor); 3.2.1 一般對(duì)象如果不需要給JavaScript提供get和set方法,可以直接創(chuàng)建對(duì)象。 CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(NULL); 給對(duì)象設(shè)置屬性名稱為myval,屬性值為My String;字符串類型。 virtual bool SetValue(int index, CefRefPtr<CefV8Value> value) = 0; obj->SetValue("myval", CefV8Value::CreateString("My String!")); 3.2.2 CEF實(shí)現(xiàn)帶access的JavaScript對(duì)象如果要提供set和get方法,需要提供access實(shí)現(xiàn)類。 (1)實(shí)現(xiàn)access類 class MyV8Accessor : public CefV8Accessor { public: MyV8Accessor() {} virtual bool Get(const CefString& name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { if (name == "myval") { // Return the value. retval = CefV8Value::CreateString(myval_); return true; } // Value does not exist. return false; } virtual bool Set(const CefString& name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) OVERRIDE { if (name == "myval") { if (value->IsString()) { // Store the value. myval_ = value->GetStringValue(); } else { // Throw an exception. exception = "Invalid value type"; } return true; } // Value does not exist. return false; } // Variable used for storing the value. CefString myval_; // Provide the reference counting implementation for this class. IMPLEMENT_REFCOUNTING(MyV8Accessor); }; (2)使用SetValue函數(shù)設(shè)置對(duì)象屬性采用access方式設(shè)置和獲取數(shù)據(jù)。把對(duì)象設(shè)置到窗口對(duì)象中。 virtual bool SetValue(const CefString& key, AccessControl settings, PropertyAttribute attribute) = 0; typedef enum { V8_ACCESS_CONTROL_DEFAULT = 0, V8_ACCESS_CONTROL_ALL_CAN_READ = 1, V8_ACCESS_CONTROL_ALL_CAN_WRITE = 1 << 1, V8_ACCESS_CONTROL_PROHIBITS_OVERWRITING = 1 << 2 } cef_v8_accesscontrol_t;
/// // V8 property attribute values. /// typedef enum { V8_PROPERTY_ATTRIBUTE_NONE = 0, // Writeable, Enumerable, // Configurable V8_PROPERTY_ATTRIBUTE_READONLY = 1 << 0, // Not writeable V8_PROPERTY_ATTRIBUTE_DONTENUM = 1 << 1, // Not enumerable V8_PROPERTY_ATTRIBUTE_DONTDELETE = 1 << 2 // Not configurable } cef_v8_propertyattribute_t;
obj->SetValue("myval", V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE); (3)JavaScript中調(diào)用set和get方法,就可以設(shè)置和獲取屬性值。 3.2.3 CEF實(shí)現(xiàn)帶攔截器CefV8Interceptor的JavaScript對(duì)象攔截器CefV8Interceptor和Access的區(qū)別是,除了可以用字符串來(lái)映射屬性,還可以用index索引來(lái)映射屬性。其定義如下 // Interface that should be implemented to handle V8 interceptor calls. The // methods of this class will be called on the thread associated with the V8 // interceptor. Interceptor's named property handlers (with first argument of // type CefString) are called when object is indexed by string. Indexed property // handlers (with first argument of type int) are called when object is indexed // by integer. /// /*--cef(source=client,no_debugct_check)--*/ class CefV8Interceptor : public virtual CefBaseRefCounted { public: /// // Handle retrieval of the interceptor value identified by |name|. |object| is // the receiver ('this' object) of the interceptor. If retrieval succeeds, set // |retval| to the return value. If the requested value does not exist, don't // set either |retval| or |exception|. If retrieval fails, set |exception| to // the exception that will be thrown. If the property has an associated // accessor, it will be called only if you don't set |retval|. // Return true if interceptor retrieval was handled, false otherwise. /// /*--cef(capi_name=get_byname)--*/ virtual bool Get(const CefString& name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) = 0;
/// // Handle retrieval of the interceptor value identified by |index|. |object| // is the receiver ('this' object) of the interceptor. If retrieval succeeds, // set |retval| to the return value. If the requested value does not exist, // don't set either |retval| or |exception|. If retrieval fails, set // |exception| to the exception that will be thrown. // Return true if interceptor retrieval was handled, false otherwise. /// /*--cef(capi_name=get_byindex,index_param=index)--*/ virtual bool Get(int index, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) = 0;
/// // Handle assignment of the interceptor value identified by |name|. |object| // is the receiver ('this' object) of the interceptor. |value| is the new // value being assigned to the interceptor. If assignment fails, set // |exception| to the exception that will be thrown. This setter will always // be called, even when the property has an associated accessor. // Return true if interceptor assignment was handled, false otherwise. /// /*--cef(capi_name=set_byname)--*/ virtual bool Set(const CefString& name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) = 0;
/// // Handle assignment of the interceptor value identified by |index|. |object| // is the receiver ('this' object) of the interceptor. |value| is the new // value being assigned to the interceptor. If assignment fails, set // |exception| to the exception that will be thrown. // Return true if interceptor assignment was handled, false otherwise. /// /*--cef(capi_name=set_byindex,index_param=index)--*/ virtual bool Set(int index, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) = 0; }; 實(shí)例步驟如下 (1)實(shí)現(xiàn)Interceptor類 class Interceptor : public CefV8Interceptor { public: Interceptor() {} virtual bool Get(const CefString& name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { return true; } virtual bool Get(int index, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { return true; } virtual bool Set(const CefString& name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) OVERRIDE { return true; } virtual bool Set(int index, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) OVERRIDE { return true; } IMPLEMENT_REFCOUNTING(Interceptor); }; (2)創(chuàng)建Interceptor對(duì)象和JavaScript對(duì)象 CefRefPtr<CefV8Interceptor> interceptor = new Interceptor(); PERF_ITERATIONS_START() CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(nullptr, interceptor); (3)SetValue()函設(shè)置到窗口對(duì)象中(待驗(yàn)證) (4)JavaScript調(diào)用按照字符串名稱或者索引來(lái)設(shè)置獲取值。 3.3 CEF進(jìn)程間通訊3.3.1 進(jìn)程間通訊函數(shù)CEF有Browser進(jìn)程和Renderer進(jìn)程,進(jìn)程之間可以相互通信。 發(fā)送消息Browser進(jìn)程和Renderer進(jìn)程都是一樣的,使用CefBrowser::SendProcessMessage() ,SendProcessMessage第一個(gè)參數(shù)是CefProcessId,是一個(gè)枚舉類型,給Browser進(jìn)程發(fā)送,就用PID_BROWSER,給Render進(jìn)程發(fā)送,就用PID_RENDERER。 typedef enum { /// // Browser process. /// PID_BROWSER, /// // Renderer process. /// PID_RENDERER, } cef_process_id_t; Render進(jìn)程這邊, 重寫CefRenderProcessHandler::OnProcessMessageReceived() Browser進(jìn)程這邊,重寫CefClient::OnProcessMessageReceived()這個(gè)方法來(lái)處理跨進(jìn)程消息。 3.3.2 進(jìn)程通訊實(shí)例(1)renderer進(jìn)程發(fā)送消息 CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("login_msg");
// Retrieve the argument list object. CefRefPtr<CefListValue> args = msg->GetArgumentList();
// Populate the argument values. args->SetSize(2); args->SetString(0, strUser); args->SetString(1, strPassword);
// Send the process message to the browser process. CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg); (2)Browser進(jìn)程這邊,重寫CefClient::OnProcessMessageReceived()這個(gè)方法來(lái)處理跨進(jìn)程消息。接收到消息之后再回復(fù)消息。 bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { const std::string& messageName = message->GetName(); if (messageName == "login_msg") { // extract message CefRefPtr<CefListValue> args = message->GetArgumentList(); CefString strUser = args->GetString(0); CefString strPassword = args->GetString(1); TCHAR szLog[256] = { 0 }; _stprintf_s(szLog, 256, _T("BrowserProcess, user - %s, password - %s\r\n"), strUser.c_str(), strPassword.c_str()); OutputDebugString(szLog);
//send reply to render process CefRefPtr<CefProcessMessage> outMsg = CefProcessMessage::Create("login_reply");
// Retrieve the argument list object. CefRefPtr<CefListValue> replyArgs = outMsg->GetArgumentList();
// Populate the argument values. replyArgs->SetSize(1); replyArgs->SetInt(0, 0);
// Send the process message to the renderer process. browser->SendProcessMessage(PID_RENDERER, outMsg);
return true; } return false; } (3)Render進(jìn)程這邊, 重寫CefRenderProcessHandler:: OnProcessMessageReceived()方法來(lái)處理來(lái)自Browser進(jìn)程的消息。 bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { const std::string& messageName = message->GetName(); if (messageName == "login_reply") { // extract message CefRefPtr<CefListValue> args = message->GetArgumentList(); int status = args->GetInt(0); OutputDebugString(status == 0 ? _T("Renderer process, login ok\r\n") : _T("Renderer process, login failed\r\n")); CefRefPtr<CefFrame> frame = browser->GetMainFrame(); frame->ExecuteJavaScript("alert('Got Login Reply from Browser process')", frame->GetURL(), 0); return true; } return false; } 3.3.3 CEF指定frame通訊一個(gè)網(wǎng)頁(yè)有多個(gè)frame,有一個(gè)mainframe和多個(gè)subframe,發(fā)送消息時(shí),將frame的id放入?yún)?shù)中一起發(fā)過(guò)去,接收時(shí)消息時(shí),獲取frameid,就可以實(shí)現(xiàn)指定frame通訊。因?yàn)閒rameid是一個(gè)int64類型的數(shù)據(jù),所以發(fā)送時(shí)將它分解為兩個(gè)int32 的高低位數(shù)據(jù),接收數(shù)據(jù)時(shí),再將兩個(gè)int32的數(shù)據(jù)拼接成一個(gè)int64數(shù)據(jù)。 #define MAKE_INT64(int_low, int_high) \ ((int64) (((int) (int_low)) | ((int64) ((int) (int_high))) << 32)) #define LOW_INT(int64_val) ((int) (int64_val)) #define HIGH_INT(int64_val) ((int) (((int64) (int64_val) >> 32) & 0xFFFFFFFFL))
// Sending the frame ID. const int64 frame_id = frame->GetIdentifier(); args->SetInt(0, LOW_INT(frame_id)); args->SetInt(1, HIGH_INT(frame_id));
// Receiving the frame ID. const int64 frame_id = MAKE_INT64(args->GetInt(0), args->GetInt(1)); CefRefPtr<CefFrame> frame = browser->GetFrame(frame_id); |
|
來(lái)自: 獵狐肥 > 《Chrome_Cef》