Flutter文件上传插件files_uploader的使用
Flutter文件上传插件files_uploader的使用
插件简介
files_uploader
是一个用于创建和管理文件上传任务的Flutter插件,支持iOS和Android平台。该插件基于Android的WorkManager
和iOS的NSURLSessionUploadTask
来实现后台模式下的文件上传。
平台集成
iOS集成
启用后台模式
需要在Xcode中启用应用程序的后台模式,并勾选"Background fetch"和"Remote notifications"选项。
AppDelegate调整
为了使插件能够在后台隔离运行,你需要对AppDelegate.swift
进行如下调整:
import files_uploader
func registerPlugins(registry: FlutterPluginRegistry) {
GeneratedPluginRegistrant.register(with: registry)
}
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
SwiftFlutterUploaderPlugin.registerPlugins = registerPlugins
// Any further code.
}
}
可选配置
- 最大连接数:可以在
Info.plist
中添加键值对来设置每个主机的最大并发连接数。 - 最大并发上传操作数:同样通过修改
Info.plist
来限制最大并发上传数量。 - 请求超时时间:控制上传请求等待数据的时间长度。
Android集成
可选配置
- 最大并发任务数:可以通过修改
AndroidManifest.xml
中的元数据来设定最大并发任务数。 - 连接超时时间:同样在
AndroidManifest.xml
中设置上传HTTP请求的连接超时时间。
使用示例
导入包
首先,在你的Dart代码中导入files_uploader
包:
import 'package:files_uploader/files_uploader.dart';
配置后台隔离入口点
定义一个顶级函数作为后台隔离的入口点,以便监听上传进度和结果:
void backgroundHandler() {
WidgetsFlutterBinding.ensureInitialized();
FlutterUploader uploader = FlutterUploader();
uploader.progress.listen((progress) {
// 处理上传进度
});
uploader.result.listen((result) {
// 处理上传结果
});
}
// 在应用启动时配置后台处理器
FlutterUploader().setBackgroundHandler(backgroundHandler);
创建新的上传任务
你可以根据需求选择使用MultipartFormDataUpload
或RawUpload
来创建上传任务:
// multipart/form-data上传
final taskId = await FlutterUploader().enqueue(
MultipartFormDataUpload(
url: "your upload link",
files: [FileItem(path: '/path/to/file', fieldname:"file")],
method: UploadMethod.POST,
headers: {"apikey": "api_123456", "userkey": "userkey_123456"},
data: {"name": "john"},
tag: 'my tag',
),
);
// 或者二进制上传
final taskId = await FlutterUploader().enqueue(
RawUpload(
url: "your upload link",
path: '/path/to/file',
method: UploadMethod.POST,
headers: {"apikey": "api_123456", "userkey": "userkey_123456"},
tag: 'my tag',
),
);
监听上传进度与结果
你还可以监听上传过程中的进度变化以及最终的结果:
final subscription = FlutterUploader().progress.listen((progress) {
// 处理进度信息
});
final resultSubscription = FlutterUploader().result.listen((result) {
// 处理上传结果
}, onError: (ex, stacktrace) {
// 错误处理
});
取消上传任务
如果需要取消某个特定的任务或者所有正在执行的任务,可以调用以下方法:
// 取消单个任务
FlutterUploader().cancel(taskId: taskId);
// 取消所有任务
FlutterUploader().cancelAll();
示例项目结构
为了更好地理解如何将这些功能整合到实际项目中,请参考完整的main.dart
文件内容。这个例子展示了如何结合SharedPreferences
存储已处理过的上传ID,并利用flutter_local_notifications
显示上传状态的通知。
// 忽略一些lint规则以简化代码展示
// ignore_for_file: public_member_api_docs
// ignore_for_file: avoid_print
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:files_uploader/files_uploader.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
const String title = 'FileUpload Sample app';
final Uri uploadURL = Uri.parse('https://us-central1-flutteruploadertest.cloudfunctions.net/upload');
FlutterUploader _uploader = FlutterUploader();
void backgroundHandler() {
WidgetsFlutterBinding.ensureInitialized();
var uploader = FlutterUploader();
var notifications = FlutterLocalNotificationsPlugin();
SharedPreferences.getInstance().then((preferences) {
var processed = preferences.getStringList('processed') ?? <String>[];
if (Platform.isAndroid) {
uploader.progress.listen((progress) {
if (!processed.contains(progress.taskId)) {
notifications.show(
progress.taskId.hashCode,
'FlutterUploader Example',
'Upload in Progress',
NotificationDetails(
android: AndroidNotificationDetails(
'FlutterUploader.Example',
'FlutterUploader',
channelDescription: 'Installed when you activate the Flutter Uploader Example',
progress: progress.progress ?? 0,
icon: 'ic_upload',
enableVibration: false,
importance: Importance.low,
showProgress: true,
onlyAlertOnce: true,
maxProgress: 100,
channelShowBadge: false,
),
iOS: const IOSNotificationDetails(),
),
);
}
});
}
uploader.result.listen((result) {
if (!processed.contains(result.taskId)) {
processed.add(result.taskId);
preferences.setStringList('processed', processed);
notifications.cancel(result.taskId.hashCode);
final successful = result.status == UploadTaskStatus.complete;
var title = 'Upload Complete';
if (result.status == UploadTaskStatus.failed) {
title = 'Upload Failed';
} else if (result.status == UploadTaskStatus.canceled) {
title = 'Upload Canceled';
}
notifications.show(
result.taskId.hashCode,
'FlutterUploader Example',
title,
NotificationDetails(
android: AndroidNotificationDetails(
'FlutterUploader.Example',
'FlutterUploader',
channelDescription: 'Installed when you activate the Flutter Uploader Example',
icon: 'ic_upload',
enableVibration: !successful,
importance: result.status == UploadTaskStatus.failed ? Importance.high : Importance.min,
),
iOS: const IOSNotificationDetails(presentAlert: true),
),
).catchError((e, stack) {
print('error while showing notification: $e, $stack');
});
}
});
});
}
void main() => runApp(const App());
class App extends StatefulWidget {
const App({Key? key}) : super(key: key);
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
int _currentIndex = 0;
bool allowCellular = true;
@override
void initState() {
super.initState();
_uploader.setBackgroundHandler(backgroundHandler);
var flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid = const AndroidInitializationSettings('ic_upload');
var initializationSettingsIOS = IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: true,
onDidReceiveLocalNotification: (int id, String? title, String? body, String? payload) async {},
);
var initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS
);
flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onSelectNotification: (payload) async {},
);
SharedPreferences.getInstance()
.then((sp) => sp.getBool('allowCellular') ?? true)
.then((result) {
if (mounted) {
setState(() {
allowCellular = result;
});
}
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: title,
theme: ThemeData(primarySwatch: Colors.blue),
home: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(allowCellular
? Icons.signal_cellular_connected_no_internet_4_bar
: Icons.wifi_outlined),
onPressed: () async {
final sp = await SharedPreferences.getInstance();
await sp.setBool('allowCellular', !allowCellular);
if (mounted) {
setState(() {
allowCellular = !allowCellular;
});
}
},
),
],
),
body: _currentIndex == 0
? UploadScreen(
uploader: _uploader,
uploadURL: uploadURL,
onUploadStarted: () {
setState(() => _currentIndex = 1);
},
)
: ResponsesScreen(
uploader: _uploader,
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.cloud_upload), label: 'Upload'),
BottomNavigationBarItem(icon: Icon(Icons.receipt), label: 'Responses'),
],
onTap: (newIndex) {
setState(() => _currentIndex = newIndex);
},
currentIndex: _currentIndex,
),
),
);
}
}
以上是关于files_uploader
插件的基本介绍及其具体使用的详细说明。希望这能帮助你在自己的Flutter项目中实现高效的文件上传功能!
更多关于Flutter文件上传插件files_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter文件上传插件files_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用files_uploader
插件进行文件上传的示例代码。这个插件允许你从设备中选择文件并将其上传到服务器。
首先,确保你已经在pubspec.yaml
文件中添加了files_uploader
依赖:
dependencies:
flutter:
sdk: flutter
files_uploader: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
接下来,你需要创建一个Flutter应用并集成文件上传功能。以下是一个简单的示例,展示如何使用files_uploader
插件:
import 'package:flutter/material.dart';
import 'package:files_uploader/files_uploader.dart';
import 'dart:io';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'File Uploader Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: FileUploadPage(),
);
}
}
class FileUploadPage extends StatefulWidget {
@override
_FileUploadPageState createState() => _FileUploadPageState();
}
class _FileUploadPageState extends State<FileUploadPage> {
final FilePicker _picker = FilePicker();
File? _selectedFile;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('File Uploader Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
_selectedFile == null ? 'No file selected.' : 'File selected: ${_selectedFile!.path}',
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
// Open file picker
FilePickerResult? result = await _picker.pickFiles(
type: FileType.any,
);
if (result != null) {
if (result.files.isNotEmpty) {
// Get the first file from the picked files
File file = File(result.files.first.path!);
setState(() {
_selectedFile = file;
});
// Upload the file
uploadFile(file);
}
}
},
child: Text('Select File'),
),
],
),
),
);
}
Future<void> uploadFile(File file) async {
String url = 'https://your-server-url/upload'; // 替换为你的服务器上传URL
var request = http.MultipartRequest('POST', Uri.parse(url));
var multipartFile = await http.MultipartFile.fromPath('file', file.path);
request.files.add(multipartFile);
var response = await request.send();
var responseData = await response.stream.toBytes();
String responseBody = String.fromCharCodes(responseData);
print('Upload response: $responseBody');
// Here you can handle the server response, e.g., show a snackbar or dialog
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('File uploaded successfully!'),
),
);
}
}
在这个示例中,我们做了以下几件事:
- 使用
FilePicker
来选择文件。 - 显示选中的文件路径。
- 使用
http.MultipartRequest
来上传文件到服务器。
注意事项:
- 你需要在你的
pubspec.yaml
文件中添加http
依赖,因为上传文件需要用到它。 - 确保你替换了服务器URL为你的实际上传URL。
- 这个示例假设服务器期望一个名为
file
的文件字段。如果你的服务器期望不同的字段名,请相应地修改代码。
dependencies:
http: ^0.13.3 # 请替换为最新版本号
这个示例提供了一个基本的文件上传流程,你可以根据需要进一步扩展和自定义。