公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

Flutter 包体积优化详解

简介

应用包体积直接影响用户下载意愿。本文介绍如何优化 Flutter 应用的包体积大小。

分析工具

1. Flutter 分析工具

bash
# 分析 APK
flutter build apk --analyze-size

# 分析 iOS 包
flutter build ios --analyze-size

2. Android Studio

groovy
android {
    buildTypes {
        release {
            // 启用 APK 分析
            minifyEnabled true
            shrinkResources true
        }
    }
}

优化方法

1. 资源优化

yaml
# pubspec.yaml
flutter:
  assets:
    # 只包含必要资源
    - assets/images/
    - assets/icons/
    
  fonts:
    # 只包含使用的字重
    - family: Roboto
      fonts:
        - asset: fonts/Roboto-Regular.ttf
        - asset: fonts/Roboto-Bold.ttf
          weight: 700

2. 代码优化

dart
// 1. 移除未使用的导入
import 'package:flutter/material.dart';
// import 'package:unused_package/unused.dart'; // 删除

// 2. 使用 const 构造函数
const MyWidget({Key? key}) : super(key: key);

// 3. 延迟加载
late final heavyWidget = FutureBuilder(
  future: _loadHeavyWidget(),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return snapshot.data as Widget;
    }
    return CircularProgressIndicator();
  },
);

3. 依赖优化

yaml
dependencies:
  # 使用精确版本
  package_name: 1.0.0
  
  # 使用范围版本
  another_package: '>=2.0.0 <3.0.0'
  
  # 按需导入
  big_package:
    path: packages/big_package
    include: ['lib/core.dart']

完整示例

dart
// 1. 图片优化工具
class ImageOptimizer {
  static Future<File> optimizeImage(File imageFile) async {
    final img = await decodeImageFromList(
      await imageFile.readAsBytes(),
    );
    
    // 压缩图片
    final compressedData = await FlutterImageCompress.compressWithList(
      await imageFile.readAsBytes(),
      minHeight: 1920,
      minWidth: 1080,
      quality: 85,
    );
    
    // 保存压缩后的图片
    final optimizedFile = File(
      imageFile.path.replaceAll('.jpg', '_optimized.jpg'),
    );
    await optimizedFile.writeAsBytes(compressedData);
    
    return optimizedFile;
  }
}

// 2. 资源管理器
class AssetManager {
  static final Map<String, ImageProvider> _imageCache = {};
  
  static ImageProvider getImage(String name) {
    if (_imageCache.containsKey(name)) {
      return _imageCache[name]!;
    }
    
    final image = AssetImage('assets/images/$name');
    _imageCache[name] = image;
    return image;
  }
  
  static void clearCache() {
    _imageCache.clear();
  }
}

// 3. 延迟加载管理器
class LazyLoadManager {
  static final Map<String, Future<dynamic>> _loadTasks = {};
  
  static Future<T> load<T>(
    String key,
    Future<T> Function() loader,
  ) async {
    if (_loadTasks.containsKey(key)) {
      return await _loadTasks[key] as T;
    }
    
    final task = loader();
    _loadTasks[key] = task;
    return await task;
  }
  
  static void clear() {
    _loadTasks.clear();
  }
}

// 4. 优化后的应用示例
class OptimizedApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // 移除调试标签
      debugShowCheckedModeBanner: false,
      
      // 只包含使用的语言
      supportedLocales: [
        Locale('en', ''),
        Locale('zh', ''),
      ],
      
      // 延迟加载页面
      home: FutureBuilder(
        future: LazyLoadManager.load(
          'home_page',
          () => Future.delayed(
            Duration(milliseconds: 100),
            () => HomePage(),
          ),
        ),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return snapshot.data as Widget;
          }
          return SplashScreen();
        },
      ),
    );
  }
}

打包配置

Android

groovy
android {
    buildTypes {
        release {
            // 启用混淆
            minifyEnabled true
            // 移除未使用资源
            shrinkResources true
            // 优化 Dex
            proguardFiles getDefaultProguardFile(
                'proguard-android-optimize.txt'
            ),
            'proguard-rules.pro'
        }
    }
    
    // 启用 R8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

iOS

ruby
# Podfile
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      # 启用 bitcode
      config.build_settings['ENABLE_BITCODE'] = 'YES'
      # 优化编译
      config.build_settings['COMPILER_INDEX_STORE_ENABLE'] = 'NO'
    end
  end
end

最佳实践

  1. 优化资源文件
  2. 移除未使用代码
  3. 合理使用依赖
  4. 启用代码压缩
  5. 实施延迟加载

注意事项

  1. 保持资源质量
  2. 测试优化效果
  3. 监控包大小
  4. 平衡性能和大小
  5. 注意兼容性

总结

包体积优化需要从多个方面入手,包括资源优化、代码优化、依赖管理等。通过合理的优化措施,可以显著减小应用的包体积。