A plugin for creating and managing download tasks. Supports iOS and Android.
This plugin is based on WorkManager
in Android and NSURLSessionDownloadTask
in iOS to run download task in background mode.
Note: following steps requires to open your ios
project in Xcode.
sqlite
library.
AppDelegate
:Objective-C:
/// AppDelegate.h
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end
// AppDelegate.m
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#include "FlutterDownloaderPlugin.h"
@implementation AppDelegate
void registerPlugins(NSObject<FlutterPluginRegistry>* registry) {
//
// Integration note:
//
// In Flutter, in order to work in background isolate, plugins need to register with
// a special instance of `FlutterEngine` that serves for background execution only.
// Hence, all (and only) plugins that require background execution feature need to
// call `registerWithRegistrar` in this function.
//
// The default `GeneratedPluginRegistrant` will call `registerWithRegistrar` of all
// plugins integrated in your application. Hence, if you are using `FlutterDownloaderPlugin`
// along with other plugins that need UI manipulation, you should register
// `FlutterDownloaderPlugin` and any 'background' plugins explicitly like this:
//
// [FlutterDownloaderPlugin registerWithRegistrar:[registry registrarForPlugin:@"vn.hunghd.flutter_downloader"]];
//
[GeneratedPluginRegistrant registerWithRegistry:registry];
}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
[FlutterDownloaderPlugin setPluginRegistrantCallback:registerPlugins];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end
Or Swift:
import UIKit
import Flutter
import flutter_downloader
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
private func registerPlugins(registry: FlutterPluginRegistry) {
//
// Integration note:
//
// In Flutter, in order to work in background isolate, plugins need to register with
// a special instance of `FlutterEngine` that serves for background execution only.
// Hence, all (and only) plugins that require background execution feature need to
// call `register` in this function.
//
// The default `GeneratedPluginRegistrant` will call `register` of all plugins integrated
// in your application. Hence, if you are using `FlutterDownloaderPlugin` along with other
// plugins that need UI manipulation, you should register `FlutterDownloaderPlugin` and any
// 'background' plugins explicitly like this:
//
// FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "vn.hunghd.flutter_downloader"))
//
GeneratedPluginRegistrant.register(with: registry)
}
Info.plist
file)<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>www.yourserver.com</key>
<dict>
<!-- add this key to enable subdomains such as sub.yourserver.com -->
<key>NSIncludesSubdomains</key>
<true/>
<!-- add this key to allow standard HTTP requests, thus negating the ATS -->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<!-- add this key to specify the minimum TLS version to accept -->
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
Info.plist
file)<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
Info.plist
file.<!-- changes this number to configure the maximum number of concurrent tasks -->
<key>FDMaximumConcurrentTasks</key>
<integer>5</integer>
Info.plist
file. (you can find the detail of Info.plist
localization in this link)<key>FDAllFilesDownloadedMessage</key>
<string>All files have been downloaded</string>
Note:
NSDocumentDirectory
Application
:Java:
// MyApplication.java (create this file if it doesn't exist in your project)
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;
import vn.hunghd.flutterdownloader.FlutterDownloaderPlugin;
public class MyApplication extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
@Override
public void registerWith(PluginRegistry registry) {
//
// Integration note:
//
// In Flutter, in order to work in background isolate, plugins need to register with
// a special instance of `FlutterEngine` that serves for background execution only.
// Hence, all (and only) plugins that require background execution feature need to
// call `registerWith` in this method.
//
// The default `GeneratedPluginRegistrant` will call `registerWith` of all plugins
// integrated in your application. Hence, if you are using `FlutterDownloaderPlugin`
// along with other plugins that need UI manipulation, you should register
// `FlutterDownloaderPlugin` and any 'background' plugins explicitly like this:
//
// FlutterDownloaderPlugin.registerWith(registry.registrarFor("vn.hunghd.flutterdownloader.FlutterDownloaderPlugin"));
//
GeneratedPluginRegistrant.registerWith(registry);
}
}
Or Kotlin:
// MyApplication.kt (create this file if it doesn't exist in your project)
import io.flutter.app.FlutterApplication
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugins.GeneratedPluginRegistrant;
import vn.hunghd.flutterdownloader.FlutterDownloaderPlugin
internal class MyApplication : FlutterApplication(), PluginRegistry.PluginRegistrantCallback {
override fun registerWith(registry: PluginRegistry) {
//
// Integration note:
//
// In Flutter, in order to work in background isolate, plugins need to register with
// a special instance of `FlutterEngine` that serves for background execution only.
// Hence, all (and only) plugins that require background execution feature need to
// call `registerWith` in this method.
//
// The default `GeneratedPluginRegistrant` will call `registerWith` of all plugins
// integrated in your application. Hence, if you are using `FlutterDownloaderPlugin`
// along with other plugins that need UI manipulation, you should register
// `FlutterDownloaderPlugin` and any 'background' plugins explicitly like this:
//
// FlutterDownloaderPlugin.registerWith(registry.registrarFor("vn.hunghd.flutterdownloader.FlutterDownloaderPlugin"))
//
GeneratedPluginRegistrant.registerWith(registry)
}
}
And update AndroidManifest.xml
<!-- AndroidManifest.xml -->
<application
android:name=".MyApplication"
....>
AndroidManifest.xml
:<provider
android:name="vn.hunghd.flutterdownloader.DownloadedFileProvider"
android:authorities="${applicationId}.flutter_downloader.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
Note:
WorkManager
library and WorkManager
depends on the number of available processor to configure the maximum number of tasks running at a moment. You can setup a fixed number for this configuration by adding following codes to your AndroidManifest.xml
: <provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:enabled="false"
android:exported="false" />
<provider
android:name="vn.hunghd.flutterdownloader.FlutterDownloaderInitializer"
android:authorities="${applicationId}.flutter-downloader-init"
android:exported="false">
<!-- changes this number to configure the maximum number of concurrent tasks -->
<meta-data
android:name="vn.hunghd.flutterdownloader.MAX_CONCURRENT_TASKS"
android:value="5" />
</provider>
<string name="flutter_downloader_notification_started">Download started</string>
<string name="flutter_downloader_notification_in_progress">Download in progress</string>
<string name="flutter_downloader_notification_canceled">Download canceled</string>
<string name="flutter_downloader_notification_failed">Download failed</string>
<string name="flutter_downloader_notification_complete">Download complete</string>
<string name="flutter_downloader_notification_paused">Download paused</string>
REQUEST_INSTALL_PACKAGES
permission. Add following codes in your AndroidManifest.xml
:<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
import 'package:flutter_downloader/flutter_downloader.dart';
await FlutterDownloader.initialize();
final taskId = await FlutterDownloader.enqueue(
url: 'your download link',
savedDir: 'the path of directory where you want to save downloaded files',
showNotification: true, // show download progress in status bar (for Android)
openFileFromNotification: true, // click on notification to open downloaded file (for Android)
);
FlutterDownloader.registerCallback(callback); // callback is a top-level or static function
Important note: your UI is rendered in the main isolate, while download events come from a background isolate (in other words, codes in callback
are run in the background isolate), so you have to handle the communication between two isolates. For example:
ReceivePort _port = ReceivePort();
@override
void initState() {
super.initState();
IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
setState((){ });
});
FlutterDownloader.registerCallback(downloadCallback);
}
@override
void dispose() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
super.dispose();
}
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port');
send.send([id, status, progress]);
}
final tasks = await FlutterDownloader.loadTasks();
final tasks = await FlutterDownloader.loadTasksWithRawQuery(query: query);
DownloadTask
object successfully, you should load data with all fields from DB (in the other word, use: SELECT *
). For example:SELECT * FROM task WHERE status=3
task
table where this plugin stores tasks informationCREATE TABLE `task` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`task_id` VARCHAR ( 256 ),
`url` TEXT,
`status` INTEGER DEFAULT 0,
`progress` INTEGER DEFAULT 0,
`file_name` TEXT,
`saved_dir` TEXT,
`resumable` TINYINT DEFAULT 0,
`headers` TEXT,
`show_notification` TINYINT DEFAULT 0,
`open_file_from_notification` TINYINT DEFAULT 0,
`time_created` INTEGER DEFAULT 0
);
FlutterDownloader.cancel(taskId: taskId);
FlutterDownloader.cancelAll();
FlutterDownloader.pause(taskId: taskId);
FlutterDownloader.resume(taskId: taskId);
resume()
will return a new taskId
corresponding to a new background task that is created to continue the download process. You should replace the original taskId
(that is marked as paused
status) by this new taskId
to continue tracking the download progress.FlutterDownloader.retry(taskId: taskId);
retry()
will return a new taskId
(like resume()
)FlutterDownloader.remove(taskId: taskId, shouldDeleteContent:false);
FlutterDownloader.open(taskId: taskId);
If you encounter any problems feel free to open an issue. If you feel the library is missing a feature, please raise a ticket on Github. Pull request are also welcome.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。