Chrome的WebUI是那种,在Chrome中输入 "chrome://xxxx"就能打开一个URL页面的对象。

创建一个Chrome WebUI接口非常的简单,只需要改动数个文件。

创建WebUI页面

webui的资源,放在资源目录下:src/chrome/browser/resources. 当创建WebUI资源时,参考​​Web Development Style Guide​​。例如,我们创建一个HelloWorld的页面

src/chrome/browser/resources/hello_world.html

 





<!DOCTYPE HTML>​

​<html i18n-values="dir:textdirection">​

​<head>​

​ <meta charset="utf-8">​

​ <title i18n-content="helloWorldTitle"></title>​

​ <link rel="stylesheet" href="hello_world.css">​

<script src="chrome://resources/js/cr.js"></script>


<script src="chrome://resources/js/load_time_data.js"></script>


<script src="chrome://resources/js/util.js"></script>


 


​ <script src="strings.js"></script>​


​ <script src="hello_world.js"></script>​


</head>


 


 


 


<body i18n-values=".style.fontFamily:fontfamily;.style.fontSize:fontsize">

​  <h1 i18n-content="helloWorldTitle"></h1>


​  <p id="welcome-message"></p>


<script src="chrome://resources/js/i18n_template2.js"></script>


​</body>​


 


​</html>​


src/chrome/browser/resources/hello_world.css:


 



​p {​


​  white-space: pre-wrap;​


​}​


 

src/chrome/browser/resources/hello_world.js:


 



​cr.define('hello_world', function() {​


​  'use strict';​



​  /**​


​   * Be polite and insert translated hello world strings for the user on loading.​


​   */​


​  function initialize() {​


    $('welcome-message').textContent = loadTimeData.getStringF('welcomeMessage',


        loadTimeData.getString('userName'));

​  }​




​  // Return an object with all of the exports.​


​  return {​


​    initialize: initialize,​


​  };​


​});​



​document.addEventListener('DOMContentLoaded', hello_world.initialize);​

资源信息应该添加到Chrome使用的 src/chrome/browser/browser_resources.grd文件中。


src/chrome/browser/browser_resources.grd:


 



​+ <include name="IDR_HELLO_WORLD_HTML" file="resources\hello_world.html" type="BINDATA" />​


​+ <include name="IDR_HELLO_WORLD_CSS" file="resources\hello_world.css" type="BINDATA" />​


​+ <include name="IDR_HELLO_WORLD_JS" file="resources\hello_world.js" type="BINDATA" />​



添加URL标识到新的Chrome URL中


URL标识被保存在 src/chrome/common/url_constants.*文件中。



src/chrome/common/url_constants.h:


 



​+ extern const char kChromeUIHelloWorldURL[];​


​...​


​+ extern const char kChromeUIHelloWorldHost[];​


src/chrome/common/url_constants.cc:


 



​+ const char kChromeUIHelloWorldURL[] = "chrome://hello-world/";​


​...​


​+ const char kChromeUIHelloWorldHost[] = "hello-world";​



添加本地字符串

我们需要为新的资源添加新的本地化字符串。比如一个欢迎信息




src/chrome/app/generated_resources.grd:


 



​+ <message name="IDS_HELLO_WORLD_TITLE" desc="A happy message saying hello to the world">​


​+   Hello World!​


​+ </message>​

​+ <message name="IDS_HELLO_WORLD_WELCOME_TEXT" desc="Message welcoming the user to the hello world page">​


​+   Welcome to this fancy Hello World page <ph name="WELCOME_NAME">$1<ex>Chromium User</ex></ph>!​


​+ </message>​

添加处理chrome://hello-world/请求的WebUI类


下面我们增加一个新的类来处理新的资源。通常情况下,它是ChromeWebUI的一个子类(WebUI对话框则从HtmlDialogUI继承)

 

 



src/chrome/browser/ui/webui/hello_world_ui.h:


 



​#ifndef CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_UI_H_​


​#define ​​​​CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_UI_H_​


​#pragma once​



​#include "content/public/browser/web_ui_controller.h"​



​// The WebUI for chrome://hello-world​


​class HelloWorldUI : public content::WebUIController {​


​ public:​


​  explicit HelloWorldUI(content::WebUI* web_ui);​


​  virtual ~HelloWorldUI();​


 private:  


​  DISALLOW_COPY_AND_ASSIGN(HelloWorldUI);​


​};​



​#endif  // ​​​​CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_UI_H_​

src/chrome/browser/ui/webui/hello_world_ui.cc:


 


 



​#include "chrome/browser/ui/webui/hello_world_ui.h"​




​#include "chrome/browser/profiles/profile.h"​


#include "chrome/common/url_constants.h"


#include "content/public/browser/web_ui_data_source.h"

#include "grit/browser_resources.h"


​#include "grit/generated_resources.h"​


​HelloWorldUI::HelloWorldUI(content::WebUI* web_ui)​


