标签: mv3

  • Chrome Extension MV3 已知兼容性问题与 Bug

    Chrome Extension MV3 已知兼容性问题与 Bug

    这几天回顾 Chrome Extension MV3,发现官方发布了一篇文章:Known issues when migrating to Manifest V3,准备结合我的经验,摘译过来分享给大家。建议大家还是要看一下原文,而且这篇文章也在不断更新,如果有新内容,也麻烦提醒我更新。目前版本是:2022-12-09,Chrome 108。

    这篇文章列举了已知的、影响开发者将插件迁移到 MV3 的重大问题。答题分为两部分:

    1. 兼容性问题。因为 MV3 的设计而产生的问题。
    2. Bug。纯粹没搞好。

    这篇文章是 Chromium issue 追踪器的子集,全部问题大家可以自行通过标签查找:平台 > 扩展

    新功能完成或者 bug 解决后,会随着稳定版发布。之后,对应的问题就会从这个页面里移除,所以,如果大家想知道问题变更的历史记录,可以去看: What’s New in Chrome Extensions

    兼容性

    【已修复】webRequest.onAuthRequired events

    普通用户安装的 MV3 扩展无法拦截事件。在 Chrome 108 中已修复。

    【已修复】Offscreen Documents API

    MV3 强制把 background page/script 改成 service worker,带来一个问题:以前的 background page 可以渲染页面,也就包含了完整的 DOM API,如今没有了,那么很多依赖 DOM 的功能也都做不到了。比如剪贴板、音乐播放、解析 HTML 等。所以新版本 Chrome 109 里增加了新的 Offscreen Documents API,方便用户使用。

    目前这个 API 的文档很简单,我用 Edge,目前还停留在 108 版本,也没能试用,回头体验了再分享。

    放宽扩展 Service worker 的生命时间

    目前扩展 Service worker 执行一段时间之后就会被终止掉,据我测试大约是 28 秒。未来这个时间长度会动态调整,以便 service worker 的功能能够稳定完成。预计 2023 年一季度开始测试此功能。

    用户脚本管理支持

    目前扩展不允许执行外部脚本,只能执行发布时已经打包进去的那些脚本。导致 GA、FB 这些平台 SDK 很难用,Showman 也一样。下一步,MV3 会提供一个管理工具,让用户授权一些特定代码和样式。

    预计也是 2023 年一季度开始测试。

    给 Storage API 扩容

    目前 Storage 的存储空间是 1MB,开发团队准备适当扩容,具体的数字还没想好。我对这个变化没啥期待,Storage 本来也就存点配置之类的信息,感觉 1M 能存很多了。

    Bugs

    【已修复】Service workers 在 webRequest 时间后不启动

    之前的版本中,MV3 扩展只会在安装后的很短时间里,能够接收到 Web Request API 事件,后面就接收不到了。如今,这个 bug 修复了,发布于 Chrome 107。

    (容我吐个槽,刚开始推广 MV3 的时候,这种 bug 不胜枚举。)

    沙箱页面 CSP 不能配置

    现在的沙箱页面 CSP 无法被用户自定义配置覆盖,会固定使用初始值。大约会在 2023 年一季度开始测试修复。


    总结

    看看这些设计导致的兼容性问题,和开发引入的质量 bug,当初他们有什么信心在 2023 年 1 月完成彻底迁移的?

    我还是那个观点:

    1. MV3 的设计有其合理之处,相对于 MV2 确实是进步
    2. MV3 整个 API 和文档的质量堪忧,给我们带来了大量不必要的工作量
    3. 插件变现很难,大家都用爱发电,这次强推 MV3 实在是不把开发者当人
    4. 希望新的一年里,MV3 能建设完全,并逐步升级

    如果你在开发插件的时候遇到问题,欢迎与我交流。

  • 好吧,Google 暂时不打算强推 Chrome Extension MV3 规范

    好吧,Google 暂时不打算强推 Chrome Extension MV3 规范

    前几天朋友提醒,Google 没有强推 Chrome Extension MV3。如果我没记错的话,按照原本的计划,今年 1 月 1 日起,Chrome Web Store 就要下架所有 MV2 扩展,只允许企业内部进行组织部署;7 月 1 日后就连用户本地也不允许安装和运行 MV2 扩展了。所有扩展必须升级到 MV3。

    不过看 Manifest V2 support timeline 的最新内容,这些安排都延期和搁置了,至少到 2024 年 1 月之前,大家还能放心继续使用 MV2。至于之后能不能用,还在考虑之中。

    我找到了官方的延迟通知,在这里:暂停清单 V2 逐步淘汰更改 (google.com)。按照官方的说法,除了一些开发负担,还有很多之前没想到的问题,比如缺少 DOM,导致很多合理的功能在 MV3 完全无法实现。这点我之前的 Chrome Extension Manifest V3 升级笔记 一文也提到过。

    朋友推测,这里的原因在于:

    1. 做浏览器扩展并不赚钱
    2. 所以很多浏览器扩展的开发者现在都没有继续维护和开发了
    3. Google 要求大家必须升级,大家说:不让用不用,鬼理你
    4. 然后这些扩展的用户,尤其是很多工具类产品,甚至包括 Cyrpess、OpenResty Showman 等测试工具都依赖 MV2 扩展,就会迁移到其它支持 MV2 的浏览器,比如 Edge、Firefox

    相对来说,Google 推 GA4 就很硬气,猜测是因为 GA 没有什么特别大的竞争对手,从速度、效果、Adsense 等方面来看,GA 有巨大优势。而且升级 GA 很容易,换个 JS,改下初始化就行了。

    升级 MV3 很困难,各种不兼容的 API 变化,大量程序几乎要完全重写。而且,看过 Chrome Extension Manifest V3 升级笔记 的同学应该还记得,Google 最开始推 MV3 的时候,API 和文档烂的一塌糊涂,简直不能用。

    Chrome Web Store 团队会进一步聆听社区,讨论升级方案,并且在 2023 年 3 月拿出新方案(他们没有放弃!),所以大家也不要掉以轻心。

    总之,我的建议是:

    1. 如果大家现在要做扩展,建议还是做 MV3 版本
    2. 如果大家现在的工作依赖 MV2,可以继续放心大胆用
    3. 保持对 MV2/MV3 升级计划的关注

    如果你有把浏览器扩展从 MV2 升级 MV3 的问题、经验,欢迎跟我讨论分享。

  • Chrome Extension MV3 在 background script 里扫描二维码并传出结果

    Chrome Extension MV3 在 background script 里扫描二维码并传出结果

    升级浏览器扩展到 MV3 时,因为 MV3 不再允许使用 background 页面,必须使用 service worker 类型的 background script。这样一来,就没有 window 对象,会遇到很多问题。

    今天分享下如何在 service worker 类型的 background script 里完成扫描二维码并传出结果。比如我帮朋友升级 二维码生成器 (Quick QR) 这个扩展,它有个功能是通过右键菜单扫描页面中的二维码,并返回扫描结果。这个过程只能在 background script 里完成,于是升级时就给我带来了不小的麻烦。

    首先,右键菜单的响应事件只能得到图片 URL。其次,扫描功能需要用到 jsqr,它接受 imageData 作为参数,可以返回扫描结果。所以我们就需要把 URL 转换成 imageData,过程如下:

    // service worker 里可以使用 `fetch()` 请求服务器
    const response = await fetch(src);
    const blob = await response.blob();
    // 使用 `createImageBitmap` 可以将支持的图片格式转换成位图
    const bitmap = await createImageBitmap(blob);
    const {width, height} = bitmap;
    // 在 service worker 里,需要使用 OffscreenCanvas
    const canvas = new OffscreenCanvas(width, height);
    // 注意,这里只能是 `2d`,`bitmaprenderer` 无法使用 `getImageData` 方法
    const context = canvas.getContext('2d');
    context.drawImage(bitmap, 0, 0);
    const imageData = context.getImageData(0, 0, width, height);
    // 接下来识别就好
    const data = jsQR(imageData.data, width, height);
    const [tab] = await getActiveTab();
    // 因为没有 `window`,`alert()`、`prompt()` 都不能用,只能通过在目标页面执行脚本的方式输出结果。注意,`tab.executeScript` 也没有了,必须用下面这个新 API,并且要提前申请权限
    await chrome.scripting.executeScript({
      args: [i18n(SCAN_RESULT), data.data],
      target: {
        tabId: tab.id,
      },
      func: (message, result) => {
        result = prompt(message, result);
        if (result) {
          navigator.clipboard.writeText(result)
            .catch(() => void 0);
        }
      },
    });

    大概过程如上面代码所示,需要注意的东西我都放在注释里了。

    关于 MV3 的其它升级经验,我会更新在 Chrome Extension Manifest V3 升级笔记,欢迎常来看看。

    (更多…)
  • Chrome Extension Manifest V3 升级笔记

    Chrome Extension Manifest V3 升级笔记

    关于 MV3 的知识,可以看这篇前文:

    《Chrome 扩展大升级 Manifest V3:变化》

    近期尝试把一个浏览器扩展升级到 MV3,然后发现了很多问题,写篇博客记录一下。

    与文档不符

    • 很多号称返回 Promise 实例的方法实际上不会返回结果,或者在没有 callback 的时候会报错

    文档未说明

    • service worker 里无法使用 chrome.i18n.getMessage 或者 chrome.i18n.getUILanguage(【v100 已修复】)。于是目前右键菜单都无法 i18n 了。
    • chrome.contextMenus.create 无法向 browser_action 添加菜单项(MV3 不再支持)

    未实现 Promise 或者有 bug

    • chrome.storage.local.get(keys) Promise 结果固定返回 undefined,不可用,需用回 callback (【v97 已修复】)
    • 【未测试】chrome.permissions.request 未 Promise 化,无返回值
    • 【未测试】必须传入 callback,不然报错
      • chrome.permissions.contains
      • chrome.contextMenus.remove

    文档写了,但我没看见(>_<!)

    • 在 service worker 里使用 chrome.contextMenus.create 时,必须传入 id,且不能使用 onclick 函数。只能侦听 chrome.contextMenus.onClicked.addListener,然后做进一步判断。

    MV2 存在的功能,但无法迁移至 MV3

    (有些可能是暂时的)

    因:不允许使用 remote JS

    MV3 不支持使用外部 JS,所以 Google Analytics 和 Facebook 分享按钮之类的 SDK 都无法使用。也即是说,现在扩展不能使用 GA,也不能嵌入 Facebook Like,也不能使用其它需要引用外部 SDK 才能实现的功能。

    因:Service worker 取代 background page/JS

    无法获取系统 light/dark mode

    Service worker 没有 window 对象,也就没有那些 window 对象上才有的方法,比如 matchMedia()。所以我们就无法在 service worker 里检查系统的 dark mode,实现动态修改 icon 的功能。

    无法将 SVG 解析成 ImageData

    因为 createImageBitmap 无法解析 SVG blob,所以原则上,所有 SVG 的操作均无法执行。

    外传信息比较麻烦

    无法使用 alert()prompt(),也无法手动弹出 popup。所以如果我们想从 service worker 里向外传出内容,只有三个选择:

    1. 使用通知 notification API
    2. 直接打开页面
    3. 使用 chrome.scripting.executeScript() 在目标页执行脚本

    (1)(3)需要不同的需要权限,(2)的体验不好。怎么用就自己选择吧。

  • Chrome 扩展大升级 Manifest V3:变化

    Chrome 扩展大升级 Manifest V3:变化

    上一篇博客 聊了聊 Manifest V3 的设计思路,接下来就该详细介绍下这个版本的变化。按照 官方介绍,V3 的变化主要有以下五点:

    1. 需使用 Service worker 替换 background scripts/pages。这个变化对我影响很大,未来开发新扩展的时候,需要使用全新的代码架构;老扩展要升级,多半也要彻底重构。
    2. 修改网络请求的 API 换作 chrome.declarativeNetRequest。这个变化我暂时没用到,将来有机会再说。
    3. 禁止运行远程代码,所有将会运行的代码都必须事先打包进扩展,接受商店的审查。这点对我厂的影响非常大,很可能我厂的 Showman 要彻底改变实现方式——最大的可能就是停留在 Manifest V2,如果 Manifest V2 被废弃,那就使用新技术栈开发下一代产品。
    4. API 全部提供 Promise。这是应该的,小改善。
    5. 其它一大批杂七杂八的功能变化。

    其中 2 暂时不好评价,3 只能被动接受,4、5没啥好说的,所以接下来谈谈 1,background script => service worker。

    Background Scripts/Pages

    Background scripts/pages(后面简称 background script)的地位很重要,是浏览器扩展的重要组成部分,可以作为联系其它组件的中心、主控,在扩展功能复杂时,作用很大。比如我厂的 Showman,既需要用 content script 注入功能到目标网页,也需要单独打开页面让用户交互,这里每个 JS 都要跑在独立环境,彼此隔离,所以就需要有一个中控,一方面连接各个独立的组件,另一方面常驻内存存储一些全局数据。

    相信大家不难想到,这种常驻内存的东西,虽然给开发带来了便利,但是也会给内存带来不小的压力。况且,在 Manifest V2 阶段,甚至还支持一个浏览器扩展注册多个 background scripts 和 background pages。每个页面和脚本都要独享一个环境,哪怕只有短短几行代码,于是就会吃掉大量的内存。

    Chrome 对内存使用方面的不检点,被大家诟病已久。其开发团队当然也知道,所以最近几个版本 Chrome 都在试图改进这些问题。既然新版本要降低系统要求提高性能表现,尽量节省内存、同时减少运行时间就是必须考虑的事情。所以,新版本扩展规范规定,background script 有且只有一个,而且只能是 service worker。

    Service worker 只能注册事件侦听器,不能持续运行。这样一来,就可以让 background script 的执行之间降到最低,并且随需而动,减少内存占用。

    Service worker 的特殊用法

    1. 事件侦听器都要放在顶层

    事件侦听器都要放在顶层,非顶层的事件侦听器会被直接忽略。

    2. 使用 storage API 存储持久化状态

    不要用全局变量,把一些需要用到的数据都放到 storage 里,如下:

    // 不要这样做
    const foo = 'bar'
    chrome.runtime.onMessage.addListener(({ type, name }) => {
      if (type === "set-name") {
        name = foo;
      }
    });
    
    // 这样做
    chrome.runtime.onMessage.addListener(({ type, name }) => {
      const foo = await chrome.storage.local.get(['name']);
      if (type === "set-name") {
        name = foo.name || 'bar';
      }
    });

    3. 使用 chrome.alarms 取代定时器

    我们以前一般习惯于用 setTimeoutsetInterval 定时执行,但它们在 service worker 里都会失效。此时,要用专门的 Alarms API 代替,使用方法倒也不难:

    chrome.alarms.create({ delayInMinutes: 3 });
    chrome.alarms.onAlarm.addListener(() => {
      // do something
    });

    需要注意的是,content script 里虽然仍支持 setTimeout,但是太长的定时器会被直接忽略掉,时间阈值是 13s,即短于这个时间的仍然会触发,但是超过的会被忽略。建议如果 content script 需要定时器,那么也交给 background script 来做。

    4. 其它一些常见场景的处理

    包括解析 HTML/XML、处理音视频播放、使用 <canvas> 绘图等,因为我暂时都没用到,所以就先不说了。

  • Chrome 扩展大升级 Manifest V3:设计原则

    Chrome 扩展大升级 Manifest V3:设计原则

    Chrome 前阵子发布了 Chrome Extension Manifest V3 规范,算是为浏览器扩展开发的下一步明确了方向。虽然目前只在 Chrome 浏览器里有效,不过鉴于 Chrome 的统治级地位,相信只要不出大问题,将来肯定会成为 Browser Extension 规范——实际上,Browser Extension API 就约等于 Chrome Extension Manifest V2。

    我最近一两年的工作大多围绕浏览器扩展展开,所以对这个规范很关注,近期也研读了不少,准备写几篇博客分享一下。这是第一篇,主要分享下 MV3 规范的设计原则。


    1. 保护隐私

    最初的浏览器扩展给了开发者非常大的自由,可以让浏览器扩展大大加强浏览器的能力,但是也会给普通用户带来大量数据外泄的风险。

    新规范支持浏览器扩展在不需要特殊权限的时候先正常运行,有用到某个权限的时候,再向用户请求使用许可。另外,权限的授予也不再是永久的,避免长期授权可能导致的问题。

    2. 保障安全

    扩展要上商店,必须经过审核,很多功能可能没那么容易过审。于是很多应用开发者都会想方设法使用外部资源来绕开平台对应用的监管,这样做能带来更强大的功能,也会带来更大的隐患。比如我厂,Showman 必须用外部 JS 才能驱动网页;但如果是恶意开发者,他们可能会利用这点干坏事。

    对于外部资源的使用,新规范采用了更严格的限制。V3 里,只能使用静态外部资源,比如图片视频等,外部脚本彻底不能跑了。这对我厂 Showman 是不利消息。

    3. 提高性能

    Chrome 的性能一直被人诟病,内存杀手的恶名背负已久。可能很多人不知道,其实 Chrome 扩展架构一直是个大问题。出于安全考虑,扩展里的 JS 会运行在很多不同环境下,比如 content script,background script,都会跑在独立的沙箱里,也就是说,哪怕你一个页面都不开,可能也有好几个扩展 background page/script 在悄悄运行,占用你的内存。

    所以新版本也作出改进,强制限制只能使用一个 background script,而且这个 background script 必须以 service worker 形式来跑。保证浏览器扩展不会吞噬掉所有系统资源。

    4. 追随统一的 Web 平台

    以前为了提供更强大的功能,给扩展增添了很多专享 API,比如文件读写。如今 Web 平台不断发展,一些经过验证的 API 被吸纳到 Web 标准,一些步子太大的 API 被证明其实没啥用。总之,为了让降低开发者的心智负担,也让更多的代码可以一次开发导出运行,新规范会尽量向 Web 平台靠拢,减少专享 API,鼓励使用 Web API。

    5. 改善功能

    当然,说到底,大家之所以用浏览器扩展,还是因为它的功能比 Web 强。所以新版本还会继续探索新的可能性,让扩展平台更强大、功能更丰富,以便给用户带来更大的价值。

    总结

    MV2 已经过去了大约十年,确实有一些不合时宜之处,各个平台也逐步摸索了一些更好的策略,比如,权限和安全性的改进很明显是从 iOS、Android 学习而来。至于性能表现,我也很期待。

    以上内容主要来自于我对新老 API 的理解和这篇官方介绍:Extensions platform vision – Chrome Developers。推荐阅读。