Flutter 包体积优化实战:减少 APK/IPA 大小

0 阅读4分钟

Flutter 包体积优化实战:减少 APK/IPA 大小

Flutter 应用在发布时,包体积是用户最直观的感受之一。过大的包会增加用户下载的门槛,影响转化率。本文系统梳理 Flutter 包体积优化的可落地方案。


一、分析包体积的工具

1.1 使用 --analyze-size 分析

# Android 分析
flutter build apk --release --analyze-size

# iOS 分析(需要先 build)
flutter build ios --release --analyze-size

# 分析结果会生成一个 .json 文件,用 DevTools 查看
flutter pub global run devtools --appSizeBase=build/flutter-size-analysis_xxx.json

1.2 使用 flutter build apk --split-per-abi

# 按 ABI 拆分 APK,减少每个 APK 的体积
flutter build apk --release --split-per-abi

# 生成的文件:
# app-armeabi-v7a-release.apk  (约 减少 30%)
# app-arm64-v8a-release.apk   (约 减少 30%)
# app-x86_64-release.apk      (模拟器用)

二、移除未使用的资源

2.1 移除未使用的图标

检查 pubspec.yaml 中声明的资源是否都有使用:

# ❌ 避免:声明整个目录(会打包所有文件)
flutter:
  assets:
    - assets/images/

# ✅ 推荐:只声明需要的文件
flutter:
  assets:
    - assets/images/logo.png
    - assets/images/placeholder.png

2.2 使用 --track-widget-creation 移除未使用的 Widget

# 发布构建时默认启用,确保没有关闭
flutter build apk --release
# 不需要额外参数,默认会 tree-shake 未使用的 Widget

三、图片优化

3.1 使用 WebP 格式

WebP 格式比 PNG/JPG 小 25-35%:

# 批量转换 PNG 到 WebP(需要安装 WebP 工具)
# 下载:https://developers.google.com/speed/webp/docs/precompiled

# 转换单张图片(有损,质量 80)
cwebp -q 80 input.png -o output.webp

# 批量转换(Linux/macOS)
for file in assets/images/*.png; do
  cwebp -q 80 "$file" -o "${file%.png}.webp"
done

# 批量转换(Windows PowerShell)
Get-ChildItem "assets\images\*.png" | ForEach-Object {
  cwebp -q 80 $_.FullName -o ($_.FullName -replace '\.png$', '.webp')
}

3.2 使用 flutter_image_compress 压缩网络图片

# pubspec.yaml
dependencies:
  flutter_image_compress: ^2.1.0
import 'package:flutter_image_compress/flutter_image_compress.dart';

Future<Uint8List?> compressImage(File file) async {
  final result = await FlutterImageCompress.compressWithFile(
    file.absolute.path,
    minWidth: 1024,
    minHeight: 1024,
    quality: 80,
    format: CompressFormat.jpeg,
  );
  return result;
}

四、代码优化

4.1 使用 @pragma('vm:entry-point') 避免混淆问题

// 如果使用了混淆,确保反射调用的类不被 tree-shake
@pragma('vm:entry-point')
class MyReflectionClass {
  final String name;
  MyReflectionClass(this.name);
}

4.2 启用代码混淆(Android)

// app/build.gradle
android {
    buildTypes {
        release {
            minifyEnabled true      // 启用代码混淆
            shrinkResources true    // 移除未使用的资源
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

proguard-rules.pro:

# 保留 Flutter 相关类
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }

# 保留 JSON 序列化类(如果使用了 json_serializable)
-keep class com.example.app.models.** { *; }
-keepattributes *Annotation*

五、字体优化

5.1 只打包需要的字体字形

如果使用了中文字体,字体文件可能非常大(3-10MB)。

方案1:使用 flutter_font_otf 裁剪字体

# 安装 fonttools
pip install fonttools brotli

# 裁剪字体(只保留用到的字形)
pyftsubset font.otf --text="你需要的字符" --output-file=font.subset.otf

方案2:使用 flutter_launcher_icons 时将图标字体替换为图片

# 如果使用了 iconfont,考虑替换为 svg/png
# flutter_svg 支持 SVG,体积比 iconfont 小

六、Gradle 配置优化(Android)

6.1 启用 Resource 缩减

// app/build.gradle
android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true  // 缩减资源
            
            // 指定需要保留的资源
            resValue "string", "app_name", "My App"
        }
    }
    
    // 启用构建缓存
    buildCache {
        local {
            enabled = true
        }
    }
}

6.2 使用 AAB(Android App Bundle)

# AAB 格式可以让 Google Play 按需下发资源,减少用户下载大小
flutter build appbundle --release

# 上传到 Google Play 时,Google Play 会为每台设备生成最优的 APK
# 平均减少 20-30% 的下载大小

七、iOS 包体积优化

7.1 启用 Bitcode(已废弃,但可以做其他优化)

# iOS 构建时启用 Release 模式优化
flutter build ios --release

# 在 Xcode 中:
# 1. 设置 Build Settings → Swift Compiler - Optimization Level → Release → Optimize for Speed [-O]
# 2. 设置 Build Settings → Dead Code Stripping → Yes
# 3. 设置 Build Settings → Strip Debug Symbols During Copy → Yes

7.2 移除未使用的架构

# ios/Podfile 中添加
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      # 只保留 arm64 架构(iOS 14+ 不需要 armv7)
      config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386'
    end
  end
end

八、优化效果对比表

优化手段预计减少体积实施难度优先级
--split-per-abi30%P0
图片转 WebP25-35%P0
启用混淆 + 资源缩减10-20%P1
使用 AAB 格式20-30%P1
字体子集化50-80%(字体文件)P2
移除未使用资源5-15%P1

九、检查清单

完成包体积优化后,建议对照以下清单进行检查:

  • 已使用 --split-per-abi 或 AAB 格式发布
  • 所有图片已转换为 WebP 格式
  • 已启用代码混淆和资源缩减
  • 未使用的资源已从 pubspec.yaml 中移除
  • 中文字体已做子集化处理(如果使用了中文字体)
  • 使用 --analyze-size 分析了包体积构成
  • Release 包体积 < 20MB(Android)、< 30MB(iOS)

十、参考资源


如果本文对你有帮助,欢迎点赞收藏。如果你有更好的包体积优化方案,欢迎在评论区分享。