UpLink
The reliable background media upload engine for Flutter.
UpLink is a production-grade Flutter plugin engineered specifically for persistent background media uploads. It addresses a critical failure point in standard uploading libraries: application termination. By leveraging low-level operating system components, UpLink ensures uploads continue executing even when the application is swiped away from the task manager, the device enters sleep mode, or network conditions fluctuate.
Under the hood, UpLink utilizes native START_STICKY Foreground Services on Android and Background URLSessions on iOS, synchronized via a direct, C-level SQLite persistence engine that does not depend on the Flutter Dart isolate remaining alive.
Core Architectural Benefits
| Feature | Technical Implementation | Developer Value |
|---|---|---|
| Persistent Lifecycle | Android START_STICKY Service |
Automatically recreates background workers if the OS terminates the user process. |
| Hardware Optimization | PowerManager WakeLock | Prevents CPU suspension during streaming to maintain full execution speed. |
| Network Prioritization | WifiManager High-Perf Lock | Instructs the radio chip to ignore background throttling for maximum bandwidth. |
| Resiliency Engine | 3-Stage Exponential Backoff | Handles transient network dropouts with automated reconnection attempts. |
| Out-of-Band State Sync | Direct SQLite integration | Records upload status reliably to shared local storage even if the Dart VM is dead. |
Installation
Add the following dependency to your pubspec.yaml file:
dependencies:
uplink: ^1.0.0
Platform Configuration
Android Setup
Android 14+ (API level 34) introduces strict declarations for Foreground Services. Ensure you include the dataSync type declaration and the hardware permission tags in your android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Required permissions for Internet, Background operations and Hardware Locks -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application>
<!-- Registers UpLink's native background service -->
<service
android:name="com.anit.uplink.UploadService"
android:foregroundServiceType="dataSync"
android:exported="false" />
</application>
</manifest>
iOS Setup
Background operations on Apple devices require explicit capabilities to be enabled via Xcode:
- Open your iOS project in Xcode.
- Navigate to Signing & Capabilities -> Click the + Capability button.
- Select Background Modes and check the following options:
Background fetchBackground processing
Implementation & API Guide
UpLink exposes a fully asynchronous static interface designed to integrate easily into any existing state management architecture.
1. Requesting System Permissions
On Android 13 and higher, applications must request runtime authorization to post notifications. Call this during your application's initial boot cycle:
import 'package:uplink/uplink.dart';
@override
void initState() {
super.initState();
// Triggers native OS dialog to request notification privileges
UpLink.requestNotificationPermission();
}
2. Submitting an Upload Task
To queue a file for upload, provide the target endpoint URL and the absolute path of the local file. You may optionally attach custom headers (such as JWT authorization tokens).
// The call returns immediately with a unique task identifier (UUID)
final String taskId = await UpLink.enqueue(
url: "https://api.yourservice.com/v1/upload",
filePath: "/absolute/path/to/your/file.mp4",
headers: {
"Authorization": "Bearer MY_JWT_TOKEN",
"X-Custom-Header": "Any String Value"
},
);
print("Background upload task queued successfully. Task ID: $taskId");
Queueing Parameters Breakdown
- url: The remote HTTP(S) destination. The native engine will execute an HTTP POST stream.
- filePath: The fully-qualified local system location of the media file.
- headers: Key-value Map injected into the HTTP request envelope natively.
3. Monitoring Live Progress Events
To render dynamic UI elements such as progress bars, subscribe to the global Event Channel stream. This stream broadcasts progress percentages and lifecycle changes in real-time.
StreamBuilder<UploadProgressEvent>(
stream: UpLink.onProgress, // Listens to native platform broadcasts
builder: (context, snapshot) {
if (snapshot.hasData) {
final UploadProgressEvent event = snapshot.data!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Active Task: ${event.id}"),
LinearProgressIndicator(value: event.progress / 100.0), // 0.0 to 1.0
Text("Current Status: ${event.status} (${event.progress}%)"),
],
);
}
return const Text("No background uploads currently running.");
},
)
4. Retrieving Persistent Task Logs
Because Native services record states directly to a localized database, you can query previous or finished uploads at any point, including after a cold application restart.
// Fetch total localized history from shared storage
List<UploadTask> history = await UpLink.getAllTasks();
for (var task in history) {
print("Task UID: ${task.id}");
print("Target File: ${task.filePath}");
print("Final Status: ${task.status.toString()}");
}
// Clean up localized database by deleting a specific log entry
await UpLink.deleteTask(taskId);
Lifecycle State Definitions
| State Identifier | Explanation |
|---|---|
enqueued |
The record has synced to local SQLite and is sitting in the native thread-safe execution queue. |
running |
Active bytes are actively streaming to the socket. Hardware WakeLocks are engaged. |
completed |
The remote target server has responded with a standard success status code (HTTP 2xx). |
failed |
The process aborted after exhausting the network-flicker auto-retry scheduler. |
Developer
Developed and maintained by Anit Pal.
License
This project is distributed under the MIT License.
Copyright (c) 2026 Anit Pal. All rights reserved.