Flutter视频上传插件video_uploader的使用
Flutter视频上传插件video_uploader的使用
Table of contents
项目描述
api.video 是为产品构建者提供的视频基础设施。它提供了快速的视频API,用于在您的应用程序中集成、扩展和管理按需和低延迟直播功能。
api.video
的 Flutter 上传器通过委托上传令牌或 API 密钥将视频上传到 api.video
。它支持两种上传方式:
- 标准上传:一次性发送整个视频文件。
- 渐进式上传:分块发送视频文件,无需知道最终文件大小。
开始使用
安装
在项目的根目录下运行以下命令以添加 video_uploader
插件:
flutter pub add video_uploader
这将在 pubspec.yaml
文件中添加以下内容:
dependencies:
video_uploader: ^1.3.0
Android配置
权限
- 对于 Android API 33 及以上版本,需要请求
android.permission.READ_MEDIA_VIDEO
权限。 - 对于 Android API 33 以下版本,需要请求
android.permission.READ_EXTERNAL_STORAGE
权限。
此外,如果您的应用目标是 Android 33 及以上版本,您可能还需要请求 android.permission.POST_NOTIFICATIONS
权限。
对于 Android API 34 及以上版本,在 AndroidManifest.xml
文件的 <application>
标签中添加以下服务声明:
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:exported="false"
android:foregroundServiceType="dataSync" />
通知
为了自定义通知样式,您可以覆盖以下资源:
- 图标:
R.drawable.ic_upload_notification
- 颜色:
R.color.upload_notification_color
- 通道名称:
R.string.upload_notification_channel_name
代码示例
以下是一个完整的示例代码,展示了如何使用 video_uploader
插件来选择并上传视频文件,并显示上传进度。
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:video_uploader/video_uploader.dart';
const primaryColor = Color(0xFFFA5B30);
const secondaryColor = Color(0xFFFFB39E);
void main() {
runApp(const UploaderDemo());
}
class UploaderDemo extends StatelessWidget {
const UploaderDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: primaryColor,
),
home: Scaffold(
appBar: AppBar(
backgroundColor: primaryColor,
title: const Text('Uploader Example'),
),
body: const UploaderPage(),
),
);
}
}
class UploaderPage extends StatefulWidget {
const UploaderPage({Key? key}) : super(key: key);
@override
UploaderPageState createState() => UploaderPageState();
}
class UploaderPageState extends State<UploaderPage> {
final _tokenTextController = TextEditingController();
final ImagePicker _picker = ImagePicker();
double _progressValue = 0;
bool _hasUploadStarted = false;
void setProgress(double value) async {
setState(() {
_progressValue = value;
});
}
@override
void dispose() {
_tokenTextController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const SizedBox(height: 52),
TextField(
cursorColor: primaryColor,
decoration: const InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 2.0),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: primaryColor, width: 2.0),
),
hintText: 'Your upload token',
),
controller: _tokenTextController,
),
MaterialButton(
color: primaryColor,
child: const Text(
"Pick Video",
style: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold),
),
onPressed: () async {
var source = ImageSource.gallery;
XFile? image = await _picker.pickVideo(source: source);
if (image != null) {
setState(() {
_hasUploadStarted = true;
});
try {
var video = await ApiVideoUploader.uploadWithUploadToken(
_tokenTextController.text, image.path,
onProgress: (progress) {
log("Progress :$progress");
setProgress(progress);
});
log("VideoId : ${video.videoId}");
log("Video : $video");
if (context.mounted) {
showSuccessSnackBar(context, "Video ${video.videoId} uploaded");
}
} on Exception catch (e) {
log("Failed to upload video: $e");
if (context.mounted) {
showErrorSnackBar(context, "Failed to upload video: ${e.message}");
}
} catch (e) {
log("Failed to upload video: $e");
if (context.mounted) {
showErrorSnackBar(context, "Failed to upload video $e");
}
}
}
},
),
_hasUploadStarted
? LinearProgressIndicator(
color: primaryColor,
backgroundColor: secondaryColor,
value: _progressValue,
)
: Container(),
_hasUploadStarted
? MaterialButton(
color: primaryColor,
child: const Text(
"Cancel",
style: TextStyle(color: Colors.white70, fontWeight: FontWeight.bold),
),
onPressed: () async {
try {
await ApiVideoUploader.cancelAll();
} catch (e) {
log("Failed to cancel video: $e");
}
},
)
: Container(),
],
),
),
);
}
void showSuccessSnackBar(BuildContext context, String message) {
context.showSnackBar(message, backgroundColor: Colors.green);
}
void showErrorSnackBar(BuildContext context, String message) {
context.showSnackBar(message,
backgroundColor: Colors.red,
duration: const Duration(seconds: 60),
showCloseIcon: true);
}
}
extension ErrorExtension on Exception {
String get message {
if (this is PlatformException) {
return (this as PlatformException).message ?? "Unknown error";
}
return toString();
}
}
extension BuildContextSnachBarExtension on BuildContext {
void showSnackBar(String message,
{Color? backgroundColor,
Duration duration = const Duration(seconds: 4),
bool showCloseIcon = false}) {
ScaffoldMessenger.of(this).showSnackBar(
SnackBar(
content: Text(message),
backgroundColor: backgroundColor,
duration: duration,
showCloseIcon: showCloseIcon,
),
);
}
}
依赖项
此项目使用了以下外部库:
Plugin | README |
---|---|
Swift-video-uploader | Swift-video-uploader |
android-video-uploader | android-video-uploader |
常见问题解答
更多关于Flutter视频上传插件video_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter视频上传插件video_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,下面是一个关于如何在Flutter项目中使用video_uploader
插件进行视频上传的示例代码。这个插件允许你将视频文件上传到服务器。首先,你需要确保你的Flutter项目已经添加了video_uploader
依赖。
- 添加依赖
在你的pubspec.yaml
文件中添加video_uploader
依赖:
dependencies:
flutter:
sdk: flutter
video_uploader: ^最新版本号 # 请替换为最新版本号
然后运行flutter pub get
来获取依赖。
- 请求权限
由于视频上传涉及到访问设备的存储,你需要在AndroidManifest.xml
和Info.plist
中请求相关权限。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.yourapp">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
...
</manifest>
Info.plist
对于iOS,你需要在Info.plist
中添加NSPhotoLibraryUsageDescription
和NSMicrophoneUsageDescription
(如果需要录音)。
<key>NSPhotoLibraryUsageDescription</key>
<string>App needs access to photo library</string>
<key>NSMicrophoneUsageDescription</key>
<string>App needs access to microphone</string>
- 使用
video_uploader
插件
下面是一个简单的示例,展示如何使用video_uploader
插件上传视频:
import 'package:flutter/material.dart';
import 'package:video_uploader/video_uploader.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Video Uploader Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final VideoUploader _videoUploader = VideoUploader();
String? uploadUrl = "https://your-server-url/upload"; // 替换为你的服务器上传URL
@override
void initState() {
super.initState();
_requestPermissions();
}
Future<void> _requestPermissions() async {
// 请求存储权限
var status = await Permission.storage.status;
if (!status.isGranted) {
var result = await Permission.storage.request();
if (!result.isGranted) {
// 权限被拒绝
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("权限被拒绝"),
content: Text("需要存储权限来上传视频"),
actions: <Widget>[
FlatButton(
child: Text("关闭"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
Future<void> _uploadVideo(File videoFile) async {
try {
var response = await _videoUploader.uploadVideo(
url: uploadUrl!,
file: videoFile,
headers: {
"Content-Type": "multipart/form-data",
},
);
print("Upload response: ${response.body}");
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("上传成功"),
content: Text("视频上传成功"),
actions: <Widget>[
FlatButton(
child: Text("确定"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
} catch (e) {
print("Upload error: $e");
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("上传失败"),
content: Text("视频上传失败: $e"),
actions: <Widget>[
FlatButton(
child: Text("确定"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Video Uploader Demo"),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
// 选择视频文件
var videoFile = await _pickVideoFile();
if (videoFile != null) {
_uploadVideo(videoFile);
}
},
child: Text("选择视频并上传"),
),
),
);
}
Future<File?> _pickVideoFile() async {
// 使用系统的文件选择器选择视频文件
var result = await FilePicker.platform.pickFiles(
type: FileType.video,
allowMultiple: false,
);
if (result != null && result.files.isNotEmpty) {
return File(result.files.first.path!);
}
return null;
}
}
注意:
- 上述代码示例使用了
file_picker
插件来选择视频文件。你需要在pubspec.yaml
中添加file_picker
依赖,并运行flutter pub get
。 - 你需要替换
uploadUrl
为你的服务器上传URL。 - 示例中的错误处理和用户提示仅为简单实现,你可以根据实际需求进行改进。
希望这个示例能帮助你理解如何在Flutter项目中使用video_uploader
插件进行视频上传。