移动端性能优化只打三场硬仗:启动耗时、包体积、渲染稳定性。本文给出启动三段拆解与对应手段、包体积五项清单,以及 Android/iOS 双端卡顿排查路径与防劣化门禁。
移动端性能优化做了这么多年,真正决定用户体验的其实只有三件事:启动够不够快、包够不够小、滑动稳不稳。其余指标(CPU 占用、流量、耗电)大多由这三项派生。
本文按这”三场硬仗”给出可落地的排查路径与优化清单,覆盖 Android 与 iOS 双端。
一、第一仗:启动耗时
先把启动拆成三段,再谈优化——不拆分就优化,等于闭眼调参。

三段拆解与对应手段
最有效的一招:把 Application 里的初始化任务画成有向无环图。 按依赖关系分出”必须同步完成””可异步””可延迟到首屏后”三类,通常能砍掉一半以上的启动耗时。
// Android 侧典型的任务化启动器写法(示意)
TaskDispatcher.init(this)
.addTask(InitPushTask()) // 首屏必须
.addTask(InitLogTask()) // 可异步
.addTask(InitRecommendTask()) // 可延迟到 idle
.start()
二、第二仗:包体积
包体积直接影响下载转化率,是唯一能直接换算成钱的移动端性能指标。
- 资源是头号大户。 图片转 WebP/AVIF、按分辨率分发、移除未使用资源;
- 代码混淆与裁剪。 Android 侧开启 R8 并配置正确的 keep 规则,iOS 侧开启 dead code stripping;
- so 库按 ABI 分发。 不要打全架构的胖包,按渠道分发对应 ABI;
- 动态化与按需下载。 低频功能模块做成插件或动态特性模块;
- 建立体积预算门禁。 在 CI 里设置体积阈值,超阈值直接卡住合并。
经验法则:没有门禁的体积优化,三个版本内必然反弹。 把体积检查放进 CI,比任何一次性瘦身都有效。
三、第三仗:渲染稳定性
卡顿的本质是主线程在 16.6ms(120Hz 设备上只有 8.3ms)内没干完活。排查时盯住主线程,其余都是噪音。
Android 侧
- 用 Perfetto / System Trace 找主线程长任务,重点看
Choreographer#doFrame与锁等待; - 布局层级用 Layout Inspector 检查,嵌套过深改为 ConstraintLayout 或扁平化;
- 列表用 RecyclerView + 稳定 ID + 预取,避免在
onBindViewHolder里做耗时解析; - ANR 排查看
/data/anr/traces.txt,重点关注主线程是否被 Binder 调用或锁阻塞。
iOS 侧
- 用 Instruments 的 Time Profiler 与 Core Animation 模板定位掉帧;
- 避免主线程做图片解码,统一走后台解码再回主线程渲染;
- 圆角、阴影、离屏渲染要谨慎,能用裁剪解决的别用 maskToBounds;
- 自动布局约束数量过多会显著拖慢布局计算,复杂 Cell 考虑手动布局。
跨端方案额外注意
Flutter 关注 Shader 编译卡顿(预热着色器)与 build 方法里的重计算;React Native 关注桥接通信频率与列表项组件的重渲染。两者的共同点是:把重活移出 UI 线程,把刷新范围收窄到最小。
四、一份可执行的优化顺序
- 先埋点再优化。 没有分阶段的启动耗时上报、没有帧率监控,优化就是盲猜;
- 按影响面排序。 启动耗时看 P95 而非均值,卡顿看掉帧率而非平均帧率;
- 一次只改一类问题。 便于归因,也便于回滚;
- 固化成果。 把指标接入 CI 或灰度看板,防止劣化回归。
五、小结
移动端性能优化没有捷径,但有方法论:拆阶段、建度量、抓主线程、设门禁。启动、体积、渲染这三场硬仗打完,其余指标会自然改善。
最后提醒一句:优化的目标是可感知的体验提升,不是好看的数字。 用户能察觉的,只有冷启动那两秒和滑动那一下。
参考:Android 官方性能指南、Apple 性能调优文档。工具链与系统版本请以官方最新文档为准。
#移动端#性能优化#Android#iOS