​    : content::WebUIController(web_ui) {​


​  // Set up the chrome://hello-world source.​


content::WebUIDataSource * html_source =


​    new ​​ content::WebUIDataSource (chrome::kChromeUIHelloWorldHost);


​  html_source->​​ SetUseJsonJSFormatV2() ;



​  // Localized strings.​


​  html_source->AddLocalizedString("helloWorldTitle", IDS_HELLO_WORLD_TITLE);​


​  html_source->AddLocalizedString("welcomeMessage", IDS_HELLO_WORLD_WELCOME_TEXT);​




​  // As a demonstration of passing a variable for JS to use we pass in the name "Bob".​


​  html_source->AddString("userName", "Bob");​


​  html_source->​​ SetJsonPath ("strings.js");



​  // Add required resources.​


​  html_source->​​ AddResourcePath ("hello_world.css", IDR_HELLO_WORLD_CSS);


​  html_source->​​ AddResourcePath ("hello_world.js", IDR_HELLO_WORLD_JS);


​  html_source->​​ SetDefaultResource (IDR_HELLO_WORLD_HTML);




​  Profile* profile = Profile::FromWebUI(web_ui);​


​  content::WebUIDataSource::Add(profile, html_source);​

​}​



​HelloWorldUI::~HelloWorldUI() {​


​}​



 

 

编译新的类,需要添加到工程的gyp文件中

 


src/chrome/chrome_browser_ui.gypi:


 



​'sources': [​


​...​


​+   'browser/ui/webui/hello_world_ui.cc',​


​+   'browser/ui/webui/hello_world_ui.h',​



 

 

添加WebUI请求到Chrome WebUI工厂

WebUI的工厂负责响应并创建你的请求

 


src/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc:


 



​+ #include "chrome/browser/ui/webui/hello_world_ui.h"​


...


​+ if (url.host() == chrome::kChromeUIHelloWorldHost)​


​+   return &NewWebUI<HelloWorldUI>;​



 

 

测试

OK!假定没有错误,你可以编译和运行chrome了。并在地址栏输入 chrome:://hello-world/ 你将看到欢迎信息。


增加回调处理句柄

你也许你问新的WebUI页面能够做些什么事情,或者从C++世界获取一些信息。为此,我们使用消息回调句柄。 假设我们不信任javascript引擎的两个整数相加(因为我们知道,它内部是使用浮点数的)。我们可以增加回调句柄来处理我们的整数运算。


 


src/chrome/browser/ui/webui/hello_world_ui.h:



 



​#include "chrome/browser/ui/webui/chrome_web_ui.h"​


​+​


​+ namespace base {​


+   class ListValue;


​+ }  // namespace base​




// The WebUI for chrome://hello-world


​...​



​    // Set up the chrome://hello-world source.​


​    ChromeWebUIDataSource* html_source =​


​    new ChromeWebUIDataSource(chrome::kChromeUIHelloWorldHost);​


​+​


​+   // Register callback handler.​


​+   RegisterMessageCallback("addNumbers",​



+       base::Bind(&HelloWorldUI::AddNumbers,


+                  base::Unretained(this)));


​    // Localized strings.​

​...​

​    virtual ~HelloWorldUI();​


​+​


​+  private:​


​+   // Add two numbers together using integer arithmetic.​


​+   void AddNumbers(const base::ListValue* args);​




​    DISALLOW_COPY_AND_ASSIGN(HelloWorldUI);​


​  };​



src/chrome/browser/ui/webui/hello_world_ui.cc:



 



​  #include "chrome/browser/ui/webui/hello_world_ui.h"​


​+​


​+ #include "base/values.h"​



​  #include "chrome/browser/profiles/profile.h"​


​...​


  HelloWorldUI::~HelloWorldUI() {

​  }​


​+​


​+ void HelloWorldUI::AddNumbers(const base::ListValue* args) {​


​+   int term1, term2;​


​+   if (!args->GetInteger(0, &term1) || !args->GetInteger(1, &term2))​


​+     return;​


​+   base::FundamentalValue result(term1 + term2);​


​+   CallJavascriptFunction("hello_world.addResult", result);​


​+ }​


src/chrome/browser/resources/hello_world.js:



 



​    function initialize() {​


​+     chrome.send('addNumbers', [2, 2]);​


​    }​


​+​


​+   function addResult(result) {​


​+     alert('The result of our C++ arithmetic: 2 + 2 = ' + result);​


​+   }​



​    return {​


​+     addResult: addResult,​


​      initialize: initialize,​


​    };​



请注意调用是异步的。我们必须等待C++端主带调用javascript的函数才能获取到结果。

 

创建WebUI对话框

一旦你按照上面的步骤创建了一个WebUI,你需要修改两个地方来创建一个WebUI Dialog。你必须从HtmlDialogUI继承,并创建一个HtmlDialogUIDelegate类。


1. 替换ChromeWebUI为HtmlDialogUIDelegate

 


src/chrome/browser/ui/webui/hello_world_ui.h:



 


 



​- #include "#chrome/browser/ui/webui/chrome_web_ui.h"​


​+ #include "#chrome/browser/ui/webui/html_dialog_ui.h"​




