Smart Assets Plugin

智能资源下载插件 - 支持图片压缩、远端下载、智能切换、增量更新、分块下载的 Flutter 资源优化方案。

特性

✅ 包体积优化: 压缩图片减小 70-80% 体积
✅ 智能下载: ZIP 包下载或增量更新,自动选择最优方案
✅ 智能切换: 自动使用高清资源,降级到压缩资源
✅ 增量更新: 基于文件哈希的增量更新,节省流量
✅ 分块下载: 按优先级分组下载,大文件分片下载
✅ 断点续传: 大文件支持断点续传,避免重复下载
✅ 通用加载器: 灵活的通用加载器,支持任意类型资源

快速开始

1. 安装依赖

dependencies:
  smart_assets_plugin:
    path: sdk/smart_assets_plugin

2. 初始化配置

dart run smart_assets_plugin:init_config

编辑生成的 smart_assets_config.yaml 配置文件。

3. 构建资源

# 增量构建(默认,只处理变化的文件)
dart run smart_assets_plugin:build_all

# 全量构建(重新处理所有文件)
dart run smart_assets_plugin:build_all --full

4. 初始化插件

import 'package:smart_assets_plugin/smart_assets_plugin.dart';
import 'package:your_app/core/assets/generated_assets.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  await SmartAssetsPlugin.initialize(
    config: GeneratedAssets.config,
    autoDownload: true,
  );
  
  runApp(MyApp());
}

使用示例

3.1 基本使用

最简单的图片加载:

SmartAssetImage(
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  width: 100,
  height: 100,
)

3.2 高阶使用

高清资源自动下载

在 manifest.json 中配置高清资源:

{
  "assets": [
    {
      "path": "icons/home.png",
      "hdUrl": "https://cdn.example.com/hd/icons/home.png",
      "hdAutoDownload": true
    }
  ]
}

使用组件(自动从 manifest 读取配置):

SmartAssetImage(
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  width: 100,
  height: 100,
  fit: BoxFit.cover,
  placeholder: CircularProgressIndicator(),
  errorWidget: Icon(Icons.error),
)

状态监听

final plugin = SmartAssetsPlugin.instance;

// 监听下载状态
plugin.downloadStatus.addListener(() {
  final status = plugin.downloadStatus.value;
  print('下载状态: $status');
});

增量更新

final plugin = SmartAssetsPlugin.instance;

// 检查是否有更新
final hasUpdate = await plugin.checkForIncrementalUpdate();

if (hasUpdate) {
  // 执行增量更新
  await plugin.performIncrementalUpdate(
    onProgress: (phase, progress, description) {
      print('[$phase] ${(progress * 100).toStringAsFixed(1)}%');
    },
  );
}

通用资源加载器

// 加载 JSON 文件
SmartAssetLoader<Map<String, dynamic>>(
  assetPath: 'assets/data/config.json',
  resolver: SmartAssetsPlugin.instance.resolver,
  loader: (resolvedPath) async {
    final text = await SmartAssetsPlugin.instance.resolver
        .loadString('assets/data/config.json');
    return jsonDecode(text) as Map<String, dynamic>;
  },
  builder: (context, data) {
    return Text('Version: ${data['version']}');
  },
  placeholder: CircularProgressIndicator(),
  errorWidget: Icon(Icons.error),
)

3.3 全部参数

SmartAssetImage 完整参数

SmartAssetImage(
  // 必需参数
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  
  // 尺寸参数
  width: 100.0,
  height: 100.0,
  fit: BoxFit.cover,
  scale: 1.0,
  
  // 样式参数
  color: Colors.blue,
  colorBlendMode: BlendMode.srcIn,
  alignment: Alignment.center,
  repeat: ImageRepeat.noRepeat,
  
  // UI 参数
  placeholder: CircularProgressIndicator(),
  errorWidget: Icon(Icons.error),
  fadeDuration: Duration(milliseconds: 300),
  
  // 配置参数
  uiConfig: UIConfig(
    showDownloadProgress: true,
    showDownloadError: true,
  ),
)

