2025年12月21日·2 分钟

移动框架如何让跨平台应用更实用

了解移动框架如何在 iOS 与 Android 之间共享代码、加速开发,并处理 UI、原生功能、测试与长期维护等问题。

移动框架如何让跨平台应用更实用

什么是跨平台开发

跨平台开发是一种为 iOS 与 Android 构建移动应用的方法,而无需把所有东西都写两遍。与其用 Swift/Objective‑C 为 iPhone 写一个应用,再用 Kotlin/Java 为 Android 写另一个应用,不如从一个共享基础出发,为每个平台打包发布对应的应用。

“一个代码库,多款应用”——到底共享什么

人们常把跨平台总结为“写一次,到处运行”,但更现实的说法是“共享合理的部分”。典型的跨平台项目通常会共享大量:

  • 应用逻辑(屏幕行为、校验、导航规则)
  • 数据与网络(API 调用、缓存、同步)
  • 状态管理与业务规则
  • 有时也共享 UI 组件,视框架而定

但你无法完全逃避平台差异。即便有共享代码库,最终仍然是两个平台特定的应用:一个为 iOS 打包,一个为 Android 打包,每个都有自己的商店要求、设备怪癖和发布流程。

与完全原生开发的不同

在完全原生开发中,团队通常维护两个独立的代码库。这能最大化平台契合度,并直接访问每个系统的全部特性,但也会把许多工作加倍:同一个功能实现两次、保持行为一致、协调发布。

跨平台框架通过让你把功能写一次并跨平台重用来减少这种重复工作。

设定期望:并非 100% 可共享

有些应用能共享 70–90% 的代码;另一些共享得更少。自定义动画、复杂相机流程或深度 OS 集成可能需要平台特定实现。目标不是完全一致,而是在更短时间内交付一致的价值,同时保证 iOS 与 Android 的体验质量。

移动框架通常共享哪些内容

大多数跨平台移动框架围绕同一个核心承诺构建:你把应用的大部分写一次,框架帮助它在 iOS 与 Android 上以合适的外观、行为和设备访问能力运行。

共享的 UI 层(通常如此)

框架通常允许你在单一 UI 系统中构建屏幕、导航和可复用组件。你定义应用的流程(标签、堆栈、模态窗口),并在多个平台复用相同的屏幕结构,同时仍允许在必要时做平台级调整(例如不同的返回行为或间距)。

共享的业务逻辑

规则与工作流——表单校验、定价逻辑、权限检查、离线规则——通常与平台无关。这正是共享能快速见效的地方:更少重复决策、更少“在 Android 上能用但在 iOS 上不行”的差异,以及当需求变化时更简单的更新。

网络与数据处理

几乎每个框架都会提供标准方式来发起 API 调用、解析响应并处理基础缓存。你仍然会选择后端模式(REST、GraphQL 等),但与服务器通信和处理常见错误的机制往往可以跨平台复用。

通过桥接或插件处理平台特性

有些能力天生是原生的:相机访问、推送通知、支付、后台任务和生物识别。框架通常通过插件、模块或桥接层把这些原生 API 暴露给你的跨平台代码。

实际上,团队会把共享代码与少量平台特定代码混合使用——尤其是在高级支付、深度 OS 集成或严格合规需求下。

关键结论:虽然 UI 和逻辑通常可以共享,但对于任何紧密依赖 iOS/Android 系统行为的功能,都应该预期存在一层薄薄的平台特定工作。

框架如何在 iOS 与 Android 间处理 UI

跨平台应用仍需在 iOS 与 Android 上“看起来正确”:熟悉的导航模式、可读的排版和响应式布局。框架通过提供一套共享的 UI 构建块(按钮、列表、文本、布局容器)来解决这点——你把这些模块拼装成屏幕,一次性发布到两个平台。

共享构建块(屏幕与布局)

大多数框架鼓励把小的 UI 片段组合成更大的单元。你可以用行/列、堆栈、约束或类似 flex 的规则定义布局,框架会把这些翻译成适配不同设备尺寸的屏幕。

一个实用好处是统一性:团队可以创建可复用的组件库(输入、卡片、页眉)并在应用中重用,减少重复工作与 UI 偏移。

两种主要渲染方法