​- class HelloWorldUI : public ChromeWebUI {​


​+ class HelloWorldUI : public HtmlDialogUI {​



 


 

 

2. 创建一个HtmlDialogUIDelegage

 


src/chrome/browser/ui/webui/hello_world.h



 



​#ifndef CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_H_​


​#define ​​ CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_H_


#pragma once



​#include "chrome/browser/ui/webui/html_dialog_ui.h"​




​class HelloWorldDialog : private HtmlDialogUIDelegate {​


​ public:​


​  // Shows the Hello World dialog.​


​  static void ShowDialog(​​​​);​


​  virtual ~HelloWorldDialog();​



​ private:​


​  // Construct a Hello World dialog​


​  explicit HelloWorldDialog(​​​​);​



​  // Overridden from HtmlDialogUI::Delegate:​


​  virtual bool IsDialogModal() const OVERRIDE;​


​  virtual string16 GetDialogTitle() const OVERRIDE;​


​  virtual GURL GetDialogContentURL() const OVERRIDE;​


​  virtual void GetWebUIMessageHandlers(​


​      std::vector<WebUIMessageHandler*>* handlers) const OVERRIDE;​


​  virtual void GetDialogSize(gfx::Size* size) const OVERRIDE;​


​  virtual std::string GetDialogArgs() const OVERRIDE;​


​  virtual void OnDialogClosed(const std::string& json_retval) OVERRIDE;​


​  virtual void OnCloseContents(​


​      TabContents* source, bool* out_close_dialog) OVERRIDE;​


​  virtual bool ShouldShowDialogTitle() const OVERRIDE;​



​  DISALLOW_COPY_AND_ASSIGN(HelloWorldDialog);​


​};​




​#endif  // ​​ CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_H_


src/chrome/browser/ui/webui/hello_world.cc


 



#include "base/utf_string_conversions.h"


#include "chrome/browser/ui/browser.h"

#include "chrome/browser/ui/browser_list.h"

​#include "chrome/browser/ui/webui/hello_world.h"​


​#include "chrome/common/url_constants.h"​



​void HelloWorldDialog::ShowDialog() {​


​  Browser* browser = BrowserList::GetLastActive();​


​  DCHECK(browser);​


​  browser->BrowserShowHtmlDialog(new HelloWorldDialog(), NULL);​


​}​



​HelloWorldDialog::HelloWorldDialog() {​


​}​



​HelloWorldDialog::~HelloWorldDialog() {​


​}​



​bool HelloWorldDialog::IsDialogModal() {​


​  return false;​


​}​



​string16 HelloWorldDialog::GetDialogTitle() {​


​  return UTF8ToUTF16("Hello World");​


​}​



​GURL HelloWorldDialog::GetDialogContentURL() const {​


​  return GURL(chrome::kChromeUIHelloWorldURL);​


​}​



​void HelloWorldDialog::GetWebUIMessageHandlers(​


​    std::vector<WebUIMessageHandler*>* handlers) const {​


​}​



​void HelloWorldDialog::GetDialogSize(gfx::Size* size) const {​


​  size->SetSize(600, 400);​


​}​



​std::string HelloWorldDialog::GetDialogArgs() const {​


​  return std::string();​


​}​



​void HelloWorldDialog::OnDialogClosed(const std::string& json_retval) {​


​  delete this;​


​}​



​void HelloWorldDialog::OnCloseContents(TabContents* source,​


​    bool* out_close_dialog) {​


​  if (out_close_dialog)​


​    *out_close_dialog = true;​


​}​



​bool HelloWorldDialog::ShouldShowDialogTitle() const {​


​  return true;​


​}​



你需要通过HelloWroldDialog::ShowDialog来创建一个新的dialog。

 


传递参数给WebUI

你可能猜到HtmlDialogUIDelegate::GetDialogArgs()函数是用来传递参数给对话框页的。例如,如果我们希望显示一个自定义的消息给用户,这个自定义消息是在创建对话框时传递给它,并由GetDialogArgs返回,并在javascript中通过chrome.dialogArguments来返回。例子如下:

 


src/chrome/browser/ui/webui/hello_world.h



 



​-   static void ShowDialog(​​​​);​


​+   static void ShowDialog(std::string message​​​​);​




​+   // The message to be displayed to the user.​


​+   std::string message_;​


​+​



​    DISALLOW_COPY_AND_ASSIGN(HelloWorldDialog);​


​  };​


src/chrome/browser/ui/webui/hello_world.cc


 



​- HelloWorldDialog::HelloWorldDialog() {​


+ HelloWorldDialog::HelloWorldDialog(std::string message)



​+     : message_(message) {​


​  }​


  std::string HelloWorldDialog::GetDialogArgs() const {


​-   return std::string();​


​+   return message_;​


​  }​



src/chrome/browser/resources/hello_world.js:


 



    function initialize() {


​+     document.getElementsByTagName('p')[0].textContent = chrome.dialogArguments;​


​    }​



 

 

实际上,你可以传递一个结构体给你的WebUI。你可以通过base::JSONWriter来产生一个JSON字符串,在javascript端通过JSON.parse(chrome.dialogArguments)获得这个参数。

例子待序.....