Chrome浏览器插件经常以CRX文件出现,但真正开发一个插件时,并不是直接编辑CRX。开发者通常先建立一个普通文件夹,在里面放入manifest.json、JavaScript、HTML、CSS和图标等文件,完成调试后再打包或提交到Chrome应用商店。

因此,要理解Chrome插件制作,可以先把它分成两层:一层是插件本身的源码目录结构,另一层才是用于签名和分发的CRX安装包。

Chrome扩展程序如何打包成CRX?开发流程介绍

CRX是什么

CRX是Chrome Extension的打包文件格式之一。已经打包的Chrome扩展通常表现为一个.crx文件,而开发阶段常见的则是一个“未打包扩展程序”目录。

两者可以简单理解为:

开发阶段:

my-extension/
├── manifest.json
├── popup.html
├── popup.js
├── service-worker.js
└── icons/

        ↓ 打包、签名

my-extension.crx

CRX并不是单纯把文件夹后缀改成.crx。当前CRX3格式在文件前部包含版本、签名和公钥证明等头部数据,后面才是扩展文件的ZIP归档内容。

从Chromium公开的CRX3格式定义来看,其结构大致可以理解为:

CRX3文件
├── Magic Number:Cr24
├── CRX格式版本:3
├── Header长度
├── CrxFileHeader
│   ├── 签名信息
│   └── 公钥证明等数据
└── ZIP归档
    ├── manifest.json
    ├── JavaScript
    ├── HTML
    ├── CSS
    └── 图片等资源

所以,CRX更准确地说是“带有签名信息的Chrome扩展安装包”。

插件目录长什么样

一个实际Chrome扩展的目录可以很简单,也可以包含很多模块。例如:

my-extension/
├── manifest.json
├── service-worker.js
├── content.js
├── popup/
│   ├── popup.html
│   ├── popup.css
│   └── popup.js
├── options/
│   ├── options.html
│   └── options.js
└── icons/
    ├── icon16.png
    ├── icon48.png
    └── icon128.png

并不是每个插件都需要这些文件。真正必不可少的是根目录中的manifest.json,其他文件是否存在取决于插件功能。

manifest.json是核心

manifest.json相当于Chrome插件的配置清单。浏览器通过它判断插件叫什么、版本是多少、需要哪些权限、运行哪些脚本,以及点击工具栏图标后应该打开什么界面。

当前Chrome扩展平台使用Manifest V3,新开发插件通常应该使用:

{
  "manifest_version": 3,
  "name": "我的Chrome插件",
  "version": "1.0.0",
  "description": "一个简单的Chrome扩展示例"
}

其中最基础的字段包括:

  • manifest_version:扩展清单规范版本;

  • name:插件名称;

  • version:插件版本号;

  • description:插件功能说明。

随着功能增加,还会使用permissionshost_permissionsbackgroundcontent_scriptsaction等配置。

几个常见组成部分

Popup弹窗

点击浏览器工具栏中的插件图标后出现的小窗口,一般由HTML、CSS和JavaScript组成。

"action": {
  "default_popup": "popup/popup.html"
}

密码生成器、二维码工具、网页辅助工具等插件,经常把主要操作界面放在Popup中。

Content Script

Content Script用于在指定网页中运行代码,可以读取或修改当前页面DOM。

例如:

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content.js"]
  }
]

网页翻译、元素修改、广告隐藏、页面增强等功能,通常都会涉及Content Script。

它虽然运行在网页环境附近,但默认处于扩展的隔离执行环境,与网页自己的JavaScript并不是完全相同的上下文。

Service Worker

Manifest V3使用扩展Service Worker承担后台事件处理工作。

"background": {
  "service_worker": "service-worker.js"
}

它可以监听插件安装、标签页变化、消息通信和浏览器API事件。

与早期Manifest V2长期运行的Background Page不同,Service Worker会在需要时启动,空闲后可能被停止,因此不能依赖全局变量长期保存状态。

Options页面

配置比较多的插件可以提供独立设置页,例如保存API Key、网站规则、主题和功能开关。

"options_page": "options/options.html"

权限怎么理解

Chrome插件并不是默认可以读取所有网页和浏览器数据。需要使用敏感能力时,应在manifest.json中声明相应权限。

例如:

{
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "https://example.com/*"
  ]
}

permissions主要声明浏览器API能力,host_permissions则用于声明插件需要访问哪些网站。

常见权限包括:

  • storage:保存插件配置;

  • activeTab:临时访问当前活动标签页;

  • scripting:向网页执行脚本;

  • tabs:使用部分标签页相关能力;

  • contextMenus:添加右键菜单。

权限不是越多越方便。权限范围过大不仅会增加安全风险,也可能在安装时向用户显示更敏感的权限提示。开发插件时通常应该按照实际功能申请最小权限。

做一个最简单的插件

下面可以制作一个简单示例:点击插件按钮后,把当前网页背景改成浅黄色。

建立目录:

page-color/
├── manifest.json
├── popup.html
└── popup.js

manifest.json

{
  "manifest_version": 3,
  "name": "页面背景修改器",
  "version": "1.0.0",
  "description": "点击按钮修改当前网页背景",
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "action": {
    "default_popup": "popup.html"
  }
}

popup.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>页面工具</title>
</head>
<body>
  <button id="changeColor">修改页面背景</button>
  <script src="popup.js"></script>
</body>
</html>

popup.js

document.getElementById("changeColor").addEventListener("click", async () => {
  const [tab] = await chrome.tabs.query({
    active: true,
    currentWindow: true
  });

  await chrome.scripting.executeScript({
    target: {
      tabId: tab.id
    },
    func: () => {
      document.body.style.backgroundColor = "#fff7d6";
    }
  });
});

这已经构成一个最基础的Manifest V3插件。