框架通常以两种方式渲染 UI:

  • 原生控件方式: 你的共享代码声明 UI,框架把它映射到平台的原生控件。这有助于应用更好地融入 iOS 与 Android 的约定。
  • 自绘方式: 框架自行绘制 UI(使用渲染引擎)以在各平台获得一致外观。这能更容易保持跨平台视觉一致性,减少平台特定的微调。

设计系统与可复用组件

如果你有品牌设计系统,跨平台框架能让你一次性实现设计 token(颜色、间距、排版)并在各处应用。你仍然可以在关键处加入“平台风味”——比如 iOS 风格的底部弹窗或 Android 风格的返回行为——而无需重写整个屏幕。

可访问性与本地化

好的 UI 处理不仅仅是视觉表现。框架通常提供钩子来支持:

  • 可访问性: 语义标签、焦点顺序、动态文本大小与屏幕阅读器支持
  • 本地化: 字符串资源、从右向左的布局以及基于区域的日期与数字格式化

把这些当作优先事项来尽早实现;后来补救会让跨平台 UI 工作变得昂贵。

访问原生设备功能

跨平台应用仍然需要“真实手机”能力:拍照、读取位置、使用 Face ID,或与蓝牙设备通信。移动框架通过在共享代码与每个平台原生 API 之间提供桥接来解决这个问题。

插件、桥接与平台 API

大多数框架通过插件(有时称为包或库)暴露设备功能。你的应用调用一个简单的共享接口,例如 getCurrentLocation,插件会把请求转发给 iOS 和 Android 上的原生代码。

在底层,桥接负责在框架运行时与 Swift/Objective‑C(iOS)或 Kotlin/Java(Android)之间转换数据与方法调用。优质插件会屏蔽平台差异,让团队主要在一个代码库中工作。

常见可访问功能

典型通过插件可访问的“原生”功能包括:

  • 相机与照片库
  • GPS / 定位服务
  • 通讯录与日历
  • 蓝牙(在 iOS 上常有额外限制)
  • 推送通知
  • 生物识别(Face ID / Touch ID / 指纹)
  • 安全存储(Keychain/Keystore)

可用性随框架与插件质量而异,因此在确定之前检查维护状态与平台支持很重要。

何时需要自定义原生模块

插件能覆盖很多需求,但当出现下列情况时你可能需要自定义原生模块:

  • 集成小众硬件 SDK(特殊扫描器、医疗设备)
  • 需要高级后台模式或操作系统特定行为
  • 插件存在但没有暴露关键设置或最新的 API

在这些情况下,你为 iOS 与 Android 添加小型原生封装,然后向共享层暴露清晰的方法。

安全基础:权限与安全存储

原生功能通常需要权限(相机、定位、蓝牙)。只请求必要权限,用简单明了的语言说明用途,并优雅地处理“被拒绝”情形。

对于敏感数据,避免使用普通偏好或文件。使用安全存储(通过框架的安全存储插件访问 iOS Keychain / Android Keystore),并尽量使令牌短期有效。

性能:应有的预期与如何衡量

性能主要体现在日常使用的“感觉”上:应用打开的速度、响应点击的流畅度,以及是否耗电。大多数现代跨平台框架能为典型业务应用提供良好体验——但你应知道性能的边界在哪里。

用户最先注意到的点

两个信号决定第一印象:

  • 应用启动时间: 从点按图标到看到可用界面的时间。启动慢常被归咎于框架,但通常是由于繁重的初始化、大包体或启动时过多网络调用造成的。
  • 滚动与动画平滑度: 卡顿的列表和不连贯的过渡会让应用显得劣质,即便功能完整。这通常与在主 UI 线程上做过多工作有关(例如昂贵的渲染、大图片或复杂布局)。

跨平台在哪些场景“足够好”(哪些场景敏感)

跨平台通常对内容类应用、表单、仪表盘、市场类与大多数 CRUD 产品绰绰有余

当你有以下需求时,性能则更敏感:

  • 重度图形、复杂 3D 或实时效果(游戏、AR、自定义绘制)
  • 视频编辑 / 音频处理或其他高计算任务
  • 非常大的列表,包含富单元、大量动态测量或频繁重渲染

在这些领域你仍可能用跨平台实现,但需要额外优化或为最关键路径编写原生模块。

电池使用与后台工作

电池问题很少在演示中出现,但用户会很快注意到。常见元凶包括频繁定位更新、激进轮询、喧闹的分析事件与后台定时器。

