版本更新与维护
本教程共 56 篇 · 第 50 篇 · 更新于 2026-08-13 · 约 8 分钟阅读
本节目标:学完你能正确递增 version、走通 Chrome Web Store 的更新发布,理解自托管更新的 update_url 机制,并用 onInstalled 检测升级、做数据迁移、妥善处理用户反馈。
上架只是开始。真实世界里,扩展要跟着浏览器升级、跟着用户需求改。
这一节讲上架之后怎么迭代、怎么维护,把「发一版就不管」变成「持续可用」。
50-1 version 字段的语义
清单里的 version 是字符串,用点分数字表示,比如 "1.2.3"。它是浏览器判断新旧的唯一依据。
{
"manifest_version": 3,
"name": "我的扩展",
"version": "1.2.3",
"version_name": "1.2.3 beta"
}
Chromium 按段从左到右逐个比较大小,规则是这样:
1.0小于1.1,1.1小于1.2,1.9小于2.0- 缺失的段视作
0,所以1.1和1.1.0相等 - 比较的是数字大小,不是字符串,所以
1.10比1.9大
提交更新时,新版本必须严格大于线上版本。填相等或更小的值,商店会直接拒绝上传。这是我见过最高频的失误。
还有个可选字段 version_name,专门用来展示给人看,可以写 1.2.3 beta 这类带文字的值。浏览器比对版本时只认 version,不看它。
Note版本号最多四段,每段是非负整数且有上限(以官网当期规则为准)。别写
1.0.0.0.0或者1.0-beta,都会被判非法。
50-2 怎么定版本号
version 只要求「能比大小」,具体怎么划分由你决定。给初学者一个够用的约定:
- 第一段是大版本,界面重构、权限有重大变化时加一。
- 第二段是功能版本,新增功能时加一。
- 第三段是修订号,只修 bug 时加一。
比如 1.4.2 修个小 bug 就发 1.4.3;加了侧边栏功能就发 1.5.0。
有一条经验值得注意:版本号只能往前走,不能回退。哪怕你发现新版有问题想撤回,也只能再发一个更高的版本去修,不能把旧版号重新提交一遍。
Tip所以别拿正式版本号做试验。想灰度验证,走不公开渠道或者分阶段发布,别在线上版本号上来回折腾。
50-3 Chrome Web Store 的更新流程
上架在 Chrome Web Store 的扩展,更新对用户是透明自动的,你不用操心推送。要做的只有两件事:
- 本地改好代码,把
version递增,重新打成 zip。 - 回开发者控制台,找到那个扩展,上传新 zip,写好本次更新说明,提交审核。
审核通过后,商店会在后台把新版本逐步推给已安装的用户。用户下次启动浏览器、或者扩展后台被唤醒时就会换成新版,整个过程无感。你不用维护任何更新服务器。
Tip每次更新都在控制台写清「本次改了什么」。这既是对用户的尊重,也方便你自己回溯是哪一版引入了某个行为。
50-4 分阶段发布
控制台提供「分阶段发布」(staged rollout)这个降低风险的选项,值得用起来:审核通过后不一次推给所有人,先按一定比例放量。有问题时影响面小,观察没事再全量。
具体选项名称和可选比例以控制台当期界面为准。核心思路不变:大改动别一把梭,先小范围验证再铺开。
Note分阶段发布期间,你的用户会同时存在新旧两个版本。如果这次改动涉及存储结构,务必保证新旧代码读同一份数据都不崩。
50-5 自托管更新的机制
不走商店、自己分发时(比如企业内部使用),自动更新就要自己管。核心是两样东西:清单里的 update_url,加一份放在服务器上的更新清单。
先在扩展清单里声明去哪查更新:
{
"manifest_version": 3,
"name": "我的扩展",
"version": "1.5.0",
"update_url": "https://myhost.com/my-ext/updates.xml"
}
服务器上那份更新清单用 Chrome 约定的 XML 格式,告诉浏览器某个 ID 的最新版是几、包在哪:
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>
<updatecheck codebase='https://myhost.com/my-ext/my-ext-1.6.0.crx' version='1.6.0' />
</app>
</gupdate>
三个属性对应关系很清楚:appid 是扩展 ID,codebase 是新包的下载地址,version 是这个包的版本号。浏览器定期访问 update_url,发现远端版本更高就下载安装。
需要的话还能限制最低浏览器版本,低于它的客户端不会收到这次更新:
<updatecheck codebase='https://myhost.com/my-ext/my-ext-1.6.0.crx'
version='1.6.0' prodversionmin='120.0' />
Note自托管场景要求包是签名过的
.crx而不是.zip,还牵涉密钥管理和企业策略配置,门槛比走商店高不少。普通开发者优先走 Chrome Web Store,省心也合规。
50-6 在代码里检测升级
有时候你想在用户刚升级到新版本时做点事,比如弹一次新功能说明、迁移旧数据格式。MV3 里用 chrome.runtime.onInstalled 配合 details.reason 判断:
chrome.runtime.onInstalled.addListener((details) => {
const current = chrome.runtime.getManifest().version;
if (details.reason === 'install') {
console.log('首次安装', current);
return;
}
if (details.reason === 'update') {
console.log('从', details.previousVersion, '升级到', current);
// 在这里做数据迁移或新功能引导
}
});
details.reason 常见取值有 install(首次安装)和 update(版本升级)。details.previousVersion 只在升级时有值,就是用户升级前的旧版本号。
靠这两个信息,你能精确区分「新用户」和「老用户升级」,只对该走的分支做事,不至于每次都骚扰所有人。
50-7 顺手做好数据迁移
存储结构一改,老用户的旧数据就得转换,不然新版本读出来是空的。做法是在 update 分支里按旧版本号判断要不要迁移:
async function migrate(previousVersion) {
const { settings } = await chrome.storage.local.get('settings');
if (!settings) return;
// 旧版把开关存成字符串,新版统一改成布尔值
if (typeof settings.enabled === 'string') {
settings.enabled = settings.enabled === 'true';
await chrome.storage.local.set({ settings });
console.log('已从', previousVersion, '迁移设置格式');
}
}
写迁移逻辑时守住三条:只改需要改的字段、改完立刻写回、迁移函数要能重复执行不出错。服务工作者随时可能被回收,代码要经得起再跑一遍。
Tip新功能引导别做成每次启动都弹。用
storage记一个「某版本引导已展示」的标记,展示过就不再弹,体验会好很多。
50-8 处理用户反馈
上架后商店会开放评分和评论。反馈是金矿,但也容易扎心。几条实操建议:
看差评先冷静。差评大多指向具体痛点,比如某个网站上失效、某个权限看着吓人。把情绪摘掉,只提取可改的点。
在描述里前置答疑。「为什么需要这个权限」这类高频问题直接写进详细描述,能拦掉一半误解型差评。
留好支持入口。商店资料里填上支持邮箱或反馈链接,让用户有处可说,而不是憋着直接给一星。
隐私政策随功能同步改。新增了涉及数据的权限,声明和政策要一起更新,否则既违规也招投诉。
Note不要刷评,也不要在扩展里诱导用户给五星。商店对这类行为有监测,轻则删评,重则下架。
50-9 维护清单
把上线后的例行动作列成清单,照着走不容易漏:
- 浏览器发布大版本后,回归测一遍核心功能。
- 依赖或接口有变化,先本地验证再发版。
- 每次发版递增
version,写清更新说明。 - 涉及存储结构调整时,先写好并测过迁移逻辑。
- 大改动走分阶段发布,观察没问题再全量。
- 定期看评论和评分,归类高频问题。
- 权限或数据处理有变,同步更新隐私政策与数据声明。
- 确定不再维护的扩展主动下架,别留僵尸包。
50-10 小结
维护的本质是让已安装的用户持续用得稳。版本号必须严格递增且不可回退,Chrome Web Store 上传新包审核通过后就自动推送,风险大的改动配合分阶段发布。
自托管才需要自己管 update_url 加更新清单,包还得是签名过的 .crx。代码里用 chrome.runtime.onInstalled 判断 details.reason === 'update' 来检测升级,配合 details.previousVersion 做数据迁移,迁移函数要能重复执行。
用户反馈要正面接,描述里前置答疑、留好支持入口、隐私政策随权限同步。做到这些,扩展就能从「能跑」长成「好用」。