参数说明:

  • assetPath (String, 必需): 资源路径,如 'assets/icons/home.png'
  • resolver (SmartAssetsResolver, 必需): 资源解析器,使用 SmartAssetsPlugin.instance.resolver
  • width (double?, 可选): 图片宽度
  • height (double?, 可选): 图片高度
  • fit (BoxFit?, 可选): 图片适配方式
  • scale (double, 可选): 图片缩放比例,默认 1.0
  • color (Color?, 可选): 图片颜色混合
  • colorBlendMode (BlendMode?, 可选): 颜色混合模式
  • alignment (AlignmentGeometry, 可选): 对齐方式,默认 Alignment.center
  • repeat (ImageRepeat, 可选): 重复方式,默认 ImageRepeat.noRepeat
  • placeholder (Widget?, 可选): 加载占位符
  • errorWidget (Widget?, 可选): 错误占位符
  • fadeDuration (Duration?, 可选): 淡入淡出动画时长
  • uiConfig (UIConfig?, 可选): UI 配置

SmartAssetLoader 完整参数

SmartAssetLoader<T>(
  // 必需参数
  assetPath: 'assets/data/config.json',
  resolver: SmartAssetsPlugin.instance.resolver,
  loader: (resolvedPath) async {
    // 加载资源的异步函数
    final bytes = await resolver.loadBytes(assetPath);
    return parseData(bytes);
  },
  builder: (context, data) {
    // 构建 UI 的函数
    return Widget(data);
  },
  
  // UI 参数
  placeholder: CircularProgressIndicator(),
  errorWidget: Icon(Icons.error),
  
  // 配置参数
  uiConfig: UIConfig(
    showDownloadProgress: true,
    showDownloadError: true,
  ),
)

参数说明:

  • assetPath (String, 必需): 资源路径
  • resolver (SmartAssetsResolver, 必需): 资源解析器
  • loader (Future
  • builder (Widget Function(BuildContext, T), 必需): 构建 UI 的函数
  • placeholder (Widget?, 可选): 加载占位符
  • errorWidget (Widget?, 可选): 错误占位符
  • uiConfig (UIConfig?, 可选): UI 配置

完整配置示例

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  await SmartAssetsPlugin.initialize(
    config: GeneratedAssets.config,
    autoDownload: true,
    loggingConfig: const LoggingConfig(
      enabled: true,
      level: 'debug',
      prefix: '[SmartAssets]',
    ),
  );
  
  runApp(MyApp());
}

构建脚本

build_all - 一键构建(推荐)

执行完整的资源构建流程。

使用方式:

# 增量构建(默认,只处理变化的文件)
dart run smart_assets_plugin:build_all

# 全量构建(重新处理所有文件)
dart run smart_assets_plugin:build_all --full
# 或
dart run smart_assets_plugin:build_all -f

执行步骤:

  1. 压缩图片资源(备份到 assets_backup/)
  2. 生成常量文件(lib/core/assets/generated_assets.dart)
  3. 生成 Manifest 文件(build/assets_release/manifest.json)
  4. 打包 ZIP 文件(build/assets_release/assets.zip)

参数说明:

  • --full 或 -f: 全量构建模式,重新处理所有文件(默认:增量构建)

init_config - 初始化配置

生成配置文件模板。

使用方式:

# 在项目根目录生成配置文件
dart run smart_assets_plugin:init_config

# 指定输出路径
dart run smart_assets_plugin:init_config /path/to/output.yaml

功能:

  • 在项目根目录生成 smart_assets_config.yaml
  • 包含所有配置项的详细说明
  • 如果文件已存在,会提示是否覆盖

compress_assets - 压缩资源

单独执行图片压缩。

使用方式:

# 增量压缩(默认,只处理变化的文件)
dart run smart_assets_plugin:compress_assets

# 全量压缩(重新处理所有文件)
dart run smart_assets_plugin:compress_assets --full
# 或
dart run smart_assets_plugin:compress_assets -f