为后台行为设定清晰规则:同步频率、计划工作的条件,以及低电量模式下的行为。

如何衡量(避免凭感觉判断)

把性能当作一个功能,跟着检查表走:

  • 设定目标(例如“在中端设备冷启动 < 2 秒”、“关键界面 60 fps”)
  • 在真机上剖析,而非仅用模拟器——尤其是旧机型
  • 使用内置工具(Flutter DevTools、React Native 性能监测器、Android Studio Profiler、Xcode Instruments)
  • 在 CI 中自动化回归检测(可行时),并在重大 UI 变更后重新测试

如果你想要团队的实用工作流,把本节与 /blog/mobile-app-testing-basics 的测试策略结合起来。

常见框架选项(快速概述)

保持源码完全所有权
导出源码给现有移动团队,从原型无缝过渡到生产。

在评估跨平台开发时,了解框架的“主要类型”及其优化方向很有帮助。下面是快速概述,足以在深入比较前列出候选。

React Native

React Native 使用 JavaScript 或 TypeScript,并在底层渲染真实的原生 UI 组件。许多团队喜欢它,因为可以复用 Web 风格的开发技能,招聘池大,且能在 iOS 与 Android 间共享相当比例的代码库。

它适合希望获得近原生外观与感觉、拥有稳健第三方生态并需要快速迭代的产品团队。

Flutter

Flutter 使用 Dart,并用自己的渲染引擎绘制 UI,从而获得跨平台高度一致的界面。你通常能实现像素级的控制与统一的 UI 系统,这能简化设计实现并减少平台特定的惊喜。

当团队希望在 iOS 与 Android 上拥有统一视觉系统与可预测的 UI 行为时,Flutter 是常见选择。

Kotlin Multiplatform (KMP)

Kotlin Multiplatform 侧重于共享业务逻辑(网络、数据、规则),同时保留原生 UI在重要场景下的优势。如果你已有 Android 团队在用 Kotlin,或想保留平台原生体验而不复制“核心”逻辑,这很有吸引力。

Ionic + Capacitor

Ionic 用 Web 技术(HTML/CSS/JavaScript)构建应用,并通过 Capacitor 打包到移动平台。它通常适合类似 Web 产品的应用——仪表盘、表单、内容类体验——以及拥有强 Web 专长的团队。

Xamarin / .NET MAUI(也很常见)

如果你的组织大量投资于 Microsoft 工具链,.NET MAUI 可以用 C# 与 .NET 统一跨平台开发,并与企业生态深度集成。

如何为你的应用选择合适的框架

选择跨平台框架不是要找到“最好的”一个,而是要把工具与团队与产品目标匹配。适合营销应用的框架,可能并不适合硬件密集或对性能极度敏感的产品。

从团队优势入手

如果团队以 Web 为主,能复用 Web 技能的框架会降低上手时间。如果已有强 iOS/Android 工程师,你或许更愿意采用保持更多原生代码的方案。

  • Web 团队: 更快上手,但要验证所需原生 API 的可用性
  • 移动团队: 更易维护平台惯例并调试边缘问题
  • 混合团队: 选择在共享与原生模块之间边界清晰的框架

明确产品可接受的权衡

在首发版本需考虑的优先级:

  • 上市速度 vs 深度平台集成: 若早期需要大量设备特性,偏向桥接与插件生态成熟的框架
  • UI 预期: 需要平台原生外观(iOS 像 iOS、Android 像 Android)还是处处相同的 UI 以保障品牌一致性?

考虑第一版之后的影响

框架选择会影响招聘、维护与发布节奏多年。

  • 招聘: 在你的市场能否稳定招聘到该栈的开发者?
  • 维护: 升级是否可预期,社区是否活跃?
  • 发布节奏: 在 OS 版本变更时能否较快发布更新?

若想结构化比较,把选项列入得分卡并用小型原型验证假设。在规划发布流水线时,见 /blog/build-release-ci-cd-considerations。

成本、时间与维护的权衡

快速进行框架试验
生成一个关键界面和一个复杂设备集成,提前验证方案。

跨平台开发通常能节省时间与金钱,因为你不用在两端重复构建(与重构)相同功能。共享代码库能减少产品逻辑、网络、分析以至部分 UI 的重复工作——尤其是当 iOS 与 Android 屏幕相似时。

