转换 Chrome Extension 为 Safari 版本

本文最后更新于:2025年4月1日 凌晨

背景

这两天吾辈开始尝试将一个 Chrome 扩展发布到 Safari,这是一件一直想做的事情,但由于 Xcode 极其糟糕的开发体验,一直没有提起兴趣完成。这两天又重新燃起了一丝想法,来来回回,真正想做的事情总是会完成。所以于此记录一篇,如何做到以及踩过的坑。下面转换的扩展 Redirector 实际上已经发布到 Chrome/Firefox/Edge,将作为吾辈第一个发布到 App Store 的 Safari 扩展。

转换扩展

首先,在 WXT 的官方文档中提到了如何发布 Safari 版本 [1],提到了一个命令行工具 xcrun [2],它允许将一个 Chrome 扩展转换为 Safari 扩展。

WXT 提供的命令

1
2
pnpm wxt build -b safari
xcrun safari-web-extension-converter .output/safari-mv2

由于吾辈使用了 Manifest V3,第二条命令必须修改为

1
2
3
4
5
6
7
8
xcrun safari-web-extension-converter .output/safari-mv3

# Output
Xcode Project Location: /Users/rxliuli/code/web/redirect
App Name: Redirector
App Bundle Identifier: com.yourCompany.Redirector
Platform: All
Language: Swift

不幸的是,立刻就可以发现一个错误,默认的 App Bundle Identifier 不正确,需要手动指定 --bundle-identifier,由于需要运行多次这个命令,所以还应该指定 –force 允许覆盖现有 Output。

1
2
3
4
5
6
7
8
xcrun safari-web-extension-converter --bundle-identifier com.rxliuli.redirector --force .output/safari-mv3

# Output
Xcode Project Location: /Users/rxliuli/code/web/redirect
App Name: Redirector
App Bundle Identifier: com.rxliuli.redirector
Platform: All
Language: Swift

现在可以在 Redirector 目录下看到一个 Xcode 项目,并且会自动使用 Xcode 打开该项目。

构建并测试

接下来切换到 Xcode 开始 build 并运行这个扩展。

1741855496643.jpg
1741855508793.jpg

然而,打开 Safari 之后默认不会看到刚刚 build 的扩展,因为 Safari 默认不允许运行未签名的扩展 [3]
1741855578407.jpg

需要设置 Safari

  1. 选中 Safari > Settings > Advanced > Show features for web developers
    1741855703402.jpg
  2. 选中 Safari > Settings > Developer > Allow unsigned extensions
    1741855678560.jpg

此时,如果你像吾辈一样之前安装然后卸载过这个扩展的话,需要手动使用 --project-location 来指定另一个路径重新转换,然后在 Xcode 中构建,这是一个已知的 issue [4]

好的,完全退出 Xcode/Safari,然后重新运行新的转换命令,指定一个其他目录(这里是用了日期后缀)作为转换 Xcode 项目目录。

1
2
pnpm wxt build -b safari
xcrun safari-web-extension-converter --bundle-identifier com.rxliuli.redirector --force --project-location 'Redirector 2025-03-13-17-20' .output/safari-mv3

在 Safari 扩展故障排除中可以有这样一条命令,可以检查已经识别安装的扩展 [5]。当然,实际上即使识别出来了,也有可能在 Safari 中看不到,必要不充分条件,转换之前最好检查 /Users/username/Library/Developer/Xcode/DerivedData 目录并清理构建的临时扩展。

1
pluginkit -mAvvv -p com.apple.Safari.web-extension

无论如何,如果一切正常,就可以在 Extensions 中查看并启用临时扩展了。
1741858042811.jpg

启用它,然后就可以在 Safari Toolbar 中看到扩展图标并进行测试了。
1741858161233.jpg

如果你发现 Mac 生态下的开发很痛苦,经常没有任何错误但也没有正常工作,那可能是正常的。

更换不兼容的 API

好吧,如果幸运的话,扩展就可以正常在 Safari 中工作了对吧,Safari 支持 Chrome 扩展对吧?oh sweet summer child,当然不可能这么简单,Safari 有一些不兼容的 API,它不会出错,但也确实不工作。你可以在官方兼容性文档 [6] 中检查一些不兼容的 API,并采用其他方法绕过。
例如 webRequest 相关的 API,Manifest v3 中 webRequest blocking API 被删除是已知的,但根据这个 App Developer Forums 上的 issue 可知,对于 Safari 而言,Manifest v3 中 webRequest API 整个功能都不生效,仅在 Manifest v2 persistent background pages 中生效,有趣的是,iOS 不支持 persistent background pages。所以之前使用的 webRequest API 需要转换,幸运的是,对于 Redirector 而言,只需要转换为一个。

browser.webRequest.onBeforeRequest.addListener => browser.webNavigation.onCommitted.addListener

可以参考官方文档 [7] 调试 background script,它不方便,但它是唯一的方法。

现在,扩展可以正常工作了。

发布到 App Store

现在,让我们开始构建并发布到 App Store 或在其他地方发布扩展,无论哪种方式,都需要正确配置签名证书。

  1. 首先修改 Project > Build Settings > Checkout ‘All’ & ‘Combined’ > Search ‘team’ > Development Team
    1741836712437.jpg
  2. Mac/iOS Targets > General > Identity > App Category 选择产品类型
    1741837528537.jpg

在发布之前,还需要手动指定版本,因为它并不跟随 manifest 中指定的版本,而是单独的,建议在转换之后就指定。
1741862590410.jpg

该配置也在 <project name>/<project name>.xcodeproj/project.pbxproj 文件中,可以搜索并替换 MARKETING_VERSION = 1.0;

然后从 Xcode 工具栏选择 Product > Archive,就可以构建一个 bundle 并等待分发了。
1741862602934.jpg

首先点击 Validate App 确保 bundle 没有什么配置错误。这里遇到了一个错误,提示吾辈的扩展名(不是扩展 id)已存在,需要使用一个其他的名字。
1741862725322.jpg

好的,让我们修改 manifest 中的名字并重复以上转换和构建流程,重新验证,没有发现错误。
1741863485137.jpg

接下来就可以分发 App 了,点击 Distribute App,然后选择 App Store Connect 在 App Store 上架或 Direct Distribute 公证插件。
1741864293656.jpg

吾辈发现这个视频很有帮助 https://youtu.be/s0HtHvgf1EQ?si=rbzc88E1Y_6nZY6k

完善发布信息

最后,还需要前往 https://appstoreconnect.apple.com/apps 完善发布信息,包括截图、隐私政策和定价等等。吾辈没有意识到 Apple 使用网页来管理 App 发布,这与 Apple 万物皆可 App(App Developer/TestFlight) 的风格似乎不太相像,因此白白苦等了 2 周。

1743476029592.jpg

吾辈还发现 App 描述中禁止使用 emoji 字符,否则会提示 The message contains invalid characters.

总结

Mac/iOS 开发是非常封闭的平台,开发工具与体验与 Web 大有不同,但考虑到 Safari 是 Mac 上默认的浏览器,而在 iOS 上更是无法修改的事实上的标准,可能还是值得投入一些精力去支持它,尽管它甚至比 Firefox 更加糟糕。


转换 Chrome Extension 为 Safari 版本
https://blog.rxliuli.com/p/1a7d920368904cd38a0ea562cf90b246/
作者
rxliuli
发布于
2025年3月13日
许可协议