怎么加载测试

开发阶段不需要先制作CRX。

在Chrome地址栏打开:

chrome://extensions/

然后:

  1. 打开右上角“开发者模式”;

  2. 点击“加载已解压的扩展程序”;

  3. 选择刚才创建的page-color目录;

  4. 插件会出现在扩展程序列表中;

  5. 打开普通网页测试功能。

修改代码后,可以在扩展管理页面点击重新加载按钮。

修改manifest.json、Service Worker或Content Script后通常需要重新加载插件;修改Content Script后,还需要刷新对应网页才能看到新代码效果。

如何制作CRX

本地测试完成后,可以通过Chrome自身的打包功能生成CRX。

进入:

chrome://extensions/

开启开发者模式,点击“打包扩展程序”,选择扩展程序根目录。

第一次打包通常会生成:

page-color.crx
page-color.pem

.crx是打包后的扩展文件。

.pem是私钥文件,用于后续以相同身份重新签名扩展,应该妥善保存,不能上传到公开GitHub仓库或随插件一起公开分发。

也可以通过Chrome命令行进行打包:

chrome.exe --pack-extension=C:\extension\page-color

已有私钥时可以指定:

chrome.exe --pack-extension=C:\extension\page-color ^
--pack-extension-key=C:\keys\page-color.pem

开发目录、ZIP和CRX的区别

形式主要用途
源码目录开发、调试,通过“加载已解压扩展”运行
ZIP常用于提交Chrome应用商店
CRX签名后的Chrome扩展分发包
PEM本地打包使用的私钥,需要保密

这里有一个常见误区:发布Chrome应用商店时,并不是一定要自己先制作CRX。

正常首次提交Chrome Web Store时,开发者通常把扩展目录压缩成ZIP,并保证manifest.json位于ZIP根目录,再上传开发者后台。通过审核和发布流程后,由Chrome Web Store负责正式分发和签名。

CRX能直接拖进Chrome安装吗

现在的Chrome对第三方CRX安装有较严格限制。

开发者自己测试插件时,最直接的方法仍然是打开开发者模式并加载未打包目录。

面向普通Windows和macOS用户公开分发时,Chrome官方支持的主要方式是Chrome Web Store;企业环境还可以通过浏览器管理策略部署扩展。普通用户不能再把任意来源的CRX简单理解成“下载后双击即可安装的软件包”。

因此,自己制作CRX与让普通用户稳定安装CRX是两个不同问题。

Manifest V3带来的变化

现在制作Chrome插件时,需要特别注意Manifest V3。

相比早期Manifest V2,它有几个比较明显的变化:

  • 后台页面改为Service Worker模式;

  • 权限划分更加明确;

  • 扩展代码不能依赖远程托管JavaScript动态执行;

  • 内容安全策略更加严格;

  • 网络请求修改等部分API使用方式发生变化。

例如,在普通网站中常见的下面这种写法:

<script src="https://cdn.example.com/library.js"></script>

不能简单照搬到Manifest V3扩展的普通页面中执行远程代码。需要使用的JavaScript库通常应该随扩展一起打包,并遵守Chrome Web Store的相关政策。

一个完整插件如何协作

稍复杂的Chrome插件通常不是所有代码都写在一个JavaScript文件里,而是多个环境互相通信。

用户点击插件图标
        ↓
Popup
        ↓
发送消息
        ↓
Service Worker
        ↓
调用Chrome API
        ↓
Content Script
        ↓
读取或修改网页DOM

例如一个网页SEO检查插件可能这样工作:

  • Content Script读取页面Title、Description、H标签和链接;

  • Popup负责显示分析结果;

  • Service Worker处理标签页、网络请求或其他浏览器事件;

  • Storage保存用户设置和历史配置。

并不是每个插件都需要完整使用这套结构。一个简单Popup工具甚至可以只有manifest.json、HTML和JavaScript几个文件。

制作时容易踩的坑

第一个问题通常是manifest.json格式错误。它必须是合法JSON,不能像普通JavaScript对象一样随意加入注释。

第二个问题是权限申请过多。例如一个只修改当前网页的插件,没有必要一开始就申请访问所有网站。

第三个问题是把Service Worker当成永远运行的后台程序。Manifest V3会在空闲时停止它,需要长期保存的数据应该放入chrome.storage等持久化位置。

另一个常见问题是把网站开发经验完全照搬到扩展中,例如使用内联JavaScript、eval()或动态加载远程执行代码。这些行为会受到扩展内容安全策略和Chrome Web Store政策限制。

如何判断需要哪些文件

制作插件前,不必先套一个复杂目录模板,可以从功能倒推结构。

只需要点击图标显示一个工具:

manifest.json
popup.html
popup.js

需要自动修改网页:

manifest.json
content.js

需要监听浏览器后台事件:

manifest.json
service-worker.js

需要同时操作网页、保存配置并提供界面:

manifest.json
service-worker.js
content.js
popup/
options/
icons/

Chrome扩展真正的核心并不是CRX后缀,而是Manifest定义的权限、运行环境以及各模块之间的协作关系。CRX只是开发完成后的打包形式之一。

对于刚接触Chrome插件开发的人,最合适的顺序通常是先写一个Manifest V3的最小扩展,通过chrome://extensions加载目录完成调试,再逐步加入Content Script、Service Worker和权限,最后根据用途选择打包CRX或提交Chrome Web Store。这样比直接研究一个现成CRX文件更容易理解整个扩展体系。

参考资料

  1. Chrome扩展Manifest官方文档

  2. Chrome Manifest V3说明

  3. Chrome扩展权限说明

  4. Chrome扩展Service Worker说明

  5. Chrome Web Store扩展打包准备

  6. Chromium CRX3文件格式定义