常见的节省点

最大节省通常在首释后显现。共享组件提升了跨平台一致性,因此设计调整(按钮样式、间距、空状态)只需修改一次并推广到所有平台。共享逻辑中的 Bug 修复同样可以惠及两端。

成本可能增加的地方

跨平台并不消除平台工作——它只是改变了工作的发生位置。当你需要复杂原生集成(蓝牙、后台服务、高级相机流水线、自定义 AR、专用支付流)时,成本可能上升。插件有帮助,但调试插件问题、版本不匹配与操作系统更新也会引入意外时间成本。

当应用在 UX 上必须在边缘场景做到“完美原生”时,也可能产生额外费用,需要平台特定的 UI 工作或单独流程。

规划现实预算

一种实用的做法是分阶段预算:

  • 里程碑 1:核心 MVP(最高价值流程、基础集成)
  • 里程碑 2:原生边缘场景(平台特有的打磨、复杂权限、后台行为)
  • 里程碑 3:扩展与维护(重构、依赖升级、长期支持)

通过事先定义“必须有”的集成与把“锦上添花”的设备功能留到后面,可以使时间线更可预测,并在 iOS 与 Android 演进时保持可维护性。

测试跨平台应用

跨平台并不意味“测试一次,处处可用”。它意味着你可以重用很多测试(尤其是共享业务逻辑),但仍需证明 UI 在 iOS 与 Android 上都表现正确。

针对共享逻辑的单元测试

先对你希望共享的代码做单元测试:定价规则、校验、离线同步决策、格式化与 API 解析。这些测试要跑得快并在每次提交时执行。

一个实用规则:如果某个 bug 人工发现代价高(边缘情况、时区、货币、重试),就把它放进单元测试。

在真机与模拟器上的 UI 测试

UI 问题是平台分歧最多的地方:导航手势、键盘行为、权限提示和细小的布局差异。混合使用:

  • 模拟器/仿真器 用于开发期间和 CI 的快速反馈
  • 真机 用于相机、生物识别、蓝牙、推送通知、性能和厂商特有的问题

把 UI 测试聚焦在关键流程(注册、结账、核心任务完成),以保持稳定性并提供有效信号。

设备矩阵规划

与其“测试所有”,不如规划一个基于用户的矩阵:

  • 系统版本: 当前版本 + 每个平台至少一个较旧的主版本
  • 屏幕尺寸: 一个小屏、一个中屏、一个大屏(以及若支持则至少一台平板)
  • 厂商: 包含 1-2 个常见 Android 品牌,因为它们的系统 UI 与省电策略可能不同

每月复查分析数据,并根据真实采纳情况调整矩阵。

崩溃上报与分析基础

在测试阶段就加入崩溃上报,它是无法重现设备特定故障的安全网。

监控:

  • 崩溃自由用户/会话比例
  • 顶级崩溃的 OS 与设备型号
  • 应用启动时间与慢界面(基本性能面包屑)

结合轻量分析来验证修复是否真实改善了用户路径,而不仅仅是测试结果。

构建、发布与 CI/CD 注意事项

跨平台代码库简化了日常开发,但发布仍需产出两个原生应用。提前规划构建与发布流程可以避免临近发布时的“在我机器上能跑”问题。

一个仓库,两条自动化构建通道

大多数团队保留单一仓库并运行两条 CI 流水线:一条产出 Android App Bundle(AAB),一条产出 iOS 存档(IPA)。应用代码可共享,但构建步骤不同——Android 用 Gradle,iOS 依赖 Xcode。

实用基线:在每次 pull request 上运行 lint + 单元测试,合并到主分支时构建签名产物。把 CI 配置放在仓库中,以便与应用一起演进。

签名、证书与应用商店提交

签名是最常见的发布阻塞点。

Android 管理 keystore 并上传密钥(通常通过 Google Play App Signing),iOS 管理证书、描述文件与 App Store Connect 权限。

商店密钥应存放在 CI 的密钥管理器中,而非仓库里。定期轮换凭据,并记录谁可以访问它们。

环境设置:开发、预发、生产

把环境当作一等公民:不同的 API 端点、特性开关、分析密钥和推送凭证。许多团队会通过 TestFlight 和 Play 内部通道向内部测试人员发布“预发”构建,生产环境则严控。

