Set up resumable uploads for Flutter

Upload large media files to FastPix from Flutter apps with resumable chunked uploads and track the progress.

The FastPix Flutter Resumable Uploads SDK helps you efficiently upload large files from Flutter apps by splitting them into chunks and also gives you the ability to pause and resume your uploads.



Resumable uploads can be effectively handled through a technique called chunking. This method involves breaking down large files into smaller, more manageable pieces, or “chunks.” Here’s how chunking works:

  1. Divide the file: Large files are split into smaller, manageable chunks (e.g., 16 MB by default).
  2. Upload individually: Each chunk is uploaded separately. If a chunk fails, only that specific chunk needs to be re-uploaded.
  3. Resume capability: If the upload is interrupted, you can resume from the last successfully uploaded chunk instead of starting over.

This approach is important because:

  • It reduces the risk: Uploading smaller chunks minimizes the risk of failure. If a chunk fails to upload due to network issues, only that specific chunk needs to be re-uploaded, not the entire file.
  • Improves performance: Smaller chunks can be uploaded more quickly and efficiently, especially on slower connections, as they require less time to transfer.
  • Easier management: Chunking allows for better tracking of upload progress, making it easier to implement features like pause and resume.


Step 1: Install the Flutter SDK


Add the dependency to yourpubspec.yaml

Add FastPix’s Flutter library to the dependencies block of your pubspec.yaml file.

1dependencies:
2flutter:
3sdk: flutter
4fastpix_resumable_uploader: ^1.0.0

Install dependencies
Run the following command to install the dependencies:

$flutter pub get

Step 2: Create an upload URL

In order to upload a video, you will need a signed upload URL.

To get this signed URL, you’ll need a valid Access Token and Secret Key. See the Basic Authentication Guide for details on retrieving these credentials.

Once you have your credentials, use the Upload media from device API to generate a signed URL for uploading media. After fetching the the signed URL you can continue with integrating the SDK into your application.

The example below gives you an idea about how to get the signed URL using the upload media from device API. You can use the example directly or also refer to our upload videos directly guide.


Dart
1import 'dart:convert';
2import 'dart:io';
3import 'package:http/http.dart' as http;
4
5Future<String> getSignedUrl() async {
6 final client = http.Client();
7 // Construct JSON body
8 final requestBody = jsonEncode({
9 "corsOrigin": "*",
10 "pushMediaSettings": {
11 "metadata": {
12 "key1": "value1"
13 },
14 "accessPolicy": "public",
15 "maxResolution": "1080p",
16 "mediaQuality": "standard"
17 }
18 });
19 // Create Authorization header
20 final credentials = "$tokenId:$secretKey";
21 final auth = "Basic ${base64Encode(utf8.encode(credentials))}";
22 try {
23 final response = await client.post(
24 Uri.parse('https://api.fastpix.com/v1/on-demand/uploads'),
25 headers: {
26 'Authorization': auth,
27 'Content-Type': 'application/json',
28 },
29 body: requestBody,
30 );
31 if (response.statusCode == 200) {
32 final data = jsonDecode(response.body);
33 return data['signedUrl']; // Return the signed URL
34 } else {
35 throw Exception('Failed to get signed URL: ${response.statusCode}');
36 }
37 } finally {
38 client.close();
39 }
40}

Step 3: Start your upload

The Flutter SDK provides a builder pattern for easy configuration and initialization:

Dart
1import 'dart:io';
2import 'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';
3
4Future<void> uploadVideo() async {
5 final file = File('/path/to/your/video.mp4');
6 final signedUrl = await getSignedUrl(); // Get signed URL from Step 2
7 final uploadService = FlutterResumableUploads.builder()
8 .file(file)
9 .signedUrl(signedUrl)
10 .chunkSize(16 * 1024 * 1024) // 16MB chunks
11 .maxRetries(3)
12 .retryDelay(Duration(milliseconds: 2000))
13 .onProgress((progress) {
14 print('Upload progress: ${progress.uploadPercentage}%');
15 print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
16 })
17 .onError((error) {
18 print('Upload error: ${error.message}');
19 })
20 .build();
21 await uploadService.uploadVideo();
22}

