cef中c++和javascript數(shù)據(jù)交互的幾種方法

cef中c++和javascript數(shù)據(jù)交互的幾種方法

基礎(chǔ)知識(shí)

cef中有兩種進(jìn)程途茫,render進(jìn)程和browser進(jìn)程削葱。

render進(jìn)程

render進(jìn)程負(fù)責(zé)顯示web頁面半抱,運(yùn)行javascript代碼辑甜。
v8引擎的初始化是在render進(jìn)程中調(diào)用的率翅,所以你的javascript代碼是在render進(jìn)程中執(zhí)行的材原。
即使你在browser進(jìn)程中調(diào)用

frame->ExecuteJavaScript()

你也要清楚沸久,代碼是發(fā)送到render進(jìn)程執(zhí)行的。

browser進(jìn)程

browser進(jìn)程是創(chuàng)建windows系統(tǒng)的客戶端窗口的進(jìn)程余蟹。
一般我們的webrtc sdk和我們的c++代碼應(yīng)該執(zhí)行在browser進(jìn)程卷胯。

進(jìn)程通信

這樣就引入了本文要講的問題,運(yùn)行在browser進(jìn)程的c++代碼如何給render進(jìn)程中javascript傳遞數(shù)據(jù)威酒。
兩個(gè)進(jìn)程的通信是通過發(fā)送進(jìn)程間消息來完成的窑睁。

//發(fā)消息給browser進(jìn)程
browser->SendProcessMessage(PID_BROWSER, message);
//發(fā)消息給render進(jìn)程
browser->SendProcessMessage(PID_RENDERER, message);

方法一、window binding (即給window對(duì)象創(chuàng)建全局變量)

如果c++希望發(fā)送一些數(shù)據(jù)給javascript葵孤,可以使用cef中的window binding技術(shù)担钮。
給javascript中的window對(duì)象添加一個(gè)全局變量。
更詳細(xì)的教程可以看cef官網(wǎng)的文檔 cef window binding
比如視頻會(huì)議的房間信息 roomInfo佛呻。

browser進(jìn)程發(fā)送roomInfo給render進(jìn)程

假設(shè)只有一個(gè)bool值要發(fā)送

  void EngineCallback::OnRoomInfo(const truman::RoomInfo& room) {
    CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
    if (browser.get() == NULL) {
      return;
    }
    CefRefPtr<CefProcessMessage> response = CefProcessMessage::Create("onRoomInfo");
    CefRefPtr<CefListValue> response_args = response->GetArgumentList();
    bool is_start = room.IsStart();
    response_args->SetBool(0, is_start);
    browser->SendProcessMessage(PID_RENDERER, response);
    return;
  }

render收到消息裳朋,執(zhí)行window binding,給window對(duì)象創(chuàng)建全局變量window.roomInfo

bool RenderDelegate::OnProcessMessageReceived(
  CefRefPtr<ClientApp> app,
  CefRefPtr<CefBrowser> browser,
  CefProcessId source_process,
  CefRefPtr<CefProcessMessage> message) {

  std::string message_name = message->GetName();
  if (message_name == "onRoomInfo") {
      CefRefPtr<CefFrame> frame = browser->GetMainFrame();
      CefRefPtr<CefV8Context> context = frame->GetV8Context();
      CefRefPtr<CefListValue> args = message->GetArgumentList();

      bool is_start = args->GetBool(2);

      context->Enter();

      CefRefPtr<CefV8Value> is_start_v8 = CefV8Value::CreateBool(is_start);

      CefRefPtr<CefV8Value> global = context->GetGlobal();

      CefRefPtr<CefV8Value> roomInfo;
      if (global->HasValue("roomInfo")) {
          roomInfo = global->GetValue("roomInfo");
      } else {
          roomInfo = CefV8Value::CreateObject(NULL);
          global->SetValue("roomInfo", roomInfo, V8_PROPERTY_ATTRIBUTE_READONLY);
      }
      roomInfo->SetValue("isStart", is_start_v8, V8_PROPERTY_ATTRIBUTE_READONLY);
      
      context->Exit();
      return true;
    }
  }

每次roomInfo變更吓著,就需要執(zhí)行一次上面的流程鲤嫡,更新window.roomInfo

方法二、使用Objects with Accessors

這種方法也是給window綁定給一個(gè)全局變量roomInfo
但是給roomInfo設(shè)置get和set方法绑莺,當(dāng)使用語法roomInfo.isStart
就會(huì)調(diào)用到get方法暖眼,get方法運(yùn)行在render進(jìn)程

在get方法里返回isStart的值。

聲明一個(gè)accessor

#include "include/cef_v8.h"

class RoomInfoAccessor : public CefV8Accessor {
public:
    RoomInfoAccessor();
    virtual ~RoomInfoAccessor();

