HarmonyKit | 鸿蒙开发:API 废弃与迁移策略——从 pushUrl 到 UIContext

HarmonyKit | 鸿蒙开发:API 废弃与迁移策略——从 pushUrl 到 UIContext

引言:废弃不等于删除

鸿蒙 API 的废弃遵循渐进策略:标记@deprecated→ 编译器输出 warning → 数个版本后可能移除。标记为 deprecated 的 API 仍然可用——但建议尽快迁移。

HarmonyKit 遇到了三个废弃 API:router.pushUrlrouter.backpromptAction.showToast。迁移成本低——每个受影响的方法只改一行。本文梳理了废弃原因、迁移路径、版本兼容策略,以及如何建立一套通用的 API 废弃监控流程。

项目仓库:https://atomgit.com/VON-/harmony-kit

三个废弃 API 的迁移

router.pushUrl → getUIContext().getRouter().pushUrl()

废弃原因:多窗口场景下全局路由行为不确定。UIContext 绑定路由确保操作作用于正确的窗口。

// 旧写法import{router}from'@kit.ArkUI';router.pushUrl({url:'pages/tools/JsonFormatter'});// 新写法this.getUIContext().getRouter().pushUrl({url:'pages/tools/JsonFormatter'});

迁移的难点不在于"怎么写",而在于"需要改多少个文件"。HarmonyKit 中router.pushUrl的调用点分布在 11 个文件(主页 Index.ets + 10 个工具页)。如果没有 grep 工具,手动寻找所有调用点很容易遗漏。

router.back → getUIContext().getRouter().back()

// 旧写法router.back();// 新写法this.getUIContext().getRouter().back();

每个工具页的返回按钮只改一行。10 个工具页共改 10 行。

promptAction.showToast → getUIContext().getPromptAction().showToast()

// 旧写法import{promptAction}from'@kit.ArkUI';promptAction.showToast({message:'已复制到剪贴板'});// 新写法this.getUIContext().getPromptAction().showToast({message:'已复制到剪贴板'});

废弃原因类似——全局promptAction在异步场景(setTimeout、Promise 回调)中会丢失 UI 上下文,导致 Toast 无法弹出。UIContext 绑定保证了异步回调中也能正确弹 Toast。

// 异步场景中的差异性// 旧写法:在 setTimeout 中可能无法弹出setTimeout(()=>{promptAction.showToast({message:'异步完成'});// 可能失败!},1000);// 新写法:UIContext 在异步回调中仍然有效constuiContext=this.getUIContext();setTimeout(()=>{uiContext.getPromptAction().showToast({message:'异步完成'});// 总是成功},1000);

关键点在于:this.getUIContext()必须在同步上下文中调用(组件 build 或事件回调中),但获取到的uiContext实例在异步回调中仍然有效。所以在setTimeout/Promise.then中调用uiContext.getPromptAction()安全无虞。

一次性迁移 vs 渐进迁移

HarmonyKit 选择了"一次性迁移"——在一个版本中同时迁移所有三个废弃 API。理由是:

  • 改动量小:三个 API 的调用点共约 15 处,每个只需改一行
  • 风险可控:迁移后的行为在单窗口场景下与之前完全一致
  • 消除技术债:0 warning 的编译输出让后续开发者不再需要关注"这些 warning 要不要处理"

但在更大的项目中,渐进迁移可能是更好的选择。策略如下:

  1. 排优先级:按 API 的废弃影响范围排序。全局 API(如 router)影响面广,优先迁移。局部 API(某个组件的私有方法)可以推迟。
  2. 分批提交:每批迁移 1-2 个 API,确保没有回归问题。
  3. 兼容层:在迁移完成前,可以写一个简单的兼容函数:
// 兼容层示例(迁移过渡期使用)functionsafePushUrl(url:string,context?:UIContext){if(context){context.getRouter().pushUrl({url});}else{// 回退到旧 API(如果仍然可用)router.pushUrl({url});}}

但这种兼容层方案也有代价:它在鼓励继续使用旧 API。更好的做法是"一次迁移,不留后路"——直接在代码中替换为新的 UIContext 写法。

版本兼容矩阵

API引入废弃推荐替代
router.pushUrlAPI 9API 18UIContext.getRouter().pushUrl
router.backAPI 9API 18UIContext.getRouter().back
promptAction.showToastAPI 9API 18UIContext.getPromptAction().showToast

从 API 9 到 API 18 跨越了 9 个版本,这意味着旧 API 经过了长时间的稳定运行才被标记废弃。开发者有充足的迁移窗口。

发现废弃 API

在 HarmonyKit 的开发过程中,发现废弃 API 的方式有三种:

  1. 编译器 warning:最直接的方式。每次编译时检查输出中的 deprecation warning。
  2. IDE 提示:DevEco Studio 会在代码中划掉废弃方法名(类似 strikethrough 效果)。
  3. 文档/Release Notes:每次 SDK 更新时查阅废弃 API 列表。

在实际开发中,"编译器 warning"是最可靠的发现方式。建议的做法是:每次构建后 grep 一下输出中的 “deprecated” 关键词。HarmonyKit 使用了这个方式——在一次编译后发现 router.pushUrl 被标记 deprecated,随即开始迁移。

迁移后的验证

API 迁移完成后,需要验证两个关键点:

  1. 编译验证:warning 是否消失?迁移后的代码是否正确无编译错误?
  2. 功能验证:跳转、返回、Toast 是否正常工作?

对于 HarmonyKit 的迁移,验证步骤非常简单:

  • hvigor clean && hvigor build— 确认 0 warning
  • 在模拟器中运行 — 点击每个工具的 ToolCard,验证跳转正常
  • 验证每个工具页的返回按钮
  • 验证每个工具页的 CopyButton(复制后 Toast 弹出)

完整的验证在 5 分钟内完成。迁移 + 验证总计约 20 分钟——这是"消除技术债"的最佳时间窗口:当你刚刚收到废弃 warning 时立即迁移,改动的范围最小,对代码的理解最清晰。

迁移时机

收到 deprecated warning → 立即迁移(改动小、风险低)。不要等到"代码里全是 warning 再统一清理"——那是技术债。

为什么提倡"立即迁移"而不是"统一清理"?原因有三:

  1. 认知成本:当时写下那段代码的开发者对上下文最熟悉。三个月后回来清理,需要重新理解代码。
  2. 改动量分散:一个 API 废弃时只有几处调用,修改集中。当十几个 API 一起废弃时,改动的文件可能互相关联,引入回归风险。
  3. 心理成本:"代码里有 50 个 warning"是一个让人不想启动的清理任务。但"代码里有 0 个 warning"是可以长期保持的状态。

通用版本兼容策略

对于大型项目,建议建立一个"API 兼容性检查清单":

  • 收到废弃 warning 后,在项目文档中登记
  • 评估影响范围(几个文件?几个调用点?)
  • 安排迁移时间(立即 / 本周 / 下个迭代)
  • 迁移后验证功能 OK
  • 从文档中移除

项目仓库:https://atomgit.com/VON-/harmony-kit