Builder configuration options

ParameterTypeDefaultDescription
fileFileRequiredThe video file to upload
signedUrlStringRequiredThe signed URL for upload
chunkSizeint16MBSize of each chunk in bytes
maxFileSizeint?OptionalMaximum allowed file size
maxRetriesint3Maximum retry attempts for failed chunks
retryDelayDuration2 secondsDelay between retry attempts
onProgressFunctionOptionalProgress callback function
onErrorFunctionOptionalError callback function
onPauseFunctionOptionalPause callback function
onAbortFunctionOptionalAbort callback function


Step 4: Monitor upload events

The SDK provides comprehensive callback methods to monitor upload progress and handle various events:

Dart
1FlutterResumableUploads.builder()
2 .file(file)
3 .signedUrl(signedUrl)
4 .onProgress((progress) {
5 // Called periodically to report upload progress
6 print('Upload progress: ${progress.uploadPercentage}%');
7 print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
8 print('Status: ${progress.status}');
9 })
10 .onError((error) {
11 // Called when an error occurs during upload
12 print('Upload error: ${error.message}');
13 print('Error code: ${error.code}');
14 })
15 .onPause(() {
16 // Called when the upload is paused
17 print('Upload paused');
18 })
19 .onAbort(() {
20 // Called when the upload is aborted
21 print('Upload aborted');
22 })
23 .build();

Progress model
The progress callback provides a ProgressModel with the following properties:

  • uploadPercentage: Progress percentage (0.0 - 100.0)
  • currentChunkIndex: Current chunk being uploaded
  • totalChunks: Total number of chunks
  • status: Current upload status (e.g., “splitting_chunks”, “uploading_chunks”, “completed”)
  • fileSize: Total file size in bytes
  • uploadedBytes: Number of bytes uploaded so far


Step 5: Manage video uploads

You can control the upload lifecycle with the following methods:


Pause an upload

Dart
1uploadService.pauseUpload();

Resume an upload

Dart
1uploadService.resumeUpload();

Abort an upload

Dart
1uploadService.abortUpload();

Check upload status

Dart
1final isPaused = uploadService.isPaused;
2final isCompleted = uploadService.isCompleted;
3final isAborted = uploadService.isAborted;


Detailed usage example

The following example gives an overview of integrating the FastPix Flutter Uploads SDK into your project, enabling you to build a fully customized upload interface:


Dart
1import 'dart:io';
2import 'package:flutter/material.dart';
3import 'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';
4
5class UploadScreen extends StatefulWidget {
6 @override
7 _UploadScreenState createState() => _UploadScreenState();
8}
9
10class _UploadScreenState extends State<UploadScreen> {
11 FlutterResumableUploads? _uploadService;
12 double _progress = 0.0;
13 String _status = 'Ready to upload';
14 bool _isUploading = false;
15 bool _isPaused = false;
16
17 @override
18
19 Widget build(BuildContext context) {
20 return Scaffold(
21 appBar: AppBar(
22 title: Text('Video Upload'),
23 ),
24 body: Padding(
25 padding: EdgeInsets.all(16.0),
26 child: Column(
27 children: [
28 // Progress indicator
29 LinearProgressIndicator(
30 value: _progress / 100.0,
31 backgroundColor: Colors.grey[300],
32 valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
33 ),
34 SizedBox(height: 16),
35 // Status text
36 Text(
37 _status,
38 style: TextStyle(fontSize: 16),
39 ),
40 SizedBox(height: 24),
41 ElevatedButton(
42 onPressed: _isUploading ? null : _startUpload,
43 child: Text('Start Upload'),
44 ),
45 SizedBox(height: 16),
46 // Pause/Resume button
47 if (_isUploading)
48 ElevatedButton(
49 onPressed: _isPaused ? _resumeUpload : _pauseUpload,
50 child: Text(_isPaused ? 'Resume' : 'Pause'),
51 ),
52 SizedBox(height: 16),
53 // Abort button
54 if (_isUploading)
55 ElevatedButton(
56 onPressed: _abortUpload,
57 style: ElevatedButton.styleFrom(
58 backgroundColor: Colors.red,
59 ),
60 child: Text('Abort Upload'),
61 ),
62 ],
63 ),
64 ),
65 );
66 }
67
68 Future<void> _startUpload() async {
69 try {
70 final file = File('/path/to/your/video.mp4');
71 final signedUrl = await getSignedUrl(); // Implement this method
72 setState(() {
73 _isUploading = true;
74 _status = 'Initializing upload...';
75 });
76 _uploadService = FlutterResumableUploads.builder()
77 .file(file)
78 .signedUrl(signedUrl)
79 .chunkSize(16 * 1024 * 1024) // 16MB chunks
80 .maxRetries(3)
81 .retryDelay(Duration(milliseconds: 2000))
82 .onProgress((progress) {
83 setState(() {
84 _progress = progress.uploadPercentage;
85 _status = 'Uploading: ${progress.currentChunkIndex}/${progress.totalChunks} chunks';
86 });
87 })
88 .onError((error) {
89 setState(() {
90 _status = 'Error: ${error.message}';
91 _isUploading = false;
92 });
93 })
94 .onPause(() {
95 setState(() {
96 _isPaused = true;
97 _status = 'Upload paused';
98 });
99 })
100 .build();
101 await _uploadService!.uploadVideo();
102 setState(() {
103 _status = 'Upload completed successfully!';
104 _isUploading = false;
105 _progress = 100.0;
106 });
107 } catch (e) {
108 setState(() {
109 _status = 'Error: $e';
110 _isUploading = false;
111 });
112 }
113 }
114
115 void _pauseUpload() {
116 _uploadService?.pauseUpload();
117 }
118
119 void _resumeUpload() {
120 _uploadService?.resumeUpload();
121 setState(() {
122 _isPaused = false;
123 _status = 'Uploading...';
124 });
125 }
126
127 void _abortUpload() {
128 _uploadService?.abortUpload();
129 setState(() {
130 _isUploading = false;
131 _isPaused = false;
132 _status = 'Upload aborted';
133 _progress = 0.0;
134 });
135 }
136
137 @override
138 void dispose() {
139 _uploadService?.abortUpload();
140 super.dispose();
141 }
142}

Features


Core features

  • Chunking: Files are automatically split into chunks (default chunk size is 16MB).
  • Pause and resume: Allows temporarily pausing the upload and resuming after a while.
  • Retry: Uploads might fail due to temporary network failures. Individual chunks are retried with exponential backoff to recover automatically from such failures.
  • Lifecycle event listeners: Provides real-time feedback through various upload lifecycle events.
  • Error handling: Comprehensive error management to notify users of issues during uploads.
  • Customizability: Options to customize chunk size and retry attempts.

Advanced features

  • Network health monitoring: Automatically detects network connectivity changes and handles offline scenarios.
  • Upload lock management: Prevents multiple concurrent uploads from the same service instance.
  • Progress tracking: Detailed progress reporting with chunk-level information.
  • File validation: Built-in file size and format validation.
  • Memory efficient: Streams file chunks without loading the entire file into memory.

BEST PRACTICES

Chunk Size: Use appropriate chunk sizes based on your target platform and network conditions. 16MB is a good default for most scenarios.

Error Handling: Always implement proper error handling to provide meaningful feedback to users.
Progress Updates: Use progress callbacks to update your UI and keep users informed about upload status.

Network Monitoring: The SDK automatically handles network connectivity changes, but you may want to add additional network monitoring for better UX.

Memory Management: For very large files, consider implementing additional memory management strategies.

Retry Configuration: Adjust retry settings based on your network environment and requirements.



Troubleshooting common issues

Check if the signed URL is valid and not expired.

Verify network connectivity and adjust retry settings.

The SDK handles memory efficiently, but ensure your app has sufficient memory allocation.

Make sure you’re properly implementing the progress callback.


DEBUG INFORMATION

Enable debug logging to get detailed information about upload operations.

  • The SDK automatically logs debug information when running in debug mode.
  • Check the console output for detailed upload information

For more information and support, contact us.