Chromium 中的 WebUI

news2025/1/13 23:49:06

这段时间在基于 Chromium 做浏览器的定制工作,少不了需要修改 Chromium 的 UI。Chromium 中的 UI 主要有两大部分组成,一部分是原生 UI,也就是使用 C++ 等语言,利用操作系统原生 UI 框架开发的界面,另一部分则是采用 Web 技术开发的界面,称之为 WebUI。

WebUI 开发起来比较麻烦,因为涉及到与 C++ 代码的交互,让前端开发人员开发,需要安装 Chromium 的编译环境,而且 WebUI 使用了 Chromium 特有的框架,和前端开发人员的技术栈并不同,没法直接交给前端开发人员。如果让 C++ 开发人员开发,有需要懂前端开发。也不知道谷歌为啥整出这么个东西,感觉挺麻烦的。

这与我之前在项目中用的 H5 UI 开发方案有所不同。尽管 H5 UI 开发也涉及到与 C++ 代码的交互,但交互主要限于业务逻辑层面。界面的开发完全由前端负责,C++ 代码只负责通过 JS 和 C++ 之间的交互提供数据。

那什么是 Chromium WebUI 呢?

在 Chromium 中,WebUI(Web User Interface)是一个用于构建 Web 应用界面(UI)的框架,广泛应用于浏览器的设置界面、扩展管理、历史记录等功能。这些界面通常由 HTML、CSS 和 JavaScript 编写,并且需要与 Chromium 内部的 C++ 代码进行交互。WebUI 使得开发者能够通过 Web 技术来构建复杂的 UI,同时保持与 Chromium 内部系统的高效通信。

WebUI 和 Web 页面的不同

WebUI 比 Web 页面的权限更高,以便管理Chrome浏览器本身。例如,要实现设置界面,必须访问许多隐私和安全敏感的服务,普通 Web 页面并不允许访问这些服务。

WebUI 通常使用特定的 URL,可以通过安全子系统的检查:

  • 允许渲染器加载 chrome:// 开头的URL,访问浏览器的内部资源(如 chrome://resources/ )。

  • 允许浏览器通过 CallJavascriptFunction() 在渲染器中执行任意 JavaScript 代码。

  • 允许通过 chrome.send() 等方法在渲染器和浏览器之间进行通信。

  • 在显示图片或执行 JavaScript 时忽略安全设置。

WebUI 的架构

WebUI 的架构可分为以下几个主要部分:

  • WebUI 页面:每个 WebUI 页面都是一个典型的 Web 应用页面,包含 HTML、CSS 和 JavaScript。通常通过浏览器的 chrome://URL 可以访问这些页面,如 chrome://settings 。

  • C++ 后端:Chromium 的 C++ 代码提供 WebUI 页面所需的业务逻辑和数据支持。C++ 后端负责通过 IPC(进程间通信)机制与 Web 页面进行交互,并处理各种浏览器内部功能(如设置、网络请求等)。

  • UI 组件库:WebUI 提供了一套封装良好的 UI 组件库,如按钮、复选框、输入框等,这些组件与浏览器的 UI 风格高度一致,并且能够快速构建可交互的页面。

WebUI 代码结构

WebUI 页面主要由以下部分组成:

  • WebUI 页面资源: 这些资源存放在 chrome/browser/resources 目录下。

  • C++ 控制器: 与 WebUI 页面交互的 C++ 代码,位于 chrome/browser/ui/webui/

创建 WebUI 页面

1. 创建文件夹结构

我们首先需要在 chrome/browser/resources 和 chrome/browser/ui/webui 中为新页面创建文件夹。比如,为了创建一个名为 "hello_world" 的页面,我们在这两个目录下分别创建 hello_world 文件夹。

2. 编写 WebUI 页面代码

我们将通过一组文件来创建一个简单的 WebUI 页面。

chrome/browser/resources/hello_world/hello_world.html

<!DOCTYPE HTML>
<html>
  <meta charset="utf-8">
  <link rel="stylesheet" href="hello_world.css">
  <hello-world-app></hello-world-app>

  <script type="module" src="app.js"></script>

</html>

chrome/browser/resources/hello_world/hello_world.css

body {
  margin: 0;
}

chrome/browser/resources/hello_world/app.css

#example-div {
  color: blue;
}

chrome/browser/resources/hello_world/app.html.ts

import { html } from '//resources/lit/v3_0/lit.rollup.js';
import type { HelloWorldAppElement } from './app.js';