功能:

  • 压缩 assets/ 下的图片资源
  • 原始图片备份到 assets_backup/
  • 生成 assets_mapping.json 资源映射文件
  • 支持增量压缩(只处理变化的文件)

参数说明:

  • --full 或 -f: 全量压缩模式,重新处理所有文件(默认:增量压缩)

generate_constants - 生成常量

生成资源路径常量文件。

使用方式:

dart run smart_assets_plugin:generate_constants

功能:

  • 生成 lib/core/assets/generated_assets.dart
  • 包含所有资源路径常量
  • 包含运行时配置对象(GeneratedAssets.config)
  • 包含内置资源和远程资源集合

generate_manifest - 生成清单

生成资源清单文件。

使用方式:

# 增量模式(默认,合并现有 manifest)
dart run smart_assets_plugin:generate_manifest

# 全量模式(重新生成 manifest)
dart run smart_assets_plugin:generate_manifest --full
# 或
dart run smart_assets_plugin:generate_manifest -f

# 显式指定增量模式
dart run smart_assets_plugin:generate_manifest --incremental
# 或
dart run smart_assets_plugin:generate_manifest -i

功能:

  • 生成 build/assets_release/manifest.json
  • 包含所有资源的路径、哈希、大小等信息
  • 支持增量模式(合并现有 manifest,保留手动配置)
  • 支持高清资源配置(hdUrl, hdAutoDownload)

参数说明:

  • --full 或 -f: 全量模式,重新生成 manifest(默认:增量模式)
  • --incremental 或 -i: 增量模式,合并现有 manifest

generate_zip - 打包ZIP

打包资源为 ZIP 文件。

使用方式:

dart run smart_assets_plugin:generate_zip

功能:

  • 将 assets_backup/ 下的资源打包成 ZIP 文件
  • 输出到 build/assets_release/assets.zip
  • 显示打包进度和统计信息

restore_assets - 还原资源

从备份目录还原原始资源。

使用方式:

# 交互式还原(需要确认)
dart run smart_assets_plugin:restore_assets

# 强制还原(不需要确认)
dart run smart_assets_plugin:restore_assets --force
# 或
dart run smart_assets_plugin:restore_assets -f

功能:

  • 从 assets_backup/ 还原所有原始文件到 assets/
  • 覆盖压缩后的文件
  • 显示还原进度和统计信息

参数说明:

  • --force 或 -f: 强制还原,不需要确认(默认:交互式确认)

注意:还原操作会覆盖当前 assets 目录中的压缩文件,建议在提交代码前使用。

replace_image_usage - 替换图片使用

自动替换项目中的 Image.asset() 和 AssetImage() 为插件组件。

使用方式:

# 交互式替换
dart run smart_assets_plugin:replace_image_usage

# 预览模式(不实际修改)
dart run smart_assets_plugin:replace_image_usage --dry-run
# 或
dart run smart_assets_plugin:replace_image_usage -d

功能:

  • 扫描指定文件夹下的所有 .dart 文件
  • 自动替换 Image.asset() → SmartAssetImage
  • 自动替换 AssetImage() → SmartAssetImageProvider
  • 自动添加必要的 import 语句

参数说明:

  • --dry-run 或 -d: 预览模式,不实际修改文件(默认:交互式替换)

替换示例:

// 替换前
Image.asset('assets/icons/home.png', width: 100, height: 100)

// 替换后
SmartAssetImage(
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  width: 100,
  height: 100,
)

配置说明

配置文件结构

主要配置项(smart_assets_config.yaml):

# 基础配置
enabled: true
version: "1.0.0"

# 远端配置
remote:
  base_url: "https://cdn.example.com/assets/"
  zip_name: "assets.zip"
  timeout: 300
  auto_download_on_wifi: true

# 资源分类
assets:
  builtin:  # 内置资源(保留在assets,同时打包到ZIP)
    - "audio/**"
    - "videos/**"
  remote:   # 远程资源(从assets删除,仅打包到ZIP)
    - "icons/**"
    - "images/**"
  target_dirs:  # 压缩目标目录
    - "icons"
    - "images"

