Flutter 实例:Http分块下载
封面图
•
2025-10-04
•
Flutter
4
0
0
0
在 Flutter 中实现 **HTTP 分块下载(Chunked Download)** 是一个常见的需求,尤其在下载大文件时,可以避免内存溢出,并支持断点续传、进度显示等功能。 下面是一个使用 `http` 包实现 HTTP 分块下载的完整示例: --- ## ✅ 1. 添加依赖 在 `pubspec.yaml` 文件中添加以下依赖: ```yaml dependencies: flutter: sdk: flutter http: ^0.13.5 ``` 然后运行 `flutter pub get`。 --- ## ✅ 2. 示例代码:分块下载 ```dart import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Http Chunked Download', home: Scaffold( appBar: AppBar(title: Text('Http 分块下载')), body: Center(child: DownloadButton()), ), ); } } class DownloadButton extends StatefulWidget { @override _DownloadButtonState createState() => _DownloadButtonState(); } class _DownloadButtonState extends State<DownloadButton> { bool _isDownloading = false; double _progress = 0.0; Future<void> downloadFile(String url, String savePath) async { setState(() { _isDownloading = true; _progress = 0.0; }); try { final response = await http.get(Uri.parse(url), headers: { 'Range': 'bytes=0-', }); if (response.statusCode == 206) { // 206 表示部分成功(支持范围请求) final totalSize = int.parse(response.headers['content-range']!.split('/').last); final file = File(savePath); final sink = file.openWrite(); final chunkSize = 1024 * 1024; // 每次读取 1MB int offset = 0; while (offset < totalSize) { final end = min(offset + chunkSize, totalSize); final range = 'bytes=$offset-$end'; final chunkResponse = await http.get(Uri.parse(url), headers: { 'Range': range, }); if (chunkResponse.statusCode == 206) { await sink.add(chunkResponse.bodyBytes); offset += chunkSize; setState(() { _progress = offset / totalSize; }); } else { throw Exception("Failed to download chunk: ${chunkResponse.statusCode}"); } } await sink.close(); print("Download completed!"); } else { throw Exception("Server does not support range requests."); } } catch (e) { print("Error: $e"); } finally { setState(() { _isDownloading = false; }); } } @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: _isDownloading ? null : () { downloadFile( 'https://example.com/largefile.zip', // 替换为你的文件 URL '/storage/emulated/0/Download/largefile.zip', // Android 的保存路径 ); }, child: Text(_isDownloading ? "Downloading..." : "Start Download"), ), SizedBox(height: 20), if (_isDownloading) LinearProgressIndicator(value: _progress), ], ); } } ``` --- ## 📌 注意事项 1. **权限问题**: - 在 Android 上,你需要在 `AndroidManifest.xml` 中添加存储权限: ```xml <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` - 对于 Android 10 及以上,建议使用 `Directory` 或 `path_provider` 获取内部存储路径。 2. **URL 支持 Range 请求**: - 确保服务器支持 `Range` 请求。否则,无法分块下载。 - 如果服务器不支持,你只能一次性下载整个文件。 3. **断点续传**: - 可以通过记录已下载字节数,在下次下载时从该位置继续。 4. **使用 `dio` 更好**: - 如果你需要更高级的功能(如断点续传、超时控制等),推荐使用 `dio` 库(https://pub.dev/packages/dio)。 --- ## ✅ 使用 `dio` 实现分块下载(可选) 如果你希望更简单的 API 和更好的性能,可以考虑使用 `dio`: ```yaml dependencies: dio: ^4.0.0 ``` 然后: ```dart import 'package:dio/dio.dart'; Future<void> downloadWithDio(String url, String savePath) async { final dio = Dio(); final response = await dio.get( url, options: Options( responseType: ResponseType.bytes, followRedirects: false, ), ); final file = File(savePath); await file.writeAsBytes(response.data); } ``` --- ## ✅ 总结 - 使用 `http` 包可以实现基本的分块下载。 - 建议使用 `dio` 来简化网络请求和增强功能。 - 分块下载适用于大文件,能提升用户体验和稳定性。 如果你有具体的需求(比如断点续传、进度回调等),我可以进一步帮你完善代码。需要我帮你写一个支持断点续传的版本吗?
上一篇:
React 列表 和 Keys
标题录入,一次不能超过6条
返回顶部
留言
留言
评论