export function getHtml(this: HelloWorldAppElement) {
  return html`
    <h1>Hello World</h1>

    <div id="example-div">${this.message_}</div>

  `;
}

chrome/browser/resources/hello_world/app.ts

import './strings.m.js';
import { loadTimeData } from'chrome://resources/js/load_time_data.js';
import { CrLitElement } from'//resources/lit/v3_0/lit.rollup.js';
import { getCss } from'./app.css.js';
import { getHtml } from'./app.html.js';

exportclass HelloWorldAppElement extends CrLitElement {
staticget is() {
    return'hello-world-app';
  }

static override get styles() {
    return getCss();
  }

  override render() {
    return getHtml.bind(this)();
  }

static override get properties() {
    return {
      message_: { String },
    };
  }

protected message_: string = loadTimeData.getString('message');
}

customElements.define(HelloWorldAppElement.is, HelloWorldAppElement);

3. 配置构建文件

为了正确编译 TypeScript 并生成 JavaScript 文件,我们需要添加一个 BUILD.gn 文件。

chrome/browser/resources/hello_world/BUILD.gn

import("//ui/webui/resources/tools/build_webui.gni")

build_webui("build") {
  grd_prefix = "hello_world"

  static_files = [ "hello_world.html", "hello_world.css" ]
  non_web_component_files = [ "app.ts", "app.html.ts" ]
  css_files = [ "app.css" ]

  ts_deps = [
    "//third_party/lit/v3_0:build_ts",
    "//ui/webui/resources/js:build_ts",
  ]
}

4. 将 WebUI 页面资源添加到项目中

为了将新创建的 WebUI 页面资源添加到构建配置中,我们需要更新以下文件。

更新 chrome/browser/resources/BUILD.gn

group("resources") {
  public_deps += [
    "hello_world:resources"
  ]
}

更新 tools/gritsettings/resource_ids.spec

# START chrome/ WebUI resources section
"<(SHARED_INTERMEDIATE_DIR)/chrome/browser/resources/hello_world/resources.grd": {
  "META": {"sizes": {"includes": [5]}},
  "includes": [2085],
}

更新 chrome/chrome_paks.gni

template("chrome_extra_paks") {
  sources += [
    "$root_gen_dir/chrome/hello_world_resources.pak",
  ]
  deps += [
    "//chrome/browser/resources/hello_world:resources",
  ]
}

添加 C++ 处理请求的 WebUI 类

在 C++ 中,我们需要创建一个 WebUI 控制器类来处理对新页面(chrome://hello-world/)的请求。这个类通常会继承自 WebUIController

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

#ifndef CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_
#define CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_

#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);
  ~HelloWorldUI() override;
};

#endif  // CHROME_BROWSER_UI_WEBUI_HELLO_WORLD_HELLO_WORLD_H_

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

#include "chrome/browser/ui/webui/hello_world/hello_world_ui.h"
#include "chrome/common/webui_url_constants.h"
#include "content/public/browser/web_ui_data_source.h"

HelloWorldUI::HelloWorldUI(content::WebUI* web_ui)
    : content::WebUIController(web_ui) {
  content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd(
      web_ui->GetWebContents()->GetBrowserContext(),
      chrome::kChromeUIHelloWorldHost);

// 添加必要的资源
  webui::SetupWebUIDataSource(
      source,
      base::make_span(kHelloWorldResources, kHelloWorldResourcesSize),
      IDR_HELLO_WORLD_HELLO_WORLD_HTML);

  source->AddString("message", "Hello World!");
}

HelloWorldUI::~HelloWorldUI() = default;

更新 chrome/browser/ui/BUILD.gn

static_library("ui") {
  sources = [
    "webui/hello_world/hello_world_ui.cc",
    "webui/hello_world/hello_world_ui.h",
  ]
}

注册 URL 常量

我们需要为新的 WebUI 页面注册 URL 常量,以便浏览器能够识别。

chrome/common/webui_url_constants.cc

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

chrome/common/webui_url_constants.h

extern const char kChromeUIHelloWorldURL[];
extern const char kChromeUIHelloWorldHost[];

完成所有配置后,您可以编译并运行 Chromium,然后访问 chrome://hello-world/ 查看页面。如果一切顺利,您应该能看到 "Hello World!" 消息。

小结

