👋 你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】
   我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 HarmonyOS 的过程都记录在这里。
  
  🛠️ 主要方向:ArkTS 语言基础、HarmonyOS 原生应用(Stage 模型、UIAbility/ServiceAbility)、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战,以及 Android → 鸿蒙的迁移踩坑与复盘。
  🧭 内容节奏:从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘,让每篇都有可落地的代码与方法论。
  💡 我相信:写作是把知识内化的过程,分享是让生态更繁荣的方式。
  
   如果你也想拥抱鸿蒙、热爱成长,欢迎关注我,一起交流进步!🚀

前言:升级不是“发个包”,是“给千万用户动手术”🩺

很多团队对升级的理解停留在“versionCode +1,打包,上架”。然后某天凌晨你会收到一句灵魂拷问:

“为什么更新后登录态没了?收藏也没了?我刚编辑的内容去哪儿了?”
这时候你才发现:兼容、迁移、灰度、回滚缺一项,都是在给自己埋雷。

1)版本兼容设计:先定“边界”,再谈“功能”

1.1 三个版本号别乱用:versionCode / versionName / target/compatible

  • versionCode / versionName:在配置文件里声明,系统用 versionCode 判断“谁更新谁”。OpenHarmony 文档对 versionCode(整数、用于比较版本新旧)有明确说明。
  • targetSdkVersion / compatibleSdkVersion(或类似配置项):决定你“用哪套 API 行为”和“最低兼容到哪”。HarmonyOS 的应用兼容性文档强调要结合 API 版本变化评估并适配、并在历史版本设备上验证。

我的建议(很工程,但管用):

  • 兼容边界写在文档里:最低支持 API/系统版本、哪些能力降级、哪些直接不支持。
  • 行为分叉别靠“猜系统版本”:优先“能力探测”(能用就用,用不了就降级),少写硬编码 if-else 地狱。

1.2 兼容的“正确姿势”:分层兼容,而不是“全靠 UI 兜底”

我一般把兼容拆成三层(你照抄就行):

  1. API 行为兼容:同一接口在不同 API 版本可能行为变化,升级 target 时要对照“兼容性说明”逐项验证。
  2. 设备形态兼容:屏幕、输入方式、窗口能力不同——别让平板/折叠屏被手机布局“勒到窒息”。
  3. 数据兼容:这是最容易翻车的(下一节狠狠干)。

1.3 代码示例:做一个“版本闸门”,把风险关在门外

思路:首次启动记录“已运行版本”,升级后只做一次性迁移,并且可以灰度开启新能力。

import preferences from '@ohos.data.preferences'

const PREF_NAME = 'upgrade_guard'
const KEY_LAST_VERSION = 'last_version_code'

// 你可以把这个值由打包脚本注入,或从配置读取(示意用常量)
const CURRENT_VERSION_CODE = 3400123

export async function checkAndMarkUpgrade(ctx: Context): Promise<{ firstRun: boolean, upgraded: boolean }> {
  const pref = await preferences.getPreferences(ctx, PREF_NAME)
  const last = Number(await pref.get(KEY_LAST_VERSION, 0))

  const firstRun = last === 0
  const upgraded = last > 0 && last < CURRENT_VERSION_CODE

  if (firstRun || upgraded) {
    await pref.put(KEY_LAST_VERSION, CURRENT_VERSION_CODE)
    await pref.flush()
  }
  return { firstRun, upgraded }
}

你看,这玩意儿土,但它能救命:迁移只跑一次,不会每次启动都把用户数据“反复折腾”🙃。

2)数据迁移方案:别把“用户数据”当可再生资源😤

数据迁移我给你一句铁律:

永远把迁移当成“可能失败”,并且要做到“失败可恢复”。

2.1 迁移分三类:你得对症下药

  1. Preferences/轻量 KV:字段改名、结构变更(JSON)
  2. 关系型数据库 RDB:表结构变更、索引调整、拆表合表
  3. 文件/媒体缓存:目录结构变化、缓存策略变化、加密策略变化

2.2 迁移策略:版本化 + 事务 + 可回滚

给数据库加一个 schemaVersion(或 user_version),迁移按版本一步步升级,别“跨两三代一口闷”。(你跨太大,出了错你都不知道错在哪🥲)

示例:RDB 迁移骨架(事务包裹 + 逐步升级)