# 增量更新
incremental:
  enabled: true
  cache_manifest_locally: true

# 分块下载
chunked_download:
  enabled: true
  chunk_threshold_mb: 10
  chunk_size_mb: 2
  enable_breakpoint_resume: true

# 优先级配置
priority:
  download_critical_first: true
  background_download_others: true

# 压缩配置
compression:
  quality: 30
  scale_ratio: 0.8
  skip_size_kb: 50
  skip_extensions:
    - ".gif"
    - ".webp"

# 本地存储配置
storage:
  download_dir: "downloaded_assets"
  backup_dir: "assets_backup"
  mapping_file: "assets_mapping.json"
  hd_download_dir: "downloaded_assets_hd"

# 下载策略配置
download:
  max_retries: 3
  retry_delay_base: 2
  verify_integrity: true
  progress_callback_interval: 500

# 资源信息管理配置
asset_info:
  url: "https://cdn.example.com/assets/info.json"
  method: "json"
  post_data: ""

# 脚本配置
scripts:
  output_dir: "build/assets_release"
  constants_file: "lib/core/assets/generated_assets.dart"

高清资源配置

高清资源配置在 manifest.json 中,每个资源项可以配置:

{
  "assets": [
    {
      "path": "icons/home.png",
      "hash": "sha256:xxx",
      "size": 1024,
      "priority": "important",
      "builtin": true,
      "hdUrl": "https://cdn.example.com/hd/icons/home.png",
      "hdAutoDownload": true,
      "hdVersion": "1.0.0"
    }
  ]
}

配置说明:

  • hdUrl (String, 可选): 高清资源 URL
  • hdAutoDownload (bool, 可选): 是否自动下载高清资源,默认 true
  • hdVersion (String, 可选): 高清资源版本号

使用方式:

  • UI 组件自动从 manifest 读取配置,无需手动传参
  • 如果配置了 hdUrl 且 hdAutoDownload 为 true,组件会自动在后台下载高清资源
  • 下载完成后,组件会自动切换到高清资源显示

资源配置说明

builtin 和 remote 资源的区别

  • builtin(内置资源):保留在 assets/ 目录,同时打包到 ZIP。运行时优先检查是否有下载的版本,支持热更新。适合音频、视频、字体等。
  • remote(远程资源):从 assets/ 目录删除,仅打包到 ZIP。必须下载后才能使用。适合图片、图标等可以压缩的资源。

API 文档

SmartAssetsPlugin

主插件类,提供统一的入口。

初始化

await SmartAssetsPlugin.initialize(
  config: GeneratedAssets.config,
  autoDownload: true,
  loggingConfig: LoggingConfig(
    enabled: true,
    level: 'debug',
    prefix: '[SmartAssets]',
  ),
);

ZIP 包下载

final plugin = SmartAssetsPlugin.instance;

// 开始下载
await plugin.startDownload();

// 取消下载
await plugin.cancelDownload();

增量更新

final plugin = SmartAssetsPlugin.instance;

// 检查是否有更新
final hasUpdate = await plugin.checkForIncrementalUpdate();

// 执行增量更新
await plugin.performIncrementalUpdate(
  onProgress: (phase, progress, description) {
    print('[$phase] ${(progress * 100).toStringAsFixed(1)}%');
  },
);

状态监听

final plugin = SmartAssetsPlugin.instance;

// 监听下载状态
plugin.downloadStatus.addListener(() {
  final status = plugin.downloadStatus.value;
  print('下载状态: $status');
});

智能组件

SmartAssetImage

智能图片组件,自动从 manifest 读取高清资源配置。

SmartAssetImage(
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  width: 100,
  height: 100,
)

SmartAssetImageProvider

图片 Provider,支持在任何需要 ImageProvider 的地方使用。