上面的例子只是一些关键代码,并非一个完整的例子,有兴趣的朋友可以看看 chromium 源码中的例子。即使这样,看了上面的内容,大家是不是也觉得,创建一个简单的 WebUI 页面其实并不轻松?尤其是如果你深入研究 Chromium 中设置页面的源码,你会发现,这一切变得更加复杂。因为这些页面不仅仅是简单的 HTML 和 CSS,它们混合了 Web Components 和 Polymer 框架,这使得修改和定制变得异常痛苦。每次想要改动一处小细节,往往需要对多个技术栈、不同的框架和抽象层次进行深入理解。

事实上,这种复杂性几乎逼迫每个程序员都必须成为“六边形战士”,不仅要熟悉 C++ 编程,还要理解前端技术、框架以及如何在它们之间实现无缝衔接。为了搞定 WebUI,我不得不硬着头皮去学习前端相关的知识。这对我来说,本是一个前端开发者的领域,却因为 Chromium 的特殊需求,让我这个 C++ 程序员也必须在前端的海洋中挣扎一番。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2276206.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成原理(1)

系统概述 计算机硬件基本组成早期冯诺依曼机现代计算机 计算机各部分工作原理主存储器运算器控制器计算机工作过程 此文章的图片资源获取来自于王道考研 计算机硬件基本组成 早期冯诺依曼机 存储程序是指将指令以二进制的形式事先输入到计算机的主存储器&#xff0c;然后按照…

基于element UI el-dropdown打造表格操作列的“更多⌵”上下文关联菜单

<template><div :class"$options.name"><el-table :data"tableData"><el-table-column type"index" label"序号" width"60" /><!-- 主要列 BEGIN---------------------------------------- --&g…

Oracle 表分区简介

目录 一. 前置知识1.1 什么是表分区1.2 表分区的优势1.3 表分区的使用条件 二. 表分区的方法2.1 范围分区&#xff08;Range Partitioning&#xff09;2.2 列表分区&#xff08;List Partitioning&#xff09;2.3 哈希分区&#xff08;Hash Partitioning&#xff09;2.4 复合分…

罗永浩再创业,这次盯上了 AI?

罗永浩&#xff0c;1972年7月9日生于中国延边朝鲜族自治州的一个军人家庭&#xff0c;是一名朝鲜族人&#xff1b;早年在新东方授课&#xff0c;2004年当选 “网络十大红人” &#xff1b;2006年8月1日&#xff0c;罗永浩创办牛博网&#xff1b;2008年5月&#xff0c;罗永浩注册…

自然语言处理基础:全面概述

自然语言处理基础&#xff1a;全面概述 什么是NLP及其重要性、NLP的核心组件、NLU与NLG、NLU与NLG的集成、NLP的挑战以及NLP的未来 自然语言处理&#xff08;NLP&#xff09;是人工智能&#xff08;AI&#xff09;中最引人入胜且具有影响力的领域之一。它驱动着我们日常使用的…

WPF系列八:图形控件Path

简介 Path控件支持一种称为路径迷你语言&#xff08;Path Mini-Language&#xff09;的紧凑字符串格式&#xff0c;用于描述复杂的几何图形。这种语言通过一系列命令字母和坐标来定义路径上的点和线段&#xff0c;最终绘制出想要的图形。 绘制任意形状&#xff1a;可以用来绘…

计算机图形学【绘制立方体和正六边形】

工具介绍 OpenGL&#xff1a;一个跨语言的图形API&#xff0c;用于渲染2D和3D图形。它提供了绘制图形所需的底层功能。 GLUT&#xff1a;OpenGL的一个工具库&#xff0c;简化了窗口创建、输入处理和其他与图形环境相关的任务。 使用的函数 1. glClear(GL_COLOR_BUFFER_BIT |…

有限元分析学习——Anasys Workbanch第一阶段笔记(10)桌子载荷案例分析_实际载荷与均布载荷的对比

目录 0 序言 1 桌子案例 2 模型简化 3 方案A 前处理 1&#xff09;分析类型选择 2&#xff09;材料加载 3&#xff09;约束、载荷及接触 4&#xff09;控制网格(网格大小需要根据结果不断调整) 初始计算结果 加密后计算结果 4 方案B、C 前处理 1&#xff09;分析…

Docker compose 使用 --force-recreate --no-recreate 控制重启容器时的行为【后续】

前情&#xff1a;上一篇实际是让AI工具帮我总结了一下讨论的内容&#xff0c;这里把讨论的过程贴出来&#xff0c;这个讨论是为解决实际问题 前文https://blog.csdn.net/wgdzg/article/details/145039446 问题说明&#xff1a; 我使用 docker compose 管理我的容器&#xff0…

