cef3 js和C++交互

参考出处:https://github.com/fanfeilong/cefutil/blob/master/doc/CEF_JavaScript_Cpp.md

JavaScript和Cpp交互示例(Custom Implementation),交互分为js函数中带有callback和没有callback的实例

一个CEF应用程序也可以提供自己的异步JavaScript绑定。

此处演示(js在html中使用,render进程中):

JavaScript注册函数给Render进程,Render进程保存该JavaScript函数
Render进程发消息通知Browser进程
Browser进程处理后,回发消息给Render进程
Render进程调用之前保存的JavaScript函数

步骤:
1、首先在CefRenderProcessHandler的子类里覆写虚方法OnWebKitInitialized,并在该方法的实现里注册一个C++方法给JavaScript(js调用C++方法,render进程使用)

//假设CefRenderProcessHandler的子类为CefRenderProcessHandlerImpl
void CefRenderProcessHandlerImpl::OnWebKitInitialized(){
    std::string app_code =
    //-----------------------------------
    //声明JavaScript里要调用的Cpp方法
    "var app;"
    "if (!app)"
    "  app = {};"
    "(function() {"

    //  Send message ,不是回调函数实例
    "  app.sendMessage = function(name, arguments) {"
    "    native function sendMessage();"
    "    return sendMessage(name, arguments);"
    "  };"

    // Registered Javascript Function, which will be called by Cpp,有回调函数示例
    "  app.registerJavascriptFunction = function(name,callback) {"
    "    native function registerJavascriptFunction();"
    "    return registerJavascriptFunction(name,callback);"
    "  };"

    "})();";
    //------------------------------------

    // Register app extension module

    // JavaScript里调用app.registerJavascriptFunction时,就会去通过CefRegisterExtension注册的CefV8Handler列表里查找
    // 找到"v8/app"对应的CefV8HandlerImpl,就调用它的Execute方法
    // 假设m_v8Handler是CefRenderProcessHandlerImpl的一个成员变量
    m_v8Handler = new CefV8HandlerImpl();
    CefRegisterExtension("v8/app", app_code,m_v8Handler);
}

2、在CefV8Handler的子类的Execute方法里实现sendMessage和registerJavascriptFunction,js执行C++函数时,便是调用此处对应的方法。

// in CefV8HandlerImpl.h
class CefV8HandlerImpl : publice CefV8Handler{
public:
    CefV8HandlerImpl();
    ~CefV8HandlerImpl();
public:
    /**
     *  CefV8Handler Methods, Which will be called when the V8 extension 
     *  is called in the Javascript environment
     */
    virtual bool Execute(const CefString& name
        ,CefRefPtr<CefV8Value> object
        ,const CefV8ValueList& arguments
        ,CefRefPtr<CefV8Value>& retval
        ,CefString& exception);
private:
    // Map of message callbacks.
typedef std::map<std::pair<std::string, int>,
                 std::pair<CefRefPtr<CefV8Context>, CefRefPtr<CefV8Value> > >
                 CallbackMap;
CallbackMap callback_map_;//成员变量,便于js函数中设置有callback时进行调用
}
CefV8HandlerImpl::CefV8HandlerImpl()
{

}

CefV8HandlerImpl::~CefV8HandlerImpl()
{
  // Remove any JavaScript callbacks registered for the context that has been released.
  if (!callback_map_.empty()) {
    CallbackMap::iterator it = callback_map_.begin();
    for (; it != callback_map_.end();) {
      if (it->second.first->IsSame(context))
        callback_map_.erase(it++);
      else
        ++it;
    }
  }
}

// in CefV8HandlerImpl.cpp
bool CefV8HandlerImpl::Execute(const CefString& name  //JavaScript调用的C++方法名字
        ,CefRefPtr<CefV8Value> object                 //JavaScript调用者对象
        ,const CefV8ValueList& arguments              //JavaScript传递的参数
        ,CefRefPtr<CefV8Value>& retval                //需要返回给JavaScript的值设置给这个对象
        ,CefString& exception)                        //通知异常信息给JavaScript
{
    // In the CefV8Handler::Execute implementation for “registerJavascriptFunction”.
    bool handle=false;
    if(name=="registerJavascriptFunction"){
        //保存JavaScript设置的回答函数,使得render进程持有这个callback函数
        //以便js执行带有这个callback为参数的函数后,能够执行这个callback,详见步骤3
        if (arguments.size() == 2 && arguments[0]->IsString() &&
            arguments[1]->IsFunction()) {
          std::string message_name = arguments[0]->GetStringValue();
          CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
          int browser_id = context->GetBrowser()->GetIdentifier();
          //message_name和browser_id是用于区分当js回调发生时,执行的是哪个js函数的回调
          callback_map_.insert(
              std::make_pair(std::make_pair(message_name, browser_id),
                             std::make_pair(context, arguments[1])));
        handle = true;

        // 此时可以发送一个信息给Browser进程,见第4个步骤
        //registerJavascriptFunction有一个callback函数,
        //因此render进程需要持有这个callback
    }

    if(name=="sendMessage"){
        //js调用sendMessage之后,c++处理SendMessage,这个没有回调函数,
        //Execute函数return true,此次交互便结束。
        handle = true;
    }

    // 如果没有处理,则发异常信息给js
    if(!handle){
        exception="not implement function";
    }

    return true;
}

3、在HTML的JavaScript里,通过上面注册的方法向Render进程注册一个回调函数。

// In JavaScript register the callback function.
app.setMessageCallback('binding_test', function(name, args) {
  document.getElementById('result').value = "Response: "+args[0];
});
// function(name, args)为一个callback,args[0]
//消息名为binding_test,

(以下为有回调函数才有的步骤)
4、 Render进程发送异步进程间通信到Browser进程。
5、 Browser进程接收到进程间消息,并处理。
6、 Browser进程处理完毕后,发送一个异步进程间消息给Render进程,返回结果。
7、 Render进程接收到进程间消息,则调用最开始保存的JavaScript注册的回调函数处理之。(将render进程持有的这个registerJavascriptFunction的callback函数执行)

// Execute the registered JavaScript callback if any.
if (!callback_map_.empty()) {
  const CefString& message_name = message->GetName();
  CallbackMap::const_iterator it = callback_map_.find(
      std::make_pair(message_name.ToString(),
                     browser->GetIdentifier()));
//根据消息名和浏览器id找到对应的回调函数进行执行,
//message_name为binding_test时则执行js的callback,it不是空
  if (it != callback_map_.end()) {
    // Keep a local reference to the objects. The callback may remove itself
    // from the callback map.
    CefRefPtr<CefV8Context> context = it->second.first;
    CefRefPtr<CefV8Value> callback = it->second.second;

    // Enter the context.
    context->Enter();

    CefV8ValueList arguments;

    // First argument is the message name.
    arguments.push_back(CefV8Value::CreateString(message_name));

    // Second argument is the list of message arguments.
    CefRefPtr<CefListValue> list = message->GetArgumentList();
    CefRefPtr<CefV8Value> args = CefV8Value::CreateArray(list->GetSize());
    SetList(list, args);  // Helper function to convert CefListValue to CefV8Value.
    arguments.push_back(args);

    // Execute the callback.
    CefRefPtr<CefV8Value> retval = callback->ExecuteFunction(NULL, arguments);
    if (retval.get()) {
      if (retval->IsBool())
        handled = retval->GetBoolValue();
    }

    // Exit the context.
    context->Exit();
  }
}

8、在CefRenderProcessHandlerImpl::OnContextReleased()里释放JavaScript注册的回调函数以及其他V8资源。

void CefRenderProcessHandlerImpl::OnContextReleased(CefRefPtr<CefBrowser> browser,
                                  CefRefPtr<CefFrame> frame,
                                  CefRefPtr<CefV8Context> context) {
    if(m_v8Handler->Get()){
        m_v8Handler->Release();
    }
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值