DecorationImage(
  image: SmartAssetImageProvider(
    assetPath: 'assets/icons/home.png',
    resolver: SmartAssetsPlugin.instance.resolver,
    scale: 1.0,
  ),
)

SmartAssetLoader

通用资源加载器,支持任意类型资源。

SmartAssetLoader<Map<String, dynamic>>(
  assetPath: 'assets/data/config.json',
  resolver: SmartAssetsPlugin.instance.resolver,
  loader: (resolvedPath) async {
    final text = await resolver.loadString(assetPath);
    return jsonDecode(text) as Map<String, dynamic>;
  },
  builder: (context, data) {
    return Text('Version: ${data['version']}');
  },
)

核心 API

SmartAssetsResolver

资源解析器,提供资源加载和解析功能。

final resolver = SmartAssetsPlugin.instance.resolver;

// 加载字节数据
final bytes = await resolver.loadBytes('assets/icons/home.png');

// 加载文本数据
final text = await resolver.loadString('assets/data/config.json');

// 解析资源路径
final resolvedPath = await resolver.resolveAssetPath('assets/icons/home.png');

// 获取高清资源 URL
final hdUrl = resolver.getHdUrl('assets/icons/home.png');

// 获取是否自动下载高清资源
final autoDownload = resolver.getHdAutoDownload('assets/icons/home.png');

发布流程

1. 构建资源

dart run smart_assets_plugin:build_all

2. 上传到 CDN

上传以下文件到 CDN:

  • build/assets_release/assets.zip - 资源包
  • build/assets_release/manifest.json - Manifest 文件

示例(阿里云 OSS):

ossutil cp build/assets_release/assets.zip \
  oss://your-bucket/assets/assets.zip \
  --acl public-read

ossutil cp build/assets_release/manifest.json \
  oss://your-bucket/assets/manifest.json \
  --acl public-read

3. 配置 CDN URL

在 smart_assets_config.yaml 中配置 CDN URL:

remote:
  base_url: "https://cdn.example.com/assets/"
  zip_name: "assets.zip"

常见问题

Q: 如何选择 ZIP 包下载还是增量更新?

A:

  • 首次安装: 自动使用 ZIP 包下载(全量)
  • 版本更新: 如果启用了增量更新,自动使用增量更新
  • 降级方案: 增量更新失败会自动降级到 ZIP 包下载

Q: builtin 和 remote 资源的区别?

A:

  • builtin(内置资源):保留在 assets/ 目录,同时打包到 ZIP。运行时优先检查是否有下载的版本,支持热更新。适合音频、视频、字体等。
  • remote(远程资源):从 assets/ 目录删除,仅打包到 ZIP。必须下载后才能使用。适合图片、图标等可以压缩的资源。

Q: 如何配置高清资源?

A:

  • 高清资源配置在 manifest.json 中,每个资源项可以配置 hdUrl 和 hdAutoDownload
  • UI 组件会自动从 manifest 读取配置,无需手动传参
  • 如果配置了 hdUrl 且 hdAutoDownload 为 true,组件会在后台自动下载高清资源
  • 下载完成后,组件会自动切换到高清资源显示

Q: SmartAssetLoader 的 builder 为什么 data 可能为 null?

A:

  • 资源加载失败时,loader 函数可能返回 null 或抛出异常
  • 开发者需要在 builder 中判断 data == null,提供合适的错误提示
  • 这样设计是为了给开发者更灵活的错误处理能力

Q: 如何自定义加载占位符和错误提示?

A:

  • SmartAssetImage 和 SmartAssetLoader 都支持 placeholder 和 errorWidget 参数
  • 可以传入自定义的 Widget 来替换默认的占位符和错误提示
SmartAssetImage(
  assetPath: 'assets/icons/home.png',
  resolver: SmartAssetsPlugin.instance.resolver,
  placeholder: CircularProgressIndicator(),
  errorWidget: Icon(Icons.error),
)

许可证

MIT License

贡献

欢迎提交 Issue 和 Pull Request!

Libraries

smart_assets_plugin
Smart Assets Plugin - 智能资源下载插件