Mysql--基础篇--多表查询(JOIN,笛卡尔积)

在MySQL中&#xff0c;多表查询&#xff08;也称为联表查询或JOIN操作&#xff09;是数据库操作中非常常见的需求。通过多表查询&#xff0c;你可以从多个表中获取相关数据&#xff0c;并根据一定的条件将它们组合在一起。MySQL支持多种类型的JOIN操作&#xff0c;每种JOIN都有…

postgresql|数据库|利用sqlparse和psycopg2库批量按顺序执行SQL语句(psyconpg2新优化版本)

一、 旧版批量执行SQL脚本的python文件缺点&#xff0c;优点&#xff0c;以及更新内容 书接上回&#xff0c;postgresql|数据库开发|python的psycopg2库按指定顺序批量执行SQL文件(可离线化部署)_python sql psycopg2-CSDN博客 这个python脚本写了很久了&#xff0c;最近开始…

5个不同类型的数据库安装

各种社区版本下载官方地址&#xff1a;MySQL :: MySQL Community Downloads 一、在线YUM仓库&#xff08;Linux&#xff09; 选择 MySQL Yum Repository 选择对应版本下载仓库安装包&#xff08;No thanks, just start my download.&#xff09; 下载方法1&#xff1a;下载到本…

shell基础使用及vim的常用快捷键

一、shell简介 参考博文1 参考博文2——shell语法及应用 参考博文3——vi的使用 在linux中有很多类型的shell&#xff0c;不同的shell具备不同的功能&#xff0c;shell还决定了脚本中函数的语法&#xff0c;Linux中默认的shell是 / b in/ b a s h &#xff0c;流行的shell…

Spring Data Elasticsearch简介

一、Spring Data Elasticsearch简介 1 SpringData ElasticSearch简介 Elasticsearch是一个实时的分布式搜索和分析引擎。它底层封装了Lucene框架,可以提供分布式多用户的全文搜索服务。 Spring Data ElasticSearch是SpringData技术对ElasticSearch原生API封装之后的产物,它通…

【巨实用】Git客户端基本操作

本文主要分享Git的一些基本常规操作&#xff0c;手把手教你如何配置~ ● 一个文件夹中初始化Git git init ● 为了方便以后提交代码需要对git进行配置&#xff08;第一次使用或者需求变更的时候&#xff09;&#xff0c;告诉git未来是谁在提交代码 git config --global user.na…

有收到腾讯委托律师事务所向AppStore投诉带有【水印相机】主标题名称App的开发者吗

近期&#xff0c;有多名开发者反馈&#xff0c;收到来自腾讯科技 (深圳) 有限公司委托北京的一家**诚律师事务所卞&#xff0c;写给AppStore的投诉邮件。 邮件内容主要说的是&#xff0c;腾讯注册了【水印相机】这四个字的商标&#xff0c;所以你们这些在AppStore上的app&…

导出文件,能够导出但是文件打不开

背景&#xff1a; 在项目开发中&#xff0c;对于列表的查询&#xff0c;而后会有导出功能&#xff0c;这里导出的是一个excell表格。实现了两种&#xff0c;1.导出的文件&#xff0c;命名是前端传输过去的&#xff1b;2.导出的文件&#xff0c;命名是根据后端返回的文件名获取的…

Redis 源码分析-内部数据结构 dict

Redis 源码分析-内部数据结构 dict 在上一篇 Redis 数据库源码分析 提到了 Redis 其实用了全局的 hash 表来存储所有的键值对&#xff0c;即下方图示的 dict&#xff0c;dict 中有两个数组&#xff0c;其中 ht[1] 只在 rehash 时候才真正用到&#xff0c;平时都是指向 null&am…

010:传统计算机视觉之大津算法初探

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 上一节学习了利用 Canny 算法来完成一个图片的边缘检测&#xff0c;从而可以区分出图像的边缘。 本节再了解一个计算机视觉中更常见的应用&#xff0c;那就是把图片的前景和…

使用Cilium/eBPF实现大规模云原生网络和安全

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 目录 抽象 1 Trip.com 云基础设施 1.1 分层架构 1.2 更多细节 2 纤毛在 Trip.com 2.1 推出时间表 2.2 自定义 2.3 优化和调整 2.3.1 解耦安装 2.3.2 避免重试/重启风暴 2.3.3 稳定性优先 2…