我们将 Shop 应用从 React Native 迁移到了 Swift 和 Kotlin。在 AI 的辅助下,团队仅用 12 周时间就从概念验证阶段推进到完全重建的原生应用并发布到应用商店。

作为全球增长最快的移动应用之一,Shop 应用服务于数亿客户和数百万商家。自 2020 年推出以来,Shop 应用一直处于 Shopify 对 React Native 广泛投资的前沿,从框架诞生之初就采用了它。这一决策对 Shop 应用来说效果良好,但我们在使用编码智能体进行开发方面的能力不断增强,使得 Shop 能够完全转向原生开发,使用 Swift 和 Kotlin 构建。
我们曾深入撰文讨论过转向原生开发的决定,但简而言之,编码智能体的进步改变了维护共享移动代码库背后的权衡。为 iOS 和 Android 分别构建仍然有成本,但智能体让重新考虑这一决定变得合理。
对于 Shop 应用而言,这与我们下一项重大的 React Native 投资恰好重合:采用新架构(New Architecture)。这项工作需要我们重新审视原生模块集成、渲染以及共享代码与平台特定代码之间的边界。在投入这项工作之前,我们测试了编码智能体是否能帮助我们在 SwiftUI 和 Jetpack Compose 中直接构建,同时保持各平台产品行为一致。
在决定进行全面迁移之前,我们进行了一个小型概念验证。一名工程师花了一周时间与编码智能体合作,尽可能多地将现有的 React Native 应用迁移到使用 SwiftUI 构建的原生 iOS 应用中。
结果令人信服。以现有的 React Native 应用为参考,我们能够快速重建屏幕、交互和应用流程。仅仅一周后,结果虽然还未达到生产就绪的标准,但它证明了逐功能紧密迁移是可以实现的,并给了我们进行完整迁移的信心。
当智能体有现有实现可供参考时,它们尤其高效。它们移植已定义的功能、搭建屏幕脚手架、连接数据、实现动画,并根据视觉反馈优化布局。
在做出迁移决定后,一个由六名工程师组成的核心团队构建了原生基础和应用的主要用户旅程。功能团队在迁移中途加入,验证各自负责的领域并覆盖边缘情况。我们的首要任务是保持所移植功能的行为以及下游系统所依赖的分析事件。

迁移需要让现有用户感觉像是一次正常的应用更新:他们应保持登录状态并继续接收推送通知。交互还需要发出预期的事件,并携带下游系统(如推荐系统)所需的上下文。在保持这种连续性的同时,我们也利用迁移来简化应用,有意淘汰了一些屏幕并精简了其他屏幕。
我们在启动时间、会话稳定性、应用大小、构建时间和渲染性能方面,将原生应用与其 React Native 前身进行了比较。
这些录屏比较了原生 iOS 和 Android 应用与其 React Native 对应版本的冷启动。时间从点击应用图标开始,直到初始主页信息流内容可见为止。


| 平台 | 原生 | React Native | 启动时间减少 | | --- | --- | --- | --- | | iOS | 2466 ms | 3200 ms | 23% | | Android | 2233 ms | 4433 ms | 50% |
原生版本记录的稳定性率高于 React Native。我们历史上的稳定性为 99.5%+,但随着原生版本的发布,我们的会话稳定性已攀升至 99.95%+——崩溃会话减少了 10 倍。
原生 Android 发布版本比其 React Native 对应版本小得多,缩减了 109 MB。在 iOS 上,发布版本大小相似,增加了 1 MB。
| 平台 | 原生 | React Native | 差异 | | --- | --- | --- | --- | | iOS | 68 MB | 67 MB | +1 MB (+1.5%) | | Android | 184 MB | 293 MB | −109 MB (−37.2%) |
Android 发布构建时间下降了约 75%。在 iOS 上,发布构建所需时间大致相同。构建时间改进的好处包括能够更快地测试新构建,以及消耗更少的计算时间。
在这段录屏中,原生 Android 应用在 Pixel 设备上滚动信息流并在屏幕间导航时达到了 120 FPS。到目前为止,这仅通过极少的优化就实现了,凸显了性能上的关键改进。

智能体开发工作流与传统工作流不同。我们不再让一名开发者进行更改、运行应用并迭代,而是经常在独立的 worktree 中运行多个智能体会话。对于这次迁移,我们专注于为智能体提供清晰的任务、保持快速的构建和测试循环,并频繁审查更改。
我们构建了一个可复用的迁移工作流,作为 Pi 编码智能体的扩展。专门的子智能体检查 React Native 源代码、记录其行为、准备平台计划、实现功能并审查一致性。源代码审查涵盖了 UI、状态、导航、分析、可访问性和数据行为。工程师在继续实施之前审查需求和计划。计划接受与其内容的哈希绑定:更改计划会使其先前的接受失效。这确保了批准与实际已审查的实施计划保持一致。

智能体还需要来自运行中应用的反馈。我们构建了 Tardis,这是一个调试工具,为它们提供对实时原生应用事件、日志和状态的结构化访问,以及向应用发送命令的能力。智能体可以利用这些反馈来调查问题、检查导航和分析,并以更少的手动 UI 检查来验证修复。

为了支持一致性审查,我们添加了一个 Tardis 功能,在命名检查点从 React Native 和原生应用捕获屏幕截图和事件窗口。启用原始事件捕获后,智能体可以比较事件名称、计数和负载字段。比较指令考虑了运行之间自然不同的值,如时间戳和页面 UUID,同时检查事件与其页面或实体上下文之间的关系。这为我们的工程师提供了一种可重复的方式来调查他们所执行流程中的差异。
原生专业知识仍然至关重要。生成的代码可以满足功能需求,同时仍可能引入重复、架构漂移或性能问题。仓库指南有所帮助,同时还有 linting、测试、静态分析、性能检查和代码审查。
尽管如此,学习曲线比我们预期的更可控:熟悉的声明式 UI 概念帮助 React Native 工程师在 SwiftUI 和 Jetpack Compose 中变得高效,而平台知识指导了我们的架构决策和审查。我们 Avatar 组件的简化版本说明了这种共享结构。
在进行这次迁移时,我们确立的关键原则之一是 Android 和 iOS 必须始终保持功能对等。React Native 通过共享代码库强制执行了这一点,现在我们采用原生开发,将继续通过我们的开发和发布流程来强制执行这一点。
我们知道在性能方面仍有更多打磨和改进的空间。这第一个版本提升了我们作为移动应用所能达到的上限,我们将其视为我们将在此基础上改进的基线。随着我们继续演进我们的工具和开发流程,我们希望未来能在这里分享更多经验。
转载声明:本文为转载整理,原文版权归原作者及原站点所有。
原文来源:Shopify Engineering
原文作者:Shopify Engineering;如有侵权,请联系管理员删除。