如何无需在pubspec.yaml的flutter:assets中列文件添加Flutter SQL迁移脚本?
批量加载SQL迁移脚本(无需逐个声明assets、不依赖drift)
1. 组织SQL文件与配置assets
在项目根目录创建统一的迁移脚本目录,比如assets/sql/migrations/,把所有SQL脚本按执行顺序命名(例如001_initial_schema.sql、002_add_user_table.sql),确保文件名能按字典序排序。
然后修改pubspec.yaml,直接指定整个目录作为asset,无需逐个罗列文件:
flutter: assets: - assets/sql/migrations/
这样配置会自动包含该目录下的所有文件(包括子目录文件,如果有需要的话)。
2. 列举并执行迁移脚本
利用Flutter的AssetManifest.json获取所有已打包的asset路径,筛选出目标SQL文件后按顺序执行:
import 'dart:convert'; import 'package:flutter/services.dart'; import 'package:sqflite/sqflite.dart'; Future<Database> initDatabase() async { final path = await getDatabasesPath(); final dbPath = '$path/your_database.db'; // 获取所有asset清单 final manifestContent = await rootBundle.loadString('AssetManifest.json'); final manifestMap = json.decode(manifestContent) as Map<String, dynamic>; // 筛选出migrations目录下的SQL文件并排序 final migrationFiles = manifestMap.keys .where((path) => path.startsWith('assets/sql/migrations/') && path.endsWith('.sql')) .toList() ..sort(); // 按文件名排序,保证执行顺序 return openDatabase( dbPath, onCreate: (db, version) async { for (final file in migrationFiles) { // 读取SQL文件内容 final sqlContent = await rootBundle.loadString(file); // 拆分多语句并过滤空行/注释 final statements = sqlContent .split(';') .map((stmt) => stmt.trim()) .where((stmt) => stmt.isNotEmpty && !stmt.startsWith('--')); // 逐个执行SQL语句 for (final stmt in statements) { await db.execute(stmt); } } }, version: 1, ); }
关键注意事项
- 文件名顺序:必须按执行顺序命名(如001、002),排序后才能保证脚本按正确顺序执行,避免出现表不存在等错误。
- 多语句处理:sqflite的
execute方法不支持一次执行多个分号分隔的语句,所以必须拆分后逐个执行,同时过滤掉空行和单行注释。 - 热重载限制:新增或修改迁移文件后需要重启应用,因为
AssetManifest.json是打包时生成的,热重载不会更新清单内容。 - 目录扩展:如果需要按版本划分子目录(如
migrations/v1/、migrations/v2/),只需调整path.startsWith的匹配规则即可。
内容的提问来源于stack exchange,提问作者Yván Ecarri
相关产品推荐
相关产品推荐

