CEF(Chromium Embedded Framework和JavaScript交互相互調用函數和設置數據


3.1     CEF和JavaScript交互

3.1.1     在CEF執行JavaScript腳本

3.1.2     窗口綁定方式實現CEF設置JavaScript的變量

3.1.3     擴展方式(Extension)實現CEF設置JavaScript的變量

3.1.4     窗口綁定方式實現CEF給JavaScript提供函數

3.1.5     Extension方式實現CEF給JavaScript提供函數

 

3.1  CEF和JavaScript交互

https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md

CEF使用的V8 JavaScript 引擎用於內部JavaScript實現,每一個frame都有JS上下文(context),為JS代碼執行提供范圍和安全。CEF暴露了很多JS特性可以和客戶端程序進行交互。

3.1.1         在CEF執行JavaScript腳本

應用場景是需要在CEF中攔截一個URL請求,並把它重定向到另外一個URL,可以調用pFrame->ExecuteJavaScript來執行一個JavaScript腳本,實現跳轉。當然也可以實現其他應用功能。

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         窗口綁定方式實現CEF設置JavaScript的變量

在CEF程序中,創建一個CefV8Value對象,獲取上下文的窗口對象,注入窗口對象一個變量值,網頁中就可以使用JavaScript獲取這個變量值。窗口綁定在CefRenderProcessHandler::OnContextCreated()函數中。是上下文創建響應函數,窗口綁定方式在每次frame重新加載(context創建)時都會加載一遍,CEF程序可以在OnContextCreated()給每一個frame設置不同的變量值。

    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         擴展方式(Extension)實現CEF設置JavaScript的變量

Extension方式和窗口綁定方式類似,但是Extension方式是為每一個frame加載到上下文context,一旦加載變不能在修改,沒有加載之前,DOM是不存在的,嘗試范圍這個值的DOM會出現崩潰。Extension方式是在CefRenderProcessHandler::OnWebKitInitialized()函數中用CefRegisterExtension() 函數注冊的,是在初始化函數中實現的,所以對於每一個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中調用變量值

<script language="JavaScript">

alert(test.myval); // Shows an alert box with "My Value!"

</script>

3.1.4         窗口綁定方式實現CEF給JavaScript提供函數

(1)   自定義類實現CefV8Handler類,實現Execute接口,JavaScript執行函數后,會將函數名稱、參數和返回值引用傳遞給Execute函數,Execute函數根據函數名去調用函數,函數的具體實現在Execute中,然后執行返回返回值。

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)將函數名稱設置到窗口對象,提供接受調用的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執行函數調用,就會進入Execute函數,返回返回值,alert會以彈窗形式展示結果。

<script language="JavaScript">
alert(window.myfunc()); // Shows an alert box with "My Value!"
</script>

 

3.1.5         Extension方式實現CEF給JavaScript提供函數

JavaScript調用CEF中的函數步驟:

(1)實現app類,繼承與CefApp,重寫OnWebKitInitialized,在OnWebKitInitialized函數內部使用字符串定義函數。CEF調用CefRegisterExtension函數向JavaScript注冊函數,並提供處理調用的handler。

//CefClientApp.h

class CCefClientApp : public CefApp, public CefBrowserProcessHandler, CefRenderProcessHandler

{

public:

    CCefClientApp();

    ~CCefClientApp();

 

 

    //所有的CEF接口 都需要重載GetXXXHandler,並且return this,才會有效

    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里要調用的Cpp方法

        "var app;"

        "if (!app)"

        "  app = {};"

        "(function() {"

 

        //  jsInvokeCPlusPlus 實例函數

        "  app.jsInvokeCPlusPlus = function(v1, v2) {"

        "    native function jsInvokeCPlusPlus();"

        "    return jsInvokeCPlusPlus(v1, v2);"

        "  };"

 

        //函數

        "  app.jsTransform = function(v1) {"

        "    native function jsTransform();"

        "    return jsTransform(v1);"

        "  };"

 

        "})();";

 

 

    // Register app extension module

 

    // JavaScript里調用app.jsInvokeCPlusPlus時,就會去通過CefRegisterExtension注冊的CefV8Handler列表里查找

    // 找到"v8/app"對應的CCEFV8HandlerEx,就調用它的Execute方法

    // 假設v8Handler_是CCefClientApp的一個成員變量

    //v8Handler_ = new CCEFV8HandlerEx();

 

    CefRegisterExtension("v8/app", app_code, v8Handler_);

 

}

(2)JavaScript調用函數

<html>

<script>

app.jsInvokeCPlusPlus("123","xyz");

app.jsTransform("hello world");

</script>

</html>

(3)    handler的Execute函數接收調用響應,根據函數名稱判斷是調用哪個函數,獲取參數調用函數。

//CEFV8HandlerEx.h
 
class CCEFV8HandlerEx : public CefV8Handler {
public:
    CCEFV8HandlerEx();
    ~CCEFV8HandlerEx();
public:
    virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) override;
private:
    // Map of message callbacks.
    typedef std::map<std::pair<std::string, int>, std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >CallbackMap;
    CallbackMap callback_map_;
 
 
public:
    IMPLEMENT_REFCOUNTING(CCEFV8HandlerEx);
};
 
//CEFV8HandlerEx.cpp
 
//JS調用C++函數的回調
bool CCEFV8HandlerEx::Execute(const CefString& name  /*JavaScript調用的C++方法名字*/, CefRefPtr<CefV8Value> object /*JavaScript調用者對象*/, const CefV8ValueList& arguments /*JavaScript傳遞的參數*/, CefRefPtr<CefV8Value>& retval /*返回給JS的值設置給這個對象*/, CefString& exception/*通知異常信息給JavaScript*/)
{
    if (name == _T("jsInvokeCPlusPlus"))
    {
        if (arguments.size() == 2)
        {
            CefString strParam1 = arguments.at(0)->GetStringValue();
            CefString strParam2 = arguments.at(1)->GetStringValue();
 
            TCHAR szBuffer[512];
            StringCbPrintf(szBuffer, sizeof(szBuffer), _T("jsInvokeCPlusPlus(%s,%s)"), strParam1.c_str(), strParam2.c_str());
            ::MessageBox(GetForegroundWindow(), szBuffer, _T("jsInvokeCPlusPlus"), MB_OK);
            retval = CefV8Value::CreateInt(0);
        }
        else
        {
            retval = CefV8Value::CreateInt(2);
        }
 
        return true;
 
    }
 
    if (name == L"jsTransform") {
        CefString strParam1 = arguments.at(0)->GetStringValue();
        TCHAR szBuffer[512];
        StringCbPrintf(szBuffer, sizeof(szBuffer), _T("jsTransform(%s)"), strParam1.c_str());
        ::MessageBox(GetForegroundWindow(), szBuffer, _T("jsTransform"), MB_OK);
    }
    return false;
}

自己開發了一個股票智能分析軟件,功能很強大,需要的點擊下面的鏈接獲取:

https://www.cnblogs.com/bclshuai/p/11380657.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM