Upload SDK for Flutter

Upload large media files directly to FastPix from a Flutter app with resumable upload capabilities.

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.


How resumable uploads work through chunking

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.

dependencies:
flutter:
sdk: flutter
fastpix_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.


import  'dart:convert';
import  'dart:io';
import  'package:http/http.dart'  as http;

Future<String> getSignedUrl() async {
    final client = http.Client();
    // Construct JSON body
    final requestBody = jsonEncode({
        "corsOrigin": "*",
        "pushMediaSettings": {
            "metadata": {
            "key1": "value1"
            },
        "accessPolicy": "public",
        "maxResolution": "1080p"
        }
    });
    // Create Authorization header
    final credentials = "$tokenId:$secretKey";
    final auth = "Basic ${base64Encode(utf8.encode(credentials))}";
    try {
        final response = await client.post(
            Uri.parse('https://api.fastpix.io/v1/on-demand/uploads'),
            headers: {
            'Authorization': auth,
            'Content-Type': 'application/json',
            },
            body: requestBody,
        );
        if (response.statusCode == 200) {
            final data = jsonDecode(response.body);
            return data['signedUrl']; // Return the signed URL
        } else {
            throw  Exception('Failed to get signed URL: ${response.statusCode}');
        }
    } finally {
        client.close();
    }
}

Step 3: Start your upload

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

import  'dart:io';
import  'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';

Future<void> uploadVideo() async {
    final file = File('/path/to/your/video.mp4');
    final signedUrl = await getSignedUrl(); // Get signed URL from Step 2
    final uploadService = FlutterResumableUploads.builder()
        .file(file)
        .signedUrl(signedUrl)
        .chunkSize(16 * 1024 * 1024) // 16MB chunks
        .maxRetries(3)
        .retryDelay(Duration(milliseconds: 2000))
        .onProgress((progress) {
            print('Upload progress: ${progress.uploadPercentage}%');
            print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
        })
        .onError((error) {
            print('Upload error: ${error.message}');
        })
        .build();
    await uploadService.uploadVideo();
}

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:

FlutterResumableUploads.builder()
    .file(file)
    .signedUrl(signedUrl)
    .onProgress((progress) {
    // Called periodically to report upload progress
        print('Upload progress: ${progress.uploadPercentage}%');
        print('Current chunk: ${progress.currentChunkIndex}/${progress.totalChunks}');
        print('Status: ${progress.status}');
    })
    .onError((error) {
        // Called when an error occurs during upload
        print('Upload error: ${error.message}');
        print('Error code: ${error.code}');
    })
    .onPause(() {
        // Called when the upload is paused
        print('Upload paused');
    })
    .onAbort(() {
        // Called when the upload is aborted
        print('Upload aborted');
    })
    .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

uploadService.pauseUpload();

Resume an upload

uploadService.resumeUpload();

Abort an upload

uploadService.abortUpload();

Check upload status

final isPaused = uploadService.isPaused;
final isCompleted = uploadService.isCompleted;
final 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:


import  'dart:io';
import  'package:flutter/material.dart';
import  'package:fastpix_resumable_uploader/fastpix_resumable_uploader.dart';

class  UploadScreen  extends  StatefulWidget {
    @override
    _UploadScreenState createState() => _UploadScreenState();
}

class _UploadScreenState extends  State<UploadScreen> {
    FlutterResumableUploads? _uploadService;
    double _progress = 0.0;
    String _status = 'Ready to upload';
    bool _isUploading = false;
    bool _isPaused = false;

    @override

    Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(
                title: Text('Video Upload'),
            ),
            body: Padding(
                padding: EdgeInsets.all(16.0),
                child: Column(
                    children: [
                        // Progress indicator
                        LinearProgressIndicator(
                            value: _progress / 100.0,
                            backgroundColor: Colors.grey[300],
                            valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
                        ),
                        SizedBox(height: 16),
                        // Status text
                        Text(
                            _status,    
                            style: TextStyle(fontSize: 16),
                        ),
                        SizedBox(height: 24),
                        ElevatedButton(
                            onPressed: _isUploading ? null : _startUpload,
                            child: Text('Start Upload'),
                        ),
                        SizedBox(height: 16),
        // Pause/Resume button
                    if (_isUploading)
                        ElevatedButton(
                            onPressed: _isPaused ? _resumeUpload : _pauseUpload,
                            child: Text(_isPaused ? 'Resume' : 'Pause'),
                        ),
                        SizedBox(height: 16),
                        // Abort button
                        if (_isUploading)
                        ElevatedButton(
                            onPressed: _abortUpload,
                            style: ElevatedButton.styleFrom(
                                backgroundColor: Colors.red,
                            ),
                            child: Text('Abort Upload'),
                        ),
                    ],
                ),
            ),
        );
    }

    Future<void> _startUpload() async {
        try {
            final file = File('/path/to/your/video.mp4');
            final signedUrl = await getSignedUrl(); // Implement this method
            setState(() {
                _isUploading = true;
                _status = 'Initializing upload...';
            });
            _uploadService = FlutterResumableUploads.builder()
                .file(file)
                .signedUrl(signedUrl)
                .chunkSize(16 * 1024 * 1024) // 16MB chunks
                .maxRetries(3)
                .retryDelay(Duration(milliseconds: 2000))
                .onProgress((progress) {
                    setState(() {
                        _progress = progress.uploadPercentage;
                        _status = 'Uploading: ${progress.currentChunkIndex}/${progress.totalChunks} chunks';
                    });
                })
                .onError((error) {
                    setState(() {
                        _status = 'Error: ${error.message}';
                        _isUploading = false;
                    });
                })
                .onPause(() {
                    setState(() {
                        _isPaused = true;
                        _status = 'Upload paused';
                    });
                })
                .build();
            await _uploadService!.uploadVideo();
            setState(() {
                _status = 'Upload completed successfully!';
                _isUploading = false;
                _progress = 100.0;
            });
        } catch (e) {
            setState(() {
                _status = 'Error: $e';
                _isUploading = false;
            });
        }
    }

    void _pauseUpload() {
        _uploadService?.pauseUpload();
    }

    void _resumeUpload() {
        _uploadService?.resumeUpload();
        setState(() {
            _isPaused = false;
            _status = 'Uploading...';
        });
    }

    void _abortUpload() {
        _uploadService?.abortUpload();
        setState(() {
            _isUploading = false;
            _isPaused = false;
            _status = 'Upload aborted';
            _progress = 0.0;
        });
    }

    @override
    void dispose() {
        _uploadService?.abortUpload();
        super.dispose();
    }
}

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

Upload fails immediately

Check if the signed URL is valid and not expired.

Chunks fail to upload

Verify network connectivity and adjust retry settings.

Memory issues with large files

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

Progress not updating

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.