CEF3中JavaScript与C交互详解
在现代Web开发中,Chromium Embedded Framework(CEF)是一个强大的工具,它允许开发者将Chromium浏览器嵌入到他们的桌面应用程序中,CEF3作为其最新版本,提供了更加丰富的功能和更高的性能,本文将详细探讨如何在CEF3中实现JavaScript与C++的交互,包括基本概念、具体步骤以及示例代码。
JavaScript与C++交互的基本概念
JavaScript与C++的交互通常涉及两个主要方面:从C++调用JavaScript(C++ to JS)和从JavaScript调用C++(JS to C++),这种双向通信机制使得开发者可以在桌面应用中充分利用Web技术的优势,同时保持对底层系统的控制。
1. 从C++调用JavaScript
从C++调用JavaScript通常用于执行前端脚本、修改DOM或响应用户事件,CEF3提供了CefFrame::ExecuteJavaScript()
方法来执行JavaScript代码,该方法可以在渲染进程或浏览器进程中使用,并且可以在JS上下文之外执行。
2. 从JavaScript调用C++
从JavaScript调用C++则更为复杂,通常需要通过扩展JavaScript或绑定对象来实现,CEF3允许开发者注册自定义的JavaScript函数,这些函数可以调用本地的C++代码,从而实现JS to C++的通信。
从C++调用JavaScript
从C++调用JavaScript的过程相对简单,以下是一个基本的示例,展示如何使用CefFrame::ExecuteJavaScript()
方法在C++中执行JavaScript代码。
示例:弹出消息框
#include "cef_browser.h" #include "cef_frame.h" // 假设已经有一个有效的browser对象 CefRefPtr<CefBrowser> browser; // 获取主框架 CefRefPtr<CefFrame> frame = browser->GetMainFrame(); // 执行JavaScript代码 frame->ExecuteJavaScript("alert('Hello from C++!');", frame->GetURL(), 0);
在这个示例中,我们首先获取了浏览器的主框架,然后使用ExecuteJavaScript()
方法执行了一段简单的JavaScript代码,该代码将弹出一个消息框显示“Hello from C++!”。
从JavaScript调用C++
从JavaScript调用C++需要更多的设置步骤,下面是一个详细的示例,展示如何注册一个自定义的JavaScript函数,并在该函数中调用本地的C++代码。
步骤1:定义C++端接口
我们需要在C++端定义一个接口,该接口将被JavaScript调用,这通常通过继承CefV8Handler
类来实现。
#include "cef_v8handler.h" class MyV8Handler : public CefV8Handler { public: virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { if (name == "ShowMessage") { if (arguments.size() >= 1 && arguments[0].IsString()) { std::string message = arguments[0].GetStringValue(); MessageBox(NULL, message.c_str(), "C++ Message", MB_OK); retval = CefV8Value::CreateString("Message shown"); return true; } } return false; } };
在这个示例中,我们定义了一个名为MyV8Handler
的类,该类继承自CefV8Handler
并重写了Execute
方法,当JavaScript调用名为ShowMessage
的函数时,这个方法将被触发。
步骤2:注册JavaScript扩展
我们需要在渲染进程中注册这个JavaScript扩展,以便JavaScript能够访问我们定义的函数。
void RegisterExtensions(CefRefPtr<CefBrowser> renderer) { std::string extensionCode = R"( var ShowMessage = function(message) { native function ShowMessage(message); return ShowMessage(message); }; )"; CefRefPtr<CefV8Context> context = renderer->GetMainFrame()->GetV8Context(); context->RegisterExtension("v8/ShowMessage", extensionCode, new MyV8Handler()); }
在这个示例中,我们创建了一个名为RegisterExtensions
的函数,该函数接收一个CefBrowser
对象作为参数,我们使用RegisterExtension
方法注册了一个名为v8/ShowMessage
的扩展,并将我们之前定义的JavaScript代码和C++处理器关联起来。
步骤3:在JavaScript中调用C++函数
在HTML或JavaScript文件中调用我们注册的自定义函数。
<!DOCTYPE html> <html> <head> <title>My CEF App</title> <script type="text/javascript"> function callNativeFunction() { console.log("Calling native function..."); ShowMessage("Hello from JavaScript!"); } </script> </head> <body> <button onclick="callNativeFunction()">Call Native Function</button> </body> </html>
在这个示例中,我们在HTML文件中添加了一个按钮,当点击该按钮时,将调用callNativeFunction
函数,该函数进而调用我们注册的自定义JavaScript函数ShowMessage
,从而触发C++端的Execute
方法。
完整示例代码
以下是一个完整的示例代码,展示了如何在CEF3中实现JavaScript与C++的双向交互。
#include <windows.h> #include "cef_app.h" #include "cef_client.h" #include "cef_browser.h" #include "cef_frame.h" #include "cef_v8handler.h" #include "cef_render_process_handler.h" #include "include/wrapper/cef_helpers.h" class MyV8Handler : public CefV8Handler { public: virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE { if (name == "ShowMessage") { if (arguments.size() >= 1 && arguments[0].IsString()) { std::string message = arguments[0].GetStringValue(); MessageBox(NULL, message.c_str(), "C++ Message", MB_OK); retval = CefV8Value::CreateString("Message shown"); return true; } } return false; } }; class SimpleHandler : public CefClient, public CefDisplayHandler, public CefLifeSpanHandler, public CefLoadHandler, public CefRenderProcessHandler { public: SimpleHandler() : is_closing_(false) {} ~SimpleHandler() override {} // CefClient methods CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; } CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; } CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; } CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { return this; } void OnRenderThreadCreated(CefRefPtr<CefListValue> params) override {} void OnWebKitInitialized() override { RegisterExtensions(browser_); } void OnBeforeBrowse(CefRefPtr<CefBrowser> browser) override {} void OnLoadEnd(CefRefPtr<CefBrowser> browser, bool frameOnly, int httpStatusCode) override {} void OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser, const CefString& reason, bool isReload) override {} void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {} void OnClose(CefRefPtr<CefBrowser> browser) override { is_closing_ = true; } void RunFileDialog(int mode, const std::wstring& title, const std::wstring& default_file, const std::wstring& accept_filter, int selected_accept_filter, const std::vector<std::wstring>& file_paths) override {} void OnBeforePopup(CefRefPtr<CefBrowser> parent_browser, CefRefPtr<CefFrame> frame, const CefString& target_url, CefRefPtr<CefBrowserSettings> browser_settings) override {} bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser, const CefString& url) override { return false; } void OnCertificateError(CefRefPtr<CefBrowser> browser, cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr<CefSSLInfo> ssl_info, CefRefPtr<CefRequest> callback) override {} void OnPluginCrashed() override {} void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, termination_status_t status) override {} void OnRendererUnresponsive(CefRefPtr<CefBrowser> browser) override {} bool OnProtocolExecution(const CefString& name, CefRefPtr<CefV8Context> context) override { return false; } void OnQuotaRequest(const CefString& origin_url, int64 new_size, const CefString& quota_table, void* callback_data) override {} void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override { browser_ = browser; } void OnBrowserDestroyed() override {} void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override { RegisterExtensions(browser); } void OnContextReleased(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override {} void OnBeforeDownload(const CefString& url, const CefString& suggested_name, const CefString& content_disposition, const CefString& mime_type, const CefString& download_dir, int download_id) override {} void OnDownloadUpdated(int download_id, CefRefPtr<CefDownloadItem> download_item, const CefString& download_item_download_id) override {} void OnExternalProtocolExecuted(const CefString& url) override {} void OnPostNavigationCommitPending(const CefRefPtr<CefNavigationEntry>& entry, bool is_main_frame) override {} void OnPostResourceResponseStart(const CefRefPtr<CefResponse>& response, bool frame_end) override {} void OnPreResourceLoad(const CefString& url) override {} bool IsWindowless() const override { return false; } void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) override {} bool OnTooltip(CefRefPtr<CefBrowser> browser, const CefString& text) override {} void OnAddressChange(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& url) override {} bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, const CefString& method, const CefString& url, bool is_redirect) override {} CefReturnValue OnBeforeUnhandledKeyboardEvent(const MSG& msg, bool handled) override { return handled ? 1 : 0; } void OnBeforeFocus(bool set_focus) override {} bool OnDragEnter(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> drag_data, CefMouseEvent event, int allowed_ops) override { return false; } void OnDraggableRegionsChanged(const std::vector<mojom::DraggableRegionPtr>& regions) override {} void OnBeforeDrop(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDragData> drag_data, CefMouseEvent event, int allowed_ops) override {} void OnFileDialogAborted(int file_dialog_id) override {} void OnFindResult(int identifier, int count, const CefRange& selection_range, int active_match_ordinal, bool final_update) override {} void OnGetAuthPassword(const CefString& origin_url, const CefString& dialog_title, const CefString& username, const CefString& password) override {} void OnJumpToAnchor(const CefString& anchor_name) override {} bool ShouldCloseBrowser(bool force_close) override { return !is_closing_ && force_close; } bool ShouldHeuristicallyOpenPDF(const CefString& url) override { return false; } void OnMediaPlaybackStateChanged(const CefString& url, double currentTime, double duration) override {} void OnMediaMenuButtonEmitted(const std::wstring& path, int renderer_id) override {} void OnMediaRouteCreated(const std::wstring& media_route_id) override {} void OnMediaRouteClosed(const std::wstring& media_route_id) override {} bool OnTakeFocus(bool next, bool reverse) override {} bool OnSetFocus(bool source_null, CefFocusSource source) override { return false; } bool OnGotFocus(bool source_null, CefFocusSource source) override { return false; } bool OnLostFocus(bool source_null, CefFocusSource source) override { return false; } private: CefRefPtr<CefBrowser> browser_; bool is_closing_; };
原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1380658.html
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复