Flutter视频上传插件video_uploader的使用

发布于 1周前 作者 phonegap100 来自 Flutter

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

常见问题解答

如果您有任何问题,请访问 社区 或使用 Issues 提问。


更多关于Flutter视频上传插件video_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter视频上传插件video_uploader的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用video_uploader插件进行视频上传的示例代码。这个插件允许你将视频文件上传到服务器。首先,你需要确保你的Flutter项目已经添加了video_uploader依赖。

  1. 添加依赖

在你的pubspec.yaml文件中添加video_uploader依赖:

dependencies:
  flutter:
    sdk: flutter
  video_uploader: ^最新版本号  # 请替换为最新版本号

然后运行flutter pub get来获取依赖。

  1. 请求权限

由于视频上传涉及到访问设备的存储,你需要在AndroidManifest.xmlInfo.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中添加NSPhotoLibraryUsageDescriptionNSMicrophoneUsageDescription(如果需要录音)。

<key>NSPhotoLibraryUsageDescription</key>
<string>App needs access to photo library</string>
<key>NSMicrophoneUsageDescription</key>
<string>App needs access to microphone</string>
  1. 使用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插件进行视频上传。

回到顶部