利用InjectedBundle定制自己的Webkit(一)


Webkit是一個多進程構架,內核WebCore和JS引擎JavaScriptCore都處在WebProcess進程中,而用戶界面相關的處理則處在UIProcess進程中。(詳見Webkit客戶端進程解析

Webkit提供了大量的API供客戶程序調用,但是這些API都是在客戶進程中調用的,我們無法訪問到內核部分的數據結構並處理,如DOM樹、Render樹、加載的Web資源等等。為了解決這一問題,Webkit提供了一個運行在內核進程的InjectedBundle來提供對內核數據的操作。

InjectedBundle類似於一個插件,單獨編譯成一個動態庫,在內核進程運行到特定情況時會調用InjectedBundle中注冊的對應函數來實現自定義操作。每個WebProcess只能加載一個InjectedBundle,用戶可以在創建WebProcess的時候指定使用哪個InjectedBundle。

接下來我們就動手制作一個自己的InjectedBundle然后用Webkit加載它。

 

1. 准備工作

我采用的編譯環境是VC2005

(1)首先需要下載並編譯Webkit(詳見Windows平台編譯Webkit

(2)然后創建一個空項目,修改項目屬性

  a. 配置類型:動態庫(.dll)  

  b. 添加附加包含目錄:Webkit生成文件路徑\inlude 和 Webkit生成文件路徑\include\include(一定要加兩個,第二個是windows平台缺少的第三方庫頭文件)

  c. 添加附加庫目錄:Webkit生成文件路徑\lib

好,項目配置完畢!接下來實現Webkit所需的接口

 

2. 編寫InjectedBundle

先上代碼

#include <WebKit2/WKBundleInitialize.h>

#pragma comment(lib, "WebKit.lib"

extern "C" __declspec(dllexport)

void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)

  // 初始化代碼

}

InjectedBundle只需要實現這一個函數即可(是不是很簡單),其中參數bundle是Webkit給你的InjectedBundle分配的標志(identifier),可以用它來調用一些InjectedBundle的API,所以存下來為妙;參數initializationUserData是用戶利用Webkit加載該InjectedBundle時傳入的一些數據(我們可以用它來傳啟動參數)。

 

接下來我們要做的就是在該初始化函數中注冊我們需要的回調函數

  在Webkit中以Client結尾的結構體都是一個回調函數組,比如WKBundlePageLoaderClient就是一組處理頁面加載的回調函數,每個Client都有一個版本號和clientInfo,clientInfo是用來在回調函數中傳遞用戶參數。利用對應的WKBundleSetXXXClient就能夠注冊某一個回調函數組。

  我們需要注冊的第一組回調函數是WKBundleClient,內容如下

struct WKBundleClient {

  int version;                              // 版本號

  const void * clientInfo;                        // 用戶參數

  WKBundleDidCreatePageCallback didCreatePage;           // page創建完畢

  WKBundleWillDestroyPageCallback willDestroyPage;           // page將要銷毀

  WKBundleDidInitializePageGroupCallback didInitializePageGroup;   // page組初始化完畢

  WKBundleDidReceiveMessageCallback didReceiveMessage;       // 收到用戶消息

};

  前兩個已經說過了,這里主要講didCreatePage和didReceiveMessage

 

(1)didCreatePage

  該函數是在創建一個Page對象之后被調用的,原型是

typedef void (*WKBundleDidCreatePageCallback)(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo);

  在回調里我們能獲得所創建Page的引用page,利用這個引用可以調用一些和page相關的API。其中比較重要的是WKBundlePageSetXXXClient,利用這一組函數可以設置該頁面的一些回調,比如之前說過的WKBundlePageLoaderClient,包含了didReceiveTitleForFrame(當收到Frame的標題后調用),didFinishLoadForFrame(當一個Frame對象加載完畢后被調用)等回調函數。利用這些回調函數就能在不同階段實現我們想要的功能了。

 

(2)didReceiveMessage

  該函數是在收到客戶進程的消息后調用的。Webkit設計了一個消息隊列機制使得兩個進程之間能夠通信,客戶進程通過調用WKContextSetInjectedBundleClient給InjectedBundle發消息,InjectedBundle通過WKBundlePostMessage向客戶進程發消息。我們利用這個方法就能在兩個進程間交換數據。例如把InjectedBundle處理的結果傳給客戶進程,或者客戶進程向InjectedBundle發指令。

消息的格式是messageName + messageBody

messageName是WKStringRef,即一個字符串

messageBody是任意的WKType,如:WKDictionaryRef, WKDataRef, WKArrayRef等等。

 

在InjectedBundle寫完之后編譯生成一個.dll文件就可以拿來使用了。

下一篇中將介紹怎樣在Webkit中加載InjectedBundle,待續...


免責聲明!

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



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