版本控制与发布说明

在两端都使用清晰的版本策略。一种常见做法是:

  • 统一的市场版本(例如 2.3.0)
  • 单独的平台构建号(iOS 需要)

自动从合并的 PR 生成变更日志,再在提交前完善人工可读的发布说明。这让发布更可预测并便于审计。

风险与缓解方法

通过聊天原型化应用
通过聊天为跨平台应用创建原型,在选择框架前快速迭代。

跨平台框架能省去大量重复工作,但也会引入一些可预见的风险。好消息是:大多数风险如果早做规划都是可控的。

插件更新与依赖漂移

许多应用依赖第三方插件(相机、支付、分析)。随着时间推移,这些插件可能落后于框架或操作系统。

实用做法是把依赖当作维护流:

  • 固定版本并按计划升级(月度/季度),而不是“出问题再升级”
  • 偏好被广泛使用且活跃维护的插件(最近有发布、问题有人响应)
  • 用小型 spike 分支在合并前测试框架升级

改变 API 或权限的 OS 更新

iOS 与 Android 会定期收紧隐私、后台执行与权限流程。这些变化即便在你的代码未变时也可能导致功能中断。

降低意外的做法:

  • 在 Beta 窗口期在最新测试版系统上进行测试
  • 把权限检查封装在应用级服务中,以便在一个地方修复
  • 跟踪商店政策更新并为合规工作预留时间

代码组织:共享与平台文件夹

若平台特例散落各处,共享代码库会变得混乱。

目标是保持清晰边界:把大部分逻辑放在共享模块,把真正的原生代码放在平台文件夹,并通过小接口暴露(例如通知、生物识别)。这能保持共享层的整洁并加快原生修复速度。

文档与入职

跨平台团队常混合 Web、移动与后端技能。没有轻量文档时,入职速度会变慢。

维持一页短小的 README + 运行手册:如何运行应用、关键架构决策、原生代码位置、发布步骤与常见故障排查。即便只有一页也能显著缩短入职时间。

实用决策指南与下一步

选择跨平台方案主要是把你应用的“形状”(UI、性能需求、设备访问、团队技能)与框架的长处匹配起来。

简单决策检查清单

问自己并记录非可谈判项:

  • UI 期望: 需要像素级平台原生 UI,还是统一自定义 UI 可接受?
  • 设备功能: 是否大量依赖蓝牙、NFC、AR、后台服务或复杂通知?
  • 性能敏感度: 应用是否动画密集、实时或做大量本地计算?
  • 团队与招聘: 现有强项是 JavaScript、Dart 还是 .NET?
  • 发布速度: 你多久发布一次,跨平台共享对你有多重要?
  • 长期维护: 谁会在 18–36 个月内维护它,对工具链是否熟悉?

示例场景(通常可行的选择)

MVP: 共享代码库往往是最快路径。优先提升开发速度与快速迭代回路。

企业应用: 若需要与现有 .NET 系统深度集成与结构化工具链,Xamarin/.NET MAUI 常被选中。若需共享业务逻辑但保留原生 UI,可考虑 Kotlin Multiplatform。

内容类应用: 若 UI 主要是列表、信息流与表单,大多数框架表现都很好——选择团队能稳定交付与维护的堆栈。

硬件密集型应用: 若依赖底层设备 API 或专用 SDK,规划为混合方案(共享核心 + 原生模块)或在可靠性与功能深度高于代码共享时选择完全原生

下一步

  1. 写一页需求摘要(主要屏幕、关键设备特性、性能风险)。

  2. 开发一个小型 spike(一个关键屏 + 一项最难的原生集成)再做决定。

  3. 若想更快压缩 spike 周期,可以考虑在 Koder.ai 使用 vibe-coding 工作流,从聊天生成原型。团队常用它生成可工作的 React Web 前端、Go + PostgreSQL 后端,甚至 Flutter 移动脚手架,然后把源码导出给传统移动团队去打磨平台特性。快照与回滚在尝试不同框架或插件集成时尤其有用。

  4. 想看更多示例与对比,浏览 /blog。若你需要估算预算与时间表,见 /pricing。

常见问题

什么是跨平台移动开发?

跨平台开发是指从一个共享基础构建 iOS 和 Android 应用,而不是维持两个完全独立的代码库。