// 伪代码:具体 RDB API 以你项目 SDK 为准(核心是“版本驱动 + 事务”)
async function migrateRdb(store: RdbStore) {
  const current = await getSchemaVersion(store) // 例如从 meta 表读
  let v = current

  await store.beginTransaction()
  try {
    if (v < 2) {
      // v1 -> v2:新增字段/表
      await store.executeSql('ALTER TABLE user ADD COLUMN avatar TEXT', [])
      v = 2
    }
    if (v < 3) {
      // v2 -> v3:拆表/补索引
      await store.executeSql('CREATE INDEX idx_user_name ON user(name)', [])
      v = 3
    }
    await setSchemaVersion(store, v)
    await store.commit()
  } catch (e) {
    await store.rollback()
    // 关键:失败要“可诊断”,别只打个“迁移失败”
    throw new Error(`DB migrate failed at v=${v}: ${(e as Error).message}`)
  }
}

迁移失败时你至少要有两条路:

  • 保守降级:数据库不升级,功能降级(但能进应用,别直接崩)
  • 备份回滚:迁移前导出关键表/关键数据(哪怕只备份用户最重要的那几张表)

迁移最怕什么?不是慢,是“迁移到一半崩了”。所以事务/分步/可回滚,真别省。

2.3 分布式数据的兼容:字段要“向后可读”

如果你用到了分布式数据同步(比如分布式 RDB / KV 同步),那更要注意:

  • 新字段 可选(旧端读不懂也别炸)
  • 协议/数据结构 带版本号
  • 不同端版本混跑是常态(灰度期间尤其明显)

(OpenHarmony 的分布式 RDB 示例能看到 sync、dataChange 监听这类协同用法,现实里你更需要“数据结构版本化”的工程纪律。)

3)灰度发布:别把“全量发布”当勇敢,那叫鲁莽😅

灰度的目的只有一个:

让事故的爆炸半径可控。

3.1 灰度发布怎么做(AppGallery Connect 方向)

你可以用 AGC 做分阶段发布(按比例/分批),先让 1% 用户吃新版本,观察崩溃率、ANR、关键链路成功率,再逐步扩大。
(这块不同团队的流程不一样,但“阶段发布 + 指标门禁”是核心。)

3.2 “功能灰度”比“版本灰度”更狠(也更稳)

版本灰度只能控制“谁拿到包”;但你经常需要控制“谁看到新功能”。
这时候我强烈建议你上:

  • 远程配置/功能开关(例如新首页、新支付链路、某个新缓存策略)
  • 灰度策略:按账号、按设备、按地域、按百分比
    这样哪怕包已经下发,你也能做到“线上一键关功能”,不至于只能干瞪眼。

我最喜欢的救命组合拳:版本灰度 + 功能开关
出事时先关功能止血,再决定要不要回滚版本。

4)回滚机制:你得提前准备“后悔药”💊

AGC 支持把当前在架版本回退到上一个版本(“回退到最近一次上架版本”这类能力在官方帮助里有说明)。

4.1 回滚的前提:数据迁移必须“向前兼容/可回退”

这句话很残酷但真实:

  • 你发了 v3,把数据库结构升级了
  • 然后你回滚到 v2
  • v2 根本不认识 v3 的结构
    那用户进应用就可能直接凉凉🙃

所以你要做两手准备:

  1. 向前兼容:新结构尽量不破坏旧结构(新增字段比删字段安全一万倍)
  2. 回滚策略:要么迁移时保留旧表/旧字段一段时间;要么提供 downgrade 迁移(成本高,但关键业务值得)

4.2 回滚流程建议(我自己比较认这套)

  1. 触发门禁:崩溃率/关键链路失败率超过阈值 → 自动/人工进入“紧急模式”
  2. 先关功能开关(秒级止血)
  3. 如果仍不可控 → 执行 AGC 回退版本
  4. 回滚后监控:存量用户是否仍受影响(尤其数据兼容)

结尾:升级做得好,用户无感;升级做砸了,用户记仇😅

把这四件事串起来,你的升级体系才算“能打”:

  • 版本兼容:先定边界、再做能力探测、升级 target 要按兼容性说明逐项验证
  • 数据迁移:版本化、事务、可回滚(失败也能进应用)
  • 灰度发布:分批放量 + 指标门禁 + 功能开关
  • 回滚机制:平台回退 + 数据向前兼容兜底

📝 写在最后

如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!

我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!

感谢你的阅读,我们下篇文章再见~👋

✍️ 作者:某个被流“治愈”过的 移动端 老兵
📅 日期:2025-11-05
🧵 本文原创,转载请注明出处。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