編輯:關於Android編程
Chromium的Extension Page其實就是網頁,因此它們的加載過程與普通網頁相同。常見的Extension Page有Background Page和Popup Page。其中,Background Page在浏覽器窗口初始化完成後自動加載,之後運行在後台中。Popup Page在用戶點擊地址欄右邊的按鈕時加載,並且顯示在彈窗中。本文接下來就分析Extension Page的加載過程。
Extension Page是由Browser進程發加載在Extension Process中的,如圖1所示:
圖1 Extension的Background Page和Popup Page的加載示意圖
Extension Process實際上就是Render Process。Chromium的Content層向外提供了一個WebContents類,通過調用這個類的靜態成員函數Create就可以在一個Extension Process加載一個指定的Extension Page。
Background Page是一個特殊的網頁,它的內容是空的,不過包含有一個background.js。這個background.js是在Extension的清單文件中指定的。Popup Page則與普通網頁是一樣的,它既可以包含有UI元素,也可以包含JavaScript腳本。
接下來,我們就結合源代碼,先分析Background Page的加載過程,再分析Popup Page的加載過程。
Chromium的chrome模塊會創建一個ChromeNotificationObserver對象,用來監聽每一個新打開的浏覽器窗口的NOTIFICATION_BROWSER_WINDOW_READY事件。這時候上述ChromeNotificationObserver對象的成員函數OnBrowserWindowReady會被調用,如下所示:
void ChromeNotificationObserver::OnBrowserWindowReady(Browser* browser) { Profile* profile = browser->profile(); ...... extensions::ProcessManager* manager = ExtensionSystem::Get(profile)->process_manager(); ...... manager->OnBrowserWindowReady(); ...... }這個函數定義在文件external/chromium_org/chrome/browser/extensions/chrome_notification_observer.cc中。
參數browser指向的是一個Browser對象。這個Browser對象描述的就是一個新打開的浏覽器窗口,ChromeNotificationObserver類的成員函數OnBrowserWindowReady首先調用它的成員函數profile獲得浏覽器在啟動過程中創建的Profile,然後再根據這個Profile獲得一個ProcessManager對象。有了這個ProcessManager對象之後,就可以調用它的成員函數OnBrowserWindowReady,用來通知它有一個新的浏覽器窗口打開了。浏覽器啟動時創建Profile的過程,以及根據Profile創建ProcessManager對象的過程。
ProcessManager類的成員函數OnBrowserWindowReady在調用的過程中,就會為當前加載的Extension創建Background Page,如下所示:
void ProcessManager::OnBrowserWindowReady() { ...... CreateBackgroundHostsForProfileStartup(); }這個函數定義在文件external/chromium_org/extensions/browser/process_manager.cc中。
ProcessManager類的成員函數OnBrowserWindowReady調用另外一個成員函數CreateBackgroundHostsForProfileStartup為當前加載的Extension創建Background Page,如下所示:
void ProcessManager::CreateBackgroundHostsForProfileStartup() { ...... const ExtensionSet& enabled_extensions = ExtensionRegistry::Get(GetBrowserContext())->enabled_extensions(); for (ExtensionSet::const_iterator extension = enabled_extensions.begin(); extension != enabled_extensions.end(); ++extension) { CreateBackgroundHostForExtensionLoad(this, extension->get()); ...... } ...... }這個函數定義在文件external/chromium_org/extensions/browser/process_manager.cc中。
Chromium的Browser進程在啟動的時候,會將那些狀態設置為Enabled的Extension保存在一個Extension Registry的Enabled List中。ProcessManager類的成員函數CreateBackgroundHostsForProfileStartup主要就是遍歷這個Enabled List中的每一個Extension,並且調用函數CreateBackgroundHostForExtensionLoad檢查它們是否指定了Background Page。如果指定了,那麼就會進行加載。
函數CreateBackgroundHostForExtensionLoad的實現如下所示:
static void CreateBackgroundHostForExtensionLoad( ProcessManager* manager, const Extension* extension) { DVLOG(1) << "CreateBackgroundHostForExtensionLoad"; if (BackgroundInfo::HasPersistentBackgroundPage(extension)) manager->CreateBackgroundHost(extension, BackgroundInfo::GetBackgroundURL(extension)); }這個函數定義在文件external/chromium_org/extensions/browser/process_manager.cc中。
函數CreateBackgroundHostForExtensionLoad首先檢查參數extension描述的Extension是否指定了類型為persitent的Background Page。如果指定了,那麼就會調用參數manager指向的一個ProcessManager對象的成員函數CreateBackgroundHost對它進行加載。對於非persitent的Background Page,它們只會在特定事件發生時,才會被加載。本文主要以類型為persitent的Background Page為例,說明它們的加載過程。非persitent的Background Page的加載過程,也是類似的。
函數CreateBackgroundHostForExtensionLoad在調用ProcessManager類的成員函數CreateBackgroundHost加載一個Background Page之前,首先要獲得這個Background Page的URL。這個URL是通過調用BackgroundInfo類的靜態成員函數GetBackgroundURL獲得的,如下所示:
GURL BackgroundInfo::GetBackgroundURL(const Extension* extension) { const BackgroundInfo& info = GetBackgroundInfo(extension); if (info.background_scripts_.empty()) return info.background_url_; return extension->GetResourceURL(kGeneratedBackgroundPageFilename); }這個函數定義在文件external/chromium_org/extensions/common/manifest_handlers/background_info.cc中。
Chromium將其平台上的程序分為擴展(Extension)和應用(App)兩種。兩者具有相同的文件結構,在Chromium中都是通過一個Extension類描述,但是後者比前者具有更嚴格的權限限制。應用又分為Hosted App(托管應用)和Packaged App(打包應用)兩種。Hosted App只提供一個圖標和Manifest文件,並且在Manifest文件中聲明了它的Popup Page和Background Page等URL。Packaged App則將Popup Page和Background Page文件打包在一起安裝在本地。關於Extension、Packaged App和Packaged App的更詳細描述。
我們假設參數extension描述的是一個Extension,並且是一個安裝在本地的Extension。這時候它在Manifest文件實際上只是為Backgropund Page指定了Background Script,如我們在前面一文所示的Page action example:
{ ...... "background": { "scripts": ["background.js"] }, ...... }BackgroundInfo類的靜態成員函數GetBackgroundURL首先會獲得參數extension描述的Extension的Background Page信息。這些信息保存在一個BackgroundInfo對象中。當這個BackgroundInfo對象的成員變量background_scripts_的值不等空時,它的值描述的就是一個Background Page的Background Script,同時也表明參數extension描述的不是一個Hosted App。在這種情況下,我們就不能直接獲得Background Page的URL,而是要通過調用參數extension指向的Extension對象的成員函數GetResourceURL獲得。
Extension類的成員函數GetResourceURL的實現如下所示:
class Extension : public base::RefCountedThreadSafe這個函數定義在文件external/chromium_org/extensions/common/extension.h中。{ public: ...... GURL GetResourceURL(const std::string& relative_path) const { return GetResourceURL(url(), relative_path); } ...... };
從前面的調用過程可以知道,參數relative_path的值為kGeneratedBackgroundPageFilename。Extension類的成員函數GetResourceURL首先調用另外一個成員函數url獲得當前正在處理的Extension的URL。這個URL的形式為:chrome-extension://[extension_id]/。其中,[extension_id]為當前正在處理的Extension的ID。
最後,Extension類的成員函數GetResourceURL將參數relative_path的值kGeneratedBackgroundPageFilename添加在前面獲得的URL的後面,從而得到當前正在處理的Extension的Background Page的URL。這是通過調用Extension類的靜態成員函數GetResourceURL實現的,如下所示:
// static GURL Extension::GetResourceURL(const GURL& extension_url, const std::string& relative_path) { ...... std::string path = relative_path; // If the relative path starts with "/", it is "absolute" relative to the // extension base directory, but extension_url is already specified to refer // to that base directory, so strip the leading "/" if present. if (relative_path.size() > 0 && relative_path[0] == '/') path = relative_path.substr(1); GURL ret_val = GURL(extension_url.spec() + path); ...... return ret_val; }這個函數定義在文件external/chromium_org/extensions/common/extension.cc中。
通過上面的分析,我們就可以知道,一個Extension如果指定了Background Page,那麼這個Background Page的URL就為chrome-extension://[extension_id]/kGeneratedBackgroundPageFilename。其中,kGeneratedBackgroundPageFilename是一個常量,它的定義如下所示:
const char kGeneratedBackgroundPageFilename[] = "_generated_background_page.html";這個常量定義在文件external/chromium_org/extensions/common/constants.cc中。
這意味著,一個Extension的Background Page的URL為:chrome-extension://[extension_id]/_generated_background_page.html。Chromium的extension模塊會注冊一個Chromium Extension Protocol Handler,用來處理chrome-extension協議。也就是說,當我們在浏覽器的地址欄輸入上述URL時ChromiumExtension Protocol Handler會返回[extension_id]/_generated_background_page.html的內容給WebKit處理。這個文件的內容是動態生成的。以前面的Page action example為例,Chromium Extension Protocol Handler為它生成的_generated_background_page.html的內容如下所示:
<script src="background.js"></script>獲得了要加載的Background Page的URL之後,回到前面分析的函數CreateBackgroundHostForExtensionLoad中,接下來它就會調用ProcessManager類的成員函數CreateBackgroundHost加載Background Page,如下所示:
bool ProcessManager::CreateBackgroundHost(const Extension* extension, const GURL& url) { ...... ExtensionHost* host = new ExtensionHost(extension, GetSiteInstanceForURL(url), url, VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); host->CreateRenderViewSoon(); ...... return true; }這個函數定義在文件external/chromium_org/extensions/browser/process_manager.cc中。
ProcessManager類的成員函數CreateBackgroundHost首先是創建一個ExtensionHost對象。這個ExtensionHost對象類似於Chromium加載一個普通URL時在Browser進程中創建的RenderProcessHost對象。關於RenderProcessHost的詳細描述,可以參考Chromium多進程架構簡要介紹和學習計劃這個系列的文章。
ExtensionHost對象在創建的過程中,會創建一個WebContents對象,如下所示:
ExtensionHost::ExtensionHost(const Extension* extension, SiteInstance* site_instance, const GURL& url, ViewType host_type) : ......, initial_url_(url), ...... { ...... host_contents_.reset(WebContents::Create( WebContents::CreateParams(browser_context_, site_instance))), ...... }
這個函數定義在文件external/chromium_org/extensions/browser/extension_host.cc中。
創建出來的WebContents對象保存在ExtensionHost類的成員變量host_contents_中。同時,要加載的Background Page URL將會保存在ExtensionHost類的成員變量initial_url_中。
回到前面分析的ProcessManager類的成員函數CreateBackgroundHost,它創建了一個ExtensionHost對象之後,接下來就會調用這個ExtensionHost對象的成員函數CreateRenderViewSoon加載指定的Background Page,如下所示:
void ExtensionHost::CreateRenderViewSoon() { if ((render_process_host() && render_process_host()->HasConnection())) { // If the process is already started, go ahead and initialize the RenderView // synchronously. The process creation is the real meaty part that we want // to defer. CreateRenderViewNow(); } else { ProcessCreationQueue::GetInstance()->CreateSoon(this); } }這個函數定義在文件external/chromium_org/extensions/browser/extension_host.cc中。
ExtensionHost類的成員函數CreateRenderViewSoon首先判斷用來加載指定的Background Page的Extension Process是否已經創建出來了。如果已經創建,那麼就直接調用另外一個成員函數CreateRenderViewNow同步請求在這個Extension Process中加載指定的Background Page。否則的話,則需要通過調用當前進程中的一個ProcessCreationQueue單例對象的成員函數CreateSoon異步請求加載指定的的Background Page。後一種情況之所以要異步請求,是因為這種情況需要先創建一個Extension Process,然後才能加載指定的Background Page,而創建Extension Process是一個相對耗時的操作。
在異步請求情況下,指定的Background Page同樣也是通過ExtensionHost類的成員函數CreateRenderViewNow進行加載的。因此,接下來我們繼續分析它的實現,如下所示:
void ExtensionHost::CreateRenderViewNow() { LoadInitialURL(); ...... }這個函數定義在文件external/chromium_org/extensions/browser/extension_host.cc中。
ExtensionHost類的成員函數CreateRenderViewNow調用另外一個成員函數LoadInitialURL加載指定的Background Page,如下所示:
void ExtensionHost::LoadInitialURL() { host_contents_->GetController().LoadURL( initial_url_, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string()); }這個函數定義在文件external/chromium_org/extensions/browser/extension_host.cc中。
從前面的分析可以知道,指定要加載的Background Page的URL保存在ExtensionHost類的成員變量initial_url_中。ExtensionHost類的成員函數LoadInitialURL首先通過調用成員變量host_contents_指向的WebContents對象的成員函數GetController獲得一個NavigationControllerImpl對象。有了這個NavigationControllerImpl對象之後,就可以調用它的成員函數LoadURL在相應的Extension Process中加載指定的Background Page了。這個過程與加載一個普通的URL是一樣的,具體可以參考前面Chromium網頁Frame Tree創建過程分析一文。
這樣,我們就分析完成了Extension的Background Page的加載過程。從分析的過程可以知道,Extension的Background Page本質上是一個保存在本地的網頁,因此它的加載過程與普通的URL並無異。接下來,我們繼續分析Extension的Popup Page的加載過程。
從前面Chromium擴展(Extension)機制簡要介紹和學習計劃一文可以知道,Browser Action和Page Action均可在地址欄右邊放置一個按鈕,並且在點擊該按鈕時,顯示一個Popup Page。兩者加載Popup Page的原理都是一樣的,因此接下來我們以Browser Action為例,分析Popup Page的加載過程。
當一個Extension指定了Browser Action時,Chromium將會為其創建一個BrowserActionButton。這個BrowserActionButton描述的就是Extension在地址欄右邊的按鈕。當用戶點擊這個按鈕的時候,BrowserActionButton類的成員函數ButtonPressed就會被調用,如下所示:
void BrowserActionButton::ButtonPressed(views::Button* sender, const ui::Event& event) { delegate_->OnBrowserActionExecuted(this); }這個函數定義在文件external/chromium_org/chrome/browser/ui/views/toolbar/browser_action_view.cc中。
BrowserActionButton類的成員變量delegate_指向的是一個BrowserActionsContainer對象。這個BrowserActionsContainer對象描述的是包含Browser Action Button的容器,BrowserActionButton類的成員函數ButtonPressed調用它的成員函數OnBrowserActionExecuted,通知它在一個彈出窗口中加載一個Popup Page。
BrowserActionsContainer類的成員函數OnBrowserActionExecuted的實現如下所示:
void BrowserActionsContainer::OnBrowserActionExecuted( BrowserActionButton* button) { ShowPopup(button, ExtensionPopup::SHOW, true); }這個函數定義在文件external/chromium_org/chrome/browser/ui/views/toolbar/browser_actions_container.cc中。
BrowserActionsContainer類的成員函數OnBrowserActionExecuted調用另外一個成員函數ShowPopup顯示一個Popup Page,如下所示:
bool BrowserActionsContainer::ShowPopup( BrowserActionButton* button, ExtensionPopup::ShowAction show_action, bool should_grant) { const Extension* extension = button->extension(); GURL popup_url; if (model_->ExecuteBrowserAction( extension, browser_, &popup_url, should_grant) != extensions::ExtensionToolbarModel::ACTION_SHOW_POPUP) { return false; } ...... popup_ = ExtensionPopup::ShowPopup(popup_url, browser_, reference_view, views::BubbleBorder::TOP_RIGHT, show_action); ...... return true; }這個函數定義在文件external/chromium_org/chrome/browser/ui/views/toolbar/browser_actions_container.cc中。
BrowserActionsContainer類的成員函數ShowPopup首先調用成員變量model_指向的一個ExtensionToolbarModel對象的成員函數ExecuteBrowserAction獲得要顯示的Popup Page的URL,如下所示:
ExtensionToolbarModel::Action ExtensionToolbarModel::ExecuteBrowserAction( const Extension* extension, Browser* browser, GURL* popup_url_out, bool should_grant) { ...... ExtensionAction* browser_action = ExtensionActionManager::Get(profile_)->GetBrowserAction(*extension); ...... if (browser_action->HasPopup(tab_id)) { if (popup_url_out) *popup_url_out = browser_action->GetPopupUrl(tab_id); return ACTION_SHOW_POPUP; } ...... return ACTION_NONE; }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_toolbar_model.cc中。
參數extension描述的就是要顯示Popup Page的Extension。ExtensionToolbarModel類的成員函數ExecuteBrowserAction首先通過調用ExtensionActionManager類的靜態成員函數Get獲得與當前使用的Profile關聯的一個ExtensionActionManager對象。有了這個ExtensionActionManager對象之後,就可以獲得參數extension描述的Extension在清單文件中配置的Browser Action信息。這些信息封裝在一個ExtensionAction對象中。
獲得了要顯示Popup Page的Extension的Browser Action信息之後,就可以檢查它是否指定了Popup Page。如果指定了,並且輸出參數popup_url_out的值不等於NULL,那麼ExtensionToolbarModel類的成員函數ExecuteBrowserAction就會調用前面獲得的一個ExtensionAction對象的成員函數GetPopupUrl獲得當前要顯示的Popup Page的URL。獲取到的Popup Page URL將會通過輸出參數popup_url_out返回給調用者。
接下來我們繼續分析ExtensionAction類的成員函數GetPopupUrl的實現,以便了解Extension的Popup Page URL的結構,如下所示:
GURL ExtensionAction::GetPopupUrl(int tab_id) const { return GetValue(&popup_url_, tab_id); }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_action.cc中。
ExtensionAction類的成員函數GetPopupUrl返回的是成員變量popup_url_的值。這個值是在ExtensionAction類的構造函數中設置的,如下所示:
ExtensionAction::ExtensionAction(const std::string& extension_id, extensions::ActionInfo::Type action_type, const extensions::ActionInfo& manifest_data) : extension_id_(extension_id), action_type_(action_type) { ...... SetPopupUrl(kDefaultTabId, manifest_data.default_popup_url); ...... }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_action.cc中。
參數manifest_data指向的是一個ActionInfo對象。這個ActionInfo對象描述的是Extension在清單文件中配置的Browser Action信息。通過這個ActionInfo對象的成員變量default_popup_url可以獲得為Browser Action指定的Popup Page文件名。以前面Chromium擴展(Extension)機制簡要介紹和學習計劃一文中的Browser action example為例,它為Browser Action指定的Popup Page文件名為“popup.html”,如下所示:
{ ...... "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, ...... }回到ExtensionAction類的構造函數中,它獲得的Popup Page URL將會通過調用成員函數SetPopupUrl保存在成員變量popup_url_中,如下所示:
void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { ...... SetValue(&popup_url_, tab_id, url); }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_action.cc中。
從前面的分析就可以知道,Extension的Popup Page的URL來自於ExtensionAction類的成員變量popup_url_,而後者的值又來自於ActionInfo類的成員變量default_popup_url。因此,接下來我們繼續分析ActionInfo類的成員變量default_popup_url的設置過程,以便了解Extension的Popup Page URL的結構。
ActionInfo類的成員變量default_popup_url是在加載Extension的過程中設置的。一個Extension如果指定了Browser Action,那麼Chromium就會調用ActionInfo類的靜態成員函數Load解析Browser Action的信息,如下所示:
scoped_ptr ActionInfo::Load(const Extension* extension, const base::DictionaryValue* dict, base::string16* error) { scoped_ptr result(new ActionInfo()); ...... // Read the action's |popup| (optional). const char* popup_key = NULL; if (dict->HasKey(keys::kPageActionDefaultPopup)) popup_key = keys::kPageActionDefaultPopup; ...... if (popup_key) { const base::DictionaryValue* popup = NULL; std::string url_str; if (dict->GetString(popup_key, &url_str)) { // On success, |url_str| is set. Nothing else to do. } ...... if (!url_str.empty()) { // An empty string is treated as having no popup. result->default_popup_url = Extension::GetResourceURL(extension->url(), url_str); ...... } ...... } return result.Pass(); }這個函數定義在文件external/chromium_org/chrome/common/extensions/api/extension_action/action_info.cc中。
ActionInfo類的靜態成員函數Load首先創建一個ActionInfo對象描述當前要解析的Browser Action的信息。
ActionInfo類的靜態成員函數Load接下來檢查當前要解析的Browser Action是否指定了popup屬性。如果指定了,那麼它的值就是一個Popup Page的文件名。這個文件名會被提取出來,保存在變量url_str中。
有了Popup Page的文件名之後,我們還需要知道它所屬的Extension的URL。這可以通過調用參數extension指向的Extension對象的成員函數url獲得。前面我們提到過,一個Extension的URL的形式為:chrome-extension://[extension_id]/。其中,[extension_id]為當前正在處理的Extension的ID。
有了Extension的URL之後,就可以將前面獲得的Popup Page文件名附加在它之後,從而得到一個Popup Page的URL。這是通過調用Extension類的靜態成員函數GetResourceURL實現的。Extension類的靜態成員函數GetResourceURL我們在前面已經分析過,這裡不再復述。
最後,ActionInfo類的靜態成員函數Load會將獲得Popup Page URL保存在前面創建的ActionInfo對象的成員變量default_popup_url中。這樣,我們前面分析的ExtensionAction類的構造函數就可以通過這個成員變量獲得一個Popup Page的URL,並且將它保存在自己的成員變量popup_url_中了。
這一步執行完成之後,回到前面分析的BrowserActionsContainer類的成員函數ShowPopup中,這時候就它獲得了要加載的Popup Page的URL,接下來它又會通過調用ExtensionPopup類的靜態成員函數ShowPopup加載該URL,如下所示:
ExtensionPopup* ExtensionPopup::ShowPopup(const GURL& url, Browser* browser, views::View* anchor_view, views::BubbleBorder::Arrow arrow, ShowAction show_action) { extensions::ExtensionViewHost* host = extensions::ExtensionViewHostFactory::CreatePopupHost(url, browser); ExtensionPopup* popup = new ExtensionPopup(host, anchor_view, arrow, show_action); ...... return popup; }這個函數定義在文件external/chromium_org/chrome/browser/ui/views/extensions/extension_popup.cc中。
ExtensionPopup類的靜態成員函數ShowPopup首先調用ExtensionViewHostFactory類的靜態成員函數CreatePopupHost創建一個ExtensionViewHost對象。有了這個ExtensionViewHost對象之後,就可以將它封裝在一個ExtensionPopup對象中。這個ExtensionPopup對象描述的就是當前要顯示的Popup Page。
ExtensionViewHostFactory類的靜態成員函數CreatePopupHost在創建ExtensionViewHost對象的過程中,就會通過前面提到的WebContents接口加載Popup Page,如下所示:
ExtensionViewHost* ExtensionViewHostFactory::CreatePopupHost(const GURL& url, Browser* browser) { DCHECK(browser); return CreateViewHost( url, browser->profile(), browser, VIEW_TYPE_EXTENSION_POPUP); }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_view_host_factory.cc中。
ExtensionViewHostFactory類的靜態成員函數CreatePopupHost通過調用函數CreateViewHost創建一個ExtensionViewHost對象,如下所示:
ExtensionViewHost* CreateViewHost(const GURL& url, Profile* profile, Browser* browser, extensions::ViewType view_type) { ...... const Extension* extension = GetExtensionForUrl(profile, url); ...... return CreateViewHostForExtension( extension, url, profile, browser, view_type); }
這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_view_host_factory.cc中。
函數CreateViewHost首先通過調用函數GetExtensionForUrl獲得一個Extension對象。這個Extension對象描述的就是當前要顯示Popup Page的Extension。有了這個Extension對象之後,函數CreateViewHost最後調用另外一個函數CreateViewHostForExtension創建一個ExtensionViewHost對象,如下所示:
ExtensionViewHost* CreateViewHostForExtension(const Extension* extension, const GURL& url, Profile* profile, Browser* browser, ViewType view_type) { ...... ProcessManager* pm = ExtensionSystem::Get(profile)->process_manager(); content::SiteInstance* site_instance = pm->GetSiteInstanceForURL(url); ExtensionViewHost* host = #if defined(OS_MACOSX) new ExtensionViewHostMac(extension, site_instance, url, view_type); #else new ExtensionViewHost(extension, site_instance, url, view_type); #endif host->CreateView(browser); return host; }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_view_host_factory.cc中。
從這裡可以看到,在非Mac OS X平台上,函數CreateViewHostForExtension會創建一個ExtensionViewHost對象。這個ExtensionViewHost對象的創建過程,也就是ExtensionViewHost的構造函數的實現,如下所示:
ExtensionViewHost::ExtensionViewHost( const Extension* extension, content::SiteInstance* site_instance, const GURL& url, ViewType host_type) : ExtensionHost(extension, site_instance, url, host_type), ...... { ...... }這個函數定義在文件external/chromium_org/chrome/browser/extensions/extension_view_host.cc中。
ExtensionViewHost類是從ExtensionHost類繼承下來的。因此,ExtensionViewHost的構造函數會調用父類ExtensionHost的構造函數,用來執行初始化工作。前面我們在分析Extension的Background Page的加載過程時,已經分析過ExtensionHost類的構造函數了。它將會創建一個WebContents對象。有了這個WebContents對象之後,以後就可以加載這裡的參數url描述的一個Popup Page了。
這樣,我們就分析完成Extension的Popup Page的加載過程了。從分析的過程就可以看出,Extension的Popup Page與Background Page都具有自己的URL。URL的形式為chrome-extension://[extension_id]/xxx.html。這些URL都是通過Chromium的Content層向外提供的API接口WebContents在一個Extension Process中加載的。
與此同時,普通網頁的URL也是通過Chromium的Content層向外提供的API接口WebContents在一個Render Process中加載的。Extension Process和Render Process的概念是一樣的,都是用來加載、解析和渲染網頁的。從這個角度看,Extension Page的加載、解析和渲染與一般的Web Page並無異。
至此,我們就以Background Page和Popup Page為例,分析了Extension的Page加載過程。Extension由Page和Content Script組成。在接下來一篇文章中,我們將繼續分析Extension的Content Script的加載過程。這樣我們就更加完整地理解Extension的實現原理了。
本文實例講述了Android編程之View簡單學習示例。分享給大家供大家參考,具體如下:View,是Android的一個超類,這個類幾乎包含了所有的屏幕類型。每一個Vie
在網易數據酷的中看到一幅圖,非常有特色,因為最近用Canvas繪了不少圖表,就想用代碼把這幅圖也繪出來。 基本也繪出來了,效果圖如下: 繪制這張圖,a
一、前言上篇說清楚了Unity和Android調用的方式,但很多實際接入的部分沒有講的很詳細,因為重頭在這篇,會詳細講述具體接入Android SDK的方式,和怎麼去做一
我仍然從實際工作中出發!最近需要在照相機裡面添加聲控拍照功能(語音拍照),在設置當中需要實現如下圖的效果: 其設置的語音拍照菜單功能描述如下: (1)當點擊語音拍照菜單