在实践中,你通常会共享业务逻辑、网络/数据以及常见的 UI 组件——然后仍然生成两个平台特定的构建(iOS 的 IPA、Android 的 AAB),并分别遵循各自的应用商店与操作系统要求。

跨平台真的能做到“写一次,到处运行”吗?

更准确地说是**“分享合理的部分”。许多团队对典型产品类应用能共享大约70–90%** 的代码,但剩下的部分通常包括:

  • 平台特定的集成(权限、后台行为)
  • 边缘场景的 UI 差异(导航模式、系统控件)
  • 原生 SDK 包装(支付、硬件、合规相关功能)
跨平台框架通常会共享应用的哪些部分?

大多数框架会共享:

  • 业务逻辑: 校验、工作流、状态管理
  • 网络/数据: API 调用、解析、缓存模式
  • 应用结构: 导航规则与屏幕流程
  • UI 组件: 有时可以完全共享,有时只共享部分

“最后一公里”通常是平台特定的打磨和原生集成。

跨平台框架如何在 iOS 与 Android 上处理 UI?

框架通常以两种方式之一呈现 UI:

  • 原生控件映射: 共享代码映射到平台的原生控件(通常更有“原生”感)。
  • 自绘方式: 框架自己绘制 UI,以在各平台上实现一致的视觉效果。

你选的方式会影响需要调校的平台差异程度,以及 iOS/Android 之间外观的一致性。

跨平台应用如何访问相机和生物识别等原生设备功能?

它们通过插件/桥接暴露原生 API 的方式来实现。应用调用类似 getCurrentLocation 的统一接口,插件会在 iOS(Swift/Objective‑C)和 Android(Kotlin/Java)上执行相应的原生代码。

当现成插件无法满足需求时,你可以编写自定义原生模块,并在共享层暴露小而清晰的接口。

通常什么时候即便有共享代码库也需要平台特定代码?

当:

  • 你需要小众硬件 SDK(扫描器、医疗设备)
  • 依赖高级后台模式或操作系统特殊行为
  • 插件存在但滞后于操作系统更新或缺少关键选项

常见模式是“共享核心 + 原生包装”,大部分应用保持跨平台,难点隔离在原生模块中。

跨平台应用的性能如何,应如何衡量?

关注用户感受的指标:

  • 启动时间: 避免在启动时做大量初始化或太多网络请求
  • 流畅度: 把昂贵工作移出 UI 线程;优化列表与图片加载
  • 电池: 注意后台定时、定位频率与频繁轮询

设定目标(例如在中端设备上冷启动小于 2 秒、关键界面达到 60 fps),并使用真机透过工具(Xcode Instruments、Android Studio Profiler 以及框架自带的分析工具)进行剖析。

常见的跨平台框架有哪些,它们有何差异?

实用的候选清单:

  • React Native: JavaScript/TypeScript,渲染真实原生 UI 组件,生态成熟
  • Flutter: Dart,自绘渲染引擎,跨平台视觉一致性强,像素级控制
  • Kotlin Multiplatform (KMP): 共享业务逻辑,同时保持原生 UI
  • Ionic + Capacitor: 基于 Web 技术(HTML/CSS/JS),适合表单和内容类应用
  • .NET MAUI: 适合已有 Microsoft/.NET 投资的组织

最佳选项取决于 UI 期望、原生能力需求与团队技能。

如何为我的应用选对跨平台框架?

使用一个简易评分卡来决策:

  • 团队技能: 偏 Web 还是偏移动原生?
  • UI 目标: 需要平台原生体验,还是希望处处一致?
  • 原生特性需求: 是否依赖蓝牙、NFC、后台服务等
  • 长期维护: 升级节奏、生态健康和招聘可行性

在最终决定前,做一个小型原型:一个关键屏幕 + 一个最难实现的原生集成。

跨平台应用是否需要在 iOS 和 Android 分别测试?

不——两端都要测试。

实用方法:

  • 大量对共享逻辑做单元测试(规则、解析、离线决策)
  • 在模拟器/真机上运行 UI 测试,并把关注点放在关键流程(注册、结账、核心任务)
  • 基于分析数据定义设备/系统矩阵(而不是凭空猜测)
  • 尽早加入崩溃上报,捕获无法复现的设备特定故障

这样既能保证共享代码质量,也能验证 iOS/Android 的差异。

Related posts