Android 6.0以上动态获取读取权限要知道
Android 10.0以上 manifest里面加入 android:requestLegacyExternalStorage="true"
1、导入依赖包
archive: ^3.1.2 path_provider: ^2.0.5 fast_gbk: ^1.0.0
2、解压并输出到destinationDir:
zipFilePath是你获取到的zip所在的目录
Future extractZipFile() async {
try {
final zipFile = File(widget.zipFilePath);
final bytes = zipFile.readAsBytesSync();
final dir = await getApplicationDocumentsDirectory();
destinationDir = Directory('${dir.path}/assets');
if (await destinationDir.exists()) {
final deletedDir = await destinationDir.delete(recursive: true);
if (deletedDir is Directory) {
print('目录删除成功!');
} else {
print('目录删除失败!');
}
}
await destinationDir.create(recursive: true);
final archive = ZipDecoder().decodeBytes(bytes);
dynamic totalFiles = archive.numberOfFiles();
print('totalFiles====$totalFiles');
int extractedFiles = 0;
// 获取当前时间
String startTime = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
print('开始时间====$startTime');
for (final file in archive) {
final filePath = '${destinationDir.path}/${file.name}';
print('filePath===$filePath');
if (file.isFile) {
final data = file.content as List;
final decodedData = utf8.decode(data, allowMalformed: true);
final outFile = File(filePath);
await outFile.create(recursive: true);
await outFile.writeAsString(decodedData, flush: true);
// print(file.name);
} else {
await Directory(filePath).create(recursive: true);
}
extractedFiles++;
setState(() {
_extractProgress = extractedFiles / totalFiles;
// print(_extractProgress);
});
}
String endTime = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now());
print('结束时间====$endTime');
} catch (e) {
print('Error while extracting the zip file: $e');
}
}
上面代码注意在for循环里面使用到了setState,每循环一次setState一次,会对性能造成极大的损耗,因此如果要考虑解压速度、性能等,就删除该setState,或者改为如下代码:
Future.microtask(() => setState(() {}));
microTask任务会减少性能消耗,但是还是会有影响,比如我这里解压50兆的压缩包,如果彻底不使用setState,大概只需要3s左右,如果使用microtask,则需要8s左右,如果直接使用setState,那就得20s以上了。
3、加入进度条(下面代码放到Colum里面),等进度条到1的时候,点击加载html按钮。
Center(
child: CircularProgressIndicator(
value: _extractProgress,
),
),
Text('进度:$_extractProgress'),
ElevatedButton(
onPressed: () async {
// extractZipFile();
extractZipFiles();
},
child: const Text('开始解压'),
),
ElevatedButton(
onPressed: () async {
print(destinationDir.path);
if (_extractProgress == 1.0) {
final assetFile = File('${destinationDir.path}/index.html');
_assetContents = await assetFile.readAsString();
Navigator.pushNamed(context, RouteGenerator.assetHtml,
arguments: _assetContents);
}
},
child: const Text('加载html'),
),
4、AssetHtml也贴上
class AssetHtml extends StatelessWidget {
final String htmlFilePath;
const AssetHtml({super.key, required this.htmlFilePath});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('用户协议'),
),
body: WebView(
initialUrl: 'data:text/html,${Uri.encodeComponent(htmlFilePath)}',
javascriptMode: JavascriptMode.unrestricted,
// onWebViewCreated: (WebViewController webViewController) {
// _loadHtmlFromAssets(webViewController);
// },
),
);
}
}
5、第二个压缩包解压过程重复上面步骤,下面假设两个压缩包已经成功解压:
class FolderMerger {
Future merge(String firstFolderPath, String secondFolderPath,
String mergedFolderPath) async {
final firstFolder = Directory(firstFolderPath);
final secondFolder = Directory(secondFolderPath);
final mergedFolder = Directory(mergedFolderPath);
if (await mergedFolder.exists()) {
final deletedDir = await mergedFolder.delete(recursive: true);
if (deletedDir is Directory) {
print('目录删除成功!');
} else {
print('目录删除失败!');
}
}
await mergedFolder.create(recursive: true);
await _copyFolderContents(firstFolder, mergedFolder);
await _copyFolderContents(secondFolder, mergedFolder);
await firstFolder.delete(recursive: true);
await secondFolder.delete(recursive: true);
print('合并成功!');
}
Future _copyFolderContents(Directory sourceFolder, Directory targetFolder) async {
final fileList = sourceFolder.listSync(recursive: true);
for (final file in fileList) {
if (file is File) {
final relativePath = p.relative(file.path, from: sourceFolder.path);
final targetFile = File(p.join(targetFolder.path, relativePath));
await targetFile.parent.create(recursive: true);
await file.copy(targetFile.path);
}
}
}
}
使用方式:
ElevatedButton(
onPressed: () async {
final dir = await getApplicationDocumentsDirectory();
FolderMerger().merge('${dir.path}/assets', '${dir.path}/assets2',
'${dir.path}/assets3');
},
child: const Text('合并文件夹'),
),