Flutter 解压Android根目录压缩文件,并输出到应用根目录的assets文件夹下,最后合并两个文件夹,并保留原来所有的目录。

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('合并文件夹'),
          ),

你可能感兴趣的:(android,flutter,android,studio)