欢迎光临
我们一直在努力

区块链钱包开发(一)—— 浏览器插件开发

前言

本文专注于 Chrome 插件 Manifest V3(MV3)版本的开发指南,原因如下:

  • 行业标准:

    • Chrome 浏览器占据全球浏览器市场 65% 以上的份额(2024年统计)
    • 2024年1月起,Chrome 应用商店已全面下架所有 Manifest V2 插件,仅接受 MV3 版本上架
  • 学习聚焦:

    • 本教程针对区块链钱包开发场景,插件作为载体只需掌握核心功能:
      • 通信相关
      • 存储相关
      • 基础组件(content-script,service worker,popup等)
  • 延伸学习:

    • 官方最新文档: Chrome Extensions Developer Guide
    • 中文补充资料(注意时效性): Chrome插件开发全攻略 注:该教程基于 MV2 编写,部分 API(如 background page)在 MV3 中已废弃
  • 开发调试

    Chrome插件没有严格的项目结构要求,只要保证本目录有一个manifest.json即可,也不需要专门的IDE,普通的web开发工具即可。

    从右上角菜单->更多工具->扩展程序可以进入 插件管理页面,也可以直接在地址栏输入 chrome://extensions 访问。

    勾选开发者模式即可以文件夹的形式直接加载插件,否则只能安装.crx格式的文件。Chrome要求插件必须从它的Chrome应用商店安装,其它任何网站下载的都无法直接安装,所以,其实我们可以把crx文件解压,然后通过开发者模式直接加载。

    核心组件

    manifest.json

    每个插件都必须包含一个 manifest.json 文件,位于扩展根目录。以下是一个基本的 MV3 清单文件结构:

    {
    "manifest_version": 3, // 必须为3
    "name": "扩展名称", // 显示名称(≤45字符)
    "version": "1.0.0", // 版本号
    "action": { // 浏览器工具栏按钮配置
    "default_popup": "popup.html"
    },
    "background": { // 后台脚本(Service Worker)
    "service_worker": "background.js"
    },
    "content_scripts": [{ // 注入页面的脚本
    "matches": ["*://*.example.com/*"],
    "js": ["content.js"]
    }],
    "permissions": [ // 所需API权限
    "storage", "tabs"
    ],
    "host_permissions": [ // 需要访问的网站
    "https://api.example.com/"
    ]
    }

    content-scripts

    content_scripts 是 Chrome 扩展中用于向网页注入 JS/CSS 的脚本,我们每新建一个网页,都会被注入一个或多个content_scripts脚本

    {
    "manifest_version": 3,
    "content_scripts": [
    {
    "matches": ["https://example.com/*"], // 匹配的网址
    "js": ["content1.js, content2.js"], // 注入的JS
    "css": ["content.css"], // 注入的CSS
    "run_at": "document_idle" // 注入时机,可选值:"document_start","document_end",or "document_idle",最后一个表示页面空闲时,默认document_idle```(document_start|document_end|document_idle)
    }
    ]
    }

    大多数教程里都会说content-scripts和原始页面共享DOM,但是不共享JS,想要访问JS需要通过DOM 事件或注入 script 标签,这是不严谨的,在manifest.json文件中配置content_scripts可以指定world参数,如果不指定默认为ISOLATED,这种情况确实无法访问JS,因为content-scripts运行在和页面隔离的环境中。但是如果我们把参数设置为MAIN,意味着脚本会被注入到页面的主执行环境(main world),与页面原有的 JavaScript 共享同一个全局作用域(即 window 对象)。这意味着注入的脚本可以:

    • 直接访问和修改页面的全局变量(如 window.pageVariable)。
    • 调用页面定义的函数。
    • 覆盖或扩展页面原有的 JS 逻辑

    需要特别注意的是我们直接在manifest.json文件中配置参数world: 'MAIN'无法生效,这是Chrome的一个bug,只能通过chrome.scripting.registerContentScripts动态注入:

    // 注册一个在 MAIN 环境中运行的内容脚本
    const scriptConfig = {
    id: "main-world-script",
    js: ["main-world.js"], // 脚本文件需打包在扩展中
    matches: ["https://example.com/*"],
    world: "MAIN" // 关键参数
    };

    await chrome.scripting.registerContentScripts([scriptConfig]);

    background(service worker)

    插件的后台服务,理论上可以随着浏览器的打开关闭一直运行在后台,但在MV3中如果长时间无操作会被关闭,我们可以通过定时触发后台事件的方式使其一直运行,这在钱包开发中很重要,因为我们要确保后台不会停止运行。

    {
    "manifest_version": 3,
    "background": {
    "service_worker": "background.js"
    }
    }

    popup

    popup是点击插件图标时打开的一个小窗口网页,焦点离开网页就立即关闭,一般用来做一些临时性的交互

    {
    "manifest_version": 3,
    "action": {
    "default_popup": "popup.html",
    "default_icon": "icon.png"
    }
    }

    消息通信

    网页,content-script,popup,background之间相互通信的关系图:

    #mermaid-svg-UDuGrticqT1zJToS {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-UDuGrticqT1zJToS .error-icon{fill:#552222;}#mermaid-svg-UDuGrticqT1zJToS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UDuGrticqT1zJToS .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-UDuGrticqT1zJToS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UDuGrticqT1zJToS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UDuGrticqT1zJToS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UDuGrticqT1zJToS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UDuGrticqT1zJToS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UDuGrticqT1zJToS .marker.cross{stroke:#333333;}#mermaid-svg-UDuGrticqT1zJToS svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UDuGrticqT1zJToS .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-UDuGrticqT1zJToS .cluster-label text{fill:#333;}#mermaid-svg-UDuGrticqT1zJToS .cluster-label span{color:#333;}#mermaid-svg-UDuGrticqT1zJToS .label text,#mermaid-svg-UDuGrticqT1zJToS span{fill:#333;color:#333;}#mermaid-svg-UDuGrticqT1zJToS .node rect,#mermaid-svg-UDuGrticqT1zJToS .node circle,#mermaid-svg-UDuGrticqT1zJToS .node ellipse,#mermaid-svg-UDuGrticqT1zJToS .node polygon,#mermaid-svg-UDuGrticqT1zJToS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UDuGrticqT1zJToS .node .label{text-align:center;}#mermaid-svg-UDuGrticqT1zJToS .node.clickable{cursor:pointer;}#mermaid-svg-UDuGrticqT1zJToS .arrowheadPath{fill:#333333;}#mermaid-svg-UDuGrticqT1zJToS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UDuGrticqT1zJToS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UDuGrticqT1zJToS .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-UDuGrticqT1zJToS .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-UDuGrticqT1zJToS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UDuGrticqT1zJToS .cluster text{fill:#333;}#mermaid-svg-UDuGrticqT1zJToS .cluster span{color:#333;}#mermaid-svg-UDuGrticqT1zJToS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UDuGrticqT1zJToS :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    扩展环境

    网页环境

    window.postMessage

    chrome.runtime.sendMessage/connect

    chrome.runtime.sendMessage

    chrome.runtime.sendMessage

    chrome.tabs.sendMessage/connect

    window.postMessage

    BackgroundService Worker

    Popup

    Content Script

    原始网页

    实际的钱包开发中我们会对这些API做进一步的封装,详见后续系列教程。

    存储

    在 Chrome 扩展开发(Manifest V3)中,我们应当避免过度依赖全局变量,因为 Service Worker 的生命周期特性决定了它会在不活跃时被浏览器自动终止,此时所有全局变量都会丢失。为了确保数据的持久性和一致性,我们需要将关键变量进行持久化存储。Chrome 扩展提供了多种存储方案,以下是详细说明和实际应用建议:


    为什么避免全局变量?

    • Service Worker 特性:MV3 的后台脚本运行在 Service Worker 中,浏览器会在空闲时终止它(通常 30 秒无活动后)
    • 数据丢失风险:全局变量在 Service Worker 重启后会被重置
    • 状态不可靠:依赖内存状态的逻辑会失效(如计数器、临时缓存)

    持久化存储方案

    chrome.storage.local

    用途:长期持久化存储(扩展卸载前一直存在) 特点:

    • 异步操作(避免阻塞主线程)
    • 默认配额 5MB(可通过 unlimitedStorage 权限申请更多)
    • 数据以键值对存储,支持 所有 JSON 兼容类型

    示例代码:

    // 存储数据
    await chrome.storage.local.set({
    userSettings: { theme: "dark", locale: "zh-CN" }
    });

    // 读取数据
    const { userSettings } = await chrome.storage.local.get("userSettings");
    console.log(userSettings.theme); // "dark"

    // 监听变化
    chrome.storage.onChanged.addListener((changes) => {
    if (changes.userSettings) {
    console.log("设置已更新:", changes.userSettings.newValue);
    }
    });

    适用场景:

    • 用户配置项
    • 需要跨扩展组件共享的数据
    • 低频更新的缓存数据

    chrome.storage.session

    用途:内存级临时存储(仅在浏览器会话期间有效) 特点:

    • 数据保存在内存中,浏览器关闭后清除
    • 默认配额 10MB
    • 读写速度比 local 更快

    示例代码:

    // 存储会话数据
    await chrome.storage.session.set({
    tempToken: "abc123",
    lastActiveTime: Date.now()
    });

    // 读取数据
    const { tempToken } = await chrome.storage.session.get("tempToken");

    适用场景:

    • 敏感数据(如 OAuth token,避免长期存储)
    • 高频更新的临时状态
    • 需要快速读写的中间结果

    IndexedDB

    用途:结构化大数据存储(类似小型数据库) 特点:

    • 支持事务、索引、复杂查询
    • 存储量更大(通常 50% 磁盘空间)

    示例代码:

    // 打开/创建数据库
    const db = await new Promise((resolve) => {
    const request = indexedDB.open("WalletDB", 1);
    request.onupgradeneeded = (e) => {
    const db = e.target.result;
    if (!db.objectStoreNames.contains("wallets")) {
    db.createObjectStore("wallets", { keyPath: "id" });
    }
    };
    request.onsuccess = (e) => resolve(e.target.result);
    });

    // 存储钱包数据
    const tx = db.transaction("wallets", "readwrite");
    tx.objectStore("wallets").put({
    id: "1",
    address: "0x123…",
    balance: "100 ETH"
    });
    await new Promise((resolve) => tx.oncomplete = resolve);

    在实际钱包开发中我们既需要chrome.storage也需要IndexedDB做备用,详见后续系列教程。

    赞(0)
    未经允许不得转载:171主机测评 » 区块链钱包开发(一)—— 浏览器插件开发
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址