    virtual bool Get(const CefString& name, const CefRefPtr<CefV8Value> object, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE;
    virtual bool Set(const CefString& name, const CefRefPtr<CefV8Value> object, const CefRefPtr<CefV8Value> value, CefString& exception) OVERRIDE;
    IMPLEMENT_REFCOUNTING(RoomInfoAccessor);
};

實(shí)現(xiàn)Get

bool RoomInfoAccessor::Get(const CefString& name, const CefRefPtr<CefV8Value> object
    , CefRefPtr<CefV8Value>& retval, CefString& exception)
{
    if (name == "isStart") {
        // Return the value.
        retval = CefV8Value::CreateBool(false);
        return true;
    }
    // Value does not exist.
    return false;
}

Accessor如何拿到數(shù)據(jù)纺裁?

上面的代碼并沒有去拿真實(shí)的數(shù)據(jù)诫肠,只是返回了一個(gè)false司澎。
如果要獲取真實(shí)的數(shù)據(jù),有以下幾種方法:

1栋豫、可以在c++中發(fā)送進(jìn)程消息挤安,在render進(jìn)程中將數(shù)據(jù)進(jìn)行存儲(chǔ)

類似于windows binding中發(fā)消息的部分。render進(jìn)程將數(shù)據(jù)存儲(chǔ)到本進(jìn)程中的變量如:g_roomInfo
在Get方法中讀取g_roomInfo

2丧鸯、開啟單進(jìn)程模式蛤铜,直接從內(nèi)存中獲取c++數(shù)據(jù)

在Get方法中直接讀取browser中的全局變量g_roomInfo

3、多進(jìn)程模式下丛肢,共享內(nèi)存

broswer進(jìn)程中围肥,對(duì)共享內(nèi)存進(jìn)行修改,render中的Get方法進(jìn)行讀取蜂怎。

方法三穆刻、使用cefQuery

不同于以上兩種同步數(shù)據(jù)交互方式,cefQuery是一個(gè)異步數(shù)據(jù)交互方式
cefQuery封裝了進(jìn)程間消息交互的流程杠步。
我猜測(cè)的大致流程為:
1氢伟、javascript調(diào)用window.cefQuery發(fā)送請(qǐng)求,并提交一個(gè)回調(diào)函數(shù):callback,js繼續(xù)執(zhí)行篮愉,不阻塞
2腐芍、browser進(jìn)程收到消息差导,保存messageId试躏,并執(zhí)行請(qǐng)求的運(yùn)算
3、當(dāng)browser進(jìn)程完成運(yùn)算后设褐,產(chǎn)生messageId對(duì)應(yīng)的response,發(fā)送進(jìn)程消息給render進(jìn)程
4颠蕴、render進(jìn)程收到消息,調(diào)用和messageId對(duì)應(yīng)的callback

可以參考官網(wǎng)教程:examples/message_router

方法四助析、使用XMLHttpRequest

XMLHttpRequest可以通過post方法將二進(jìn)制數(shù)據(jù)如arraybuffer發(fā)送到browser進(jìn)程犀被。
1、當(dāng)javascript需要傳遞大量二進(jìn)制數(shù)據(jù)給browser進(jìn)程的c++代碼時(shí)外冀,可以使用POST方法寡键,
2、當(dāng)javascript需要從browser進(jìn)程的c++代碼拿到大量二進(jìn)制數(shù)據(jù)時(shí)雪隧,可以使用GET方法西轩。

注意:XMLHttpRequest只支持標(biāo)準(zhǔn)的http、https協(xié)議脑沿,其他自定義scheme無法支持藕畔。
所以我們需要?jiǎng)?chuàng)建自定義的http scheme,通過限定域名domain庄拇,來對(duì)特定的domain請(qǐng)求進(jìn)行處理注服。
而其他domain的請(qǐng)求韭邓,依然通過默認(rèn)處理來完成。
具體如何使用XMLHttpRequest發(fā)送二進(jìn)制數(shù)據(jù)溶弟,我將單獨(dú)寫一篇博客女淑。
cef中javascript和c++交換二進(jìn)制數(shù)據(jù)(arraybuffer)的方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辜御,隨后出現(xiàn)的幾起案子诗力,更是在濱河造成了極大的恐慌,老刑警劉巖我抠,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苇本,死亡現(xiàn)場離奇詭異,居然都是意外死亡菜拓,警方通過查閱死者的電腦和手機(jī)瓣窄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纳鼎,“玉大人俺夕,你說我怎么就攤上這事〖桑” “怎么了劝贸?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長逗宁。 經(jīng)常有香客問我映九,道長,這世上最難降的妖魔是什么瞎颗? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任件甥,我火速辦了婚禮,結(jié)果婚禮上哼拔,老公的妹妹穿的比我還像新娘引有。我一直安慰自己,他們只是感情好倦逐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布譬正。 她就那樣靜靜地躺著,像睡著了一般檬姥。 火紅的嫁衣襯著肌膚如雪曾我。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天穿铆,我揣著相機(jī)與錄音您单,去河邊找鬼。 笑死荞雏,一個(gè)胖子當(dāng)著我的面吹牛虐秦,可吹牛的內(nèi)容都是我干的平酿。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼悦陋,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼蜈彼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起俺驶,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤幸逆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后暮现,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體还绘,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年栖袋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拍顷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡塘幅,死狀恐怖昔案,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情电媳,我是刑警寧澤踏揣,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站匾乓,受9級(jí)特大地震影響捞稿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钝尸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一括享、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧珍促,春花似錦、人聲如沸剩愧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仁卷。三九已至穴翩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锦积,已是汗流浹背芒帕。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丰介,地道東北人背蟆。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓鉴分,卻偏偏與公主長得像,于是被迫代替她去往敵國和親带膀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子志珍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容