Skip to content

Commit

Permalink
V8.2.0 prep for publishing
Browse files Browse the repository at this point in the history
  • Loading branch information
781flyingdutchman committed Feb 14, 2024
1 parent 4990e15 commit 11941aa
Show file tree
Hide file tree
Showing 8 changed files with 22 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 8.2.0

* Adds `Future<bool> requireWiFi(RequireWiFi requirement, {final rescheduleRunningTasks = true})` to set a globally enforced WiFi requirement, and pause/resume or cancel/restart tasks accordingly. This is helpful when implementing a global toggle switch to prevent data download over metered (cellular) networks. iOS and Android only

## 8.1.0

* Adds `responseHeaders` to `TaskStatusUpdate` for tasks that complete successfully (null otherwise). Per Dart convention, header names are lower-cased
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ FileDownloader().configureNotification(
- [Canceling, pausing and resuming tasks](#canceling-pausing-and-resuming-tasks)
- [Grouping tasks](#grouping-tasks)
- [Task queues](#task-queues)
- [Changing WiFi requirements](#changing-wifi-requirements)
- [Server requests](#server-requests)
- [Cookies](#cookies)
- [Optional parameters](#optional-parameters)
Expand Down Expand Up @@ -774,6 +775,17 @@ A common use for the `MemoryTaskQueue` is enqueueing a large number of tasks. Th
The default `TaskQueue` is the `MemoryTaskQueue` which, as the name suggests, keeps everything in memory. This is fine for most situations, but be aware that the queue may get dropped if the OS aggressively moves the app to the background. Tasks still waiting in the queue will not be enqueued, and will therefore be lost. If you want a `TaskQueue` with more persistence, or add different prioritzation and concurrency roles, then subclass the `MemoryTaskQueue` and add your own persistence or logic.
In addition, if your app is supended by the OS due to resource constraints, tasks waiting in the queue will not be enqueued to the native platform and will not run in the background. TaskQueues are therefore best for situations where you expect the queue to be emptied while the app is still in the foreground.

### Changing WiFi requirements

By default, whether a task requires WiFi or not is determined by its `requireWiFi` property (iOS and Android only). To override this globally, call `FileDownloader().requireWifi` and pass one of the `RequireWiFi` enums:
* `asSetByTask` (default) lets the task's `requireWiFi` property determine if WiFi is required
* `forAllTasks` requires WiFi for all tasks
* `forNoTasks` does not require WiFi for any tasks

When calling `FileDownloader().requireWifi`, all enqueued tasks will be canceled and rescheduled with the appropriate WiFi requirement setting, and if the `rescheduleRunningTasks` parameter is true, all running tasks will be paused (if possible, independent of the task's `allowPause` property) or canceled and resumed/restarted with the new WiFi requirement. All newly enqueued tasks will follow this setting as well.

The global setting persists across application restarts. Check the current setting by calling `FileDownloader().getRequireWiFiSetting`.

## Server requests

To make a regular server request (e.g. to obtain a response from an API end point that you process directly in your app) use the `request` method. It works similar to the `download` method, except you pass a `Request` object that has fewer fields than the `DownloadTask`, but is similar in structure. You `await` the response, which will be a [Response](https://pub.dev/documentation/http/latest/http/Response-class.html) object as defined in the dart [http package](https://pub.dev/packages/http), and includes getters for the response body (as a `String` or as `UInt8List`), `statusCode` and `reasonPhrase`.
Expand Down Expand Up @@ -839,7 +851,7 @@ Note that certain failures can be resumed, and retries will therefore attempt to

#### Requiring WiFi

If the `requiresWiFi` field of a `Task` is set to true, the task won't start unless a WiFi network is available. By default `requiresWiFi` is false, and downloads/uploads will use the cellular (or metered) network if WiFi is not available, which may incur cost.
On Android and iOS only: If the `requiresWiFi` field of a `Task` is set to true, the task won't start unless a WiFi network is available. By default `requiresWiFi` is false, and downloads/uploads will use the cellular (or metered) network if WiFi is not available, which may incur cost. Note that every task requires a working internet connection: local server connections that do not reach the internet may not work.

#### Priority

Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ class _MyAppState extends State<MyApp> {
backgroundDownloadTask = DownloadTask(
url: downloadWithError
? 'https://avmaps-dot-bbflightserver-hrd.appspot.com/public/get_current_app_data' // returns 403 status code
: 'https://storage.googleapis.com/approachcharts/test/57MB-test.ZIP',
: 'https://storage.googleapis.com/approachcharts/test/5MB-test.ZIP',
filename: 'zipfile.zip',
directory: 'my/directory',
baseDirectory: BaseDirectory.applicationDocuments,
Expand Down
4 changes: 1 addition & 3 deletions ios/Classes/BDPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ public class BDPlugin: NSObject, FlutterPlugin, UNUserNotificationCenterDelegate
registrar.addApplicationDelegate(instance)
let defaults = UserDefaults.standard
requireWiFi = RequireWiFi(rawValue: defaults.integer(forKey: BDPlugin.keyRequireWiFi))!
os_log("requireWiFi=%d", log: log, type: .fault, requireWiFi.rawValue)
}

@objc
Expand Down Expand Up @@ -168,7 +167,7 @@ public class BDPlugin: NSObject, FlutterPlugin, UNUserNotificationCenterDelegate
}
}
isResume = isParallelDownloadTask(task: task) ? isResume : isResume && resumeData != nil
let verb = isResume ? "Resuming" : "Starting"
let verb = isResume ? "Enqueueing (to resume)" : "Enqueueing"
os_log("%@ task with id %@", log: log, type: .info, verb, task.taskId)
UrlSessionDelegate.createUrlSession()
let url: URL?
Expand Down Expand Up @@ -200,7 +199,6 @@ public class BDPlugin: NSObject, FlutterPlugin, UNUserNotificationCenterDelegate
_ = BDPlugin.taskIdsRequiringWiFi.insert(task.taskId)
}
}
os_log("Task %@ requires WiFi=%d", log: log, type: .fault, task.taskId, requiresWiFi)
if isParallelDownloadTask(task: task) {
// ParallelDownloadTask itself is not part of a urlSession, so handled separately
baseRequest.httpMethod = "HEAD" // override
Expand Down
4 changes: 1 addition & 3 deletions ios/Classes/TaskFunctions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,7 @@ func processStatusUpdate(task: Task, status: TaskStatus, taskException: TaskExce
// Intercept status updates resulting from re-enqueue requests, which
// themselves are triggered by a change in WiFi requirement
let intercepted = BDPlugin.propertyLock.withLock {
if BDPlugin.tasksToReEnqueue.contains(task) {
os_log("Task %@ with status %d needs to re-enqueue", log: log, type: .fault, task.taskId, status.rawValue)
BDPlugin.tasksToReEnqueue.remove(task)
if BDPlugin.tasksToReEnqueue.remove(task) != nil {
defer {
if BDPlugin.tasksToReEnqueue.isEmpty {
WiFiQueue.shared.reEnqueue(nil) // signal end of batch
Expand Down
1 change: 1 addition & 0 deletions ios/Classes/UrlSessionDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public class UrlSessionDelegate : NSObject, URLSessionDelegate, URLSessionDownlo
guard var task = getTaskFrom(urlSessionTask: downloadTask) else { return }
if BDPlugin.progressInfo[task.taskId] == nil {
// first 'didWriteData' call
os_log("Starting/resuming taskId %@", log: log, type: .info, task.taskId)
let response = downloadTask.response as! HTTPURLResponse
// get suggested filename if needed
if task.filename == "?" {
Expand Down
10 changes: 0 additions & 10 deletions ios/Classes/WiFi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class WiFiQueue {
func requireWiFiChange(requireWiFi: RequireWiFi, rescheduleRunningTasks: Bool) {
requireWiFiChangeQueue.async {
_Concurrency.Task {
os_log("requireWiFi=%d", log: log, type: .fault, requireWiFi.rawValue)
BDPlugin.requireWiFi = requireWiFi
let defaults = UserDefaults.standard
defaults.setValue(requireWiFi.rawValue, forKey: BDPlugin.keyRequireWiFi)
Expand All @@ -46,7 +45,6 @@ class WiFiQueue {
guard let task = getTaskFrom(urlSessionTask: urlSessionTask) else {
return
}
os_log("Checking taskId %@", log: log, type: .fault, task.taskId)
BDPlugin.propertyLock.withLock {
if taskRequiresWiFi(task: task) != BDPlugin.taskIdsRequiringWiFi.contains(task.taskId) {
// requirement differs, so we need to re-enqueue
Expand All @@ -56,14 +54,12 @@ class WiFiQueue {
BDPlugin.taskIdsRequiringWiFi.remove(task.taskId)
}
if BDPlugin.progressInfo[task.taskId] == nil {
os_log("TaskId %@ was enqueued, re-enqueueing", log: log, type: .fault, task.taskId)
// enqueued only, so ensure it is re-enqueued and cancel
haveReEnqueued = true
BDPlugin.tasksToReEnqueue.insert(task)
urlSessionTask.cancel()
} else {
if rescheduleRunningTasks {
os_log("TaskId %@ was running, re-enqueueing", log: log, type: .fault, task.taskId)
// already running, so pause instead of cancel
haveReEnqueued = true
BDPlugin.tasksToReEnqueue.insert(task)
Expand All @@ -72,8 +68,6 @@ class WiFiQueue {
}
}
}
} else {
os_log("No need to change taskId %@", log: log, type: .fault, task.taskId)
}
}
}
Expand All @@ -93,20 +87,16 @@ class WiFiQueue {

/// Re-enqueue this task and associated data. Nil signals end of batch
func reEnqueue(_ reEnqueueData: ReEnqueueData?) {
os_log("ReEnqueue entry for %@", log: log, type: .fault, reEnqueueData?.task.taskId ?? "nil")
reEnqueueQueue.async {
guard let reEnqueueData = reEnqueueData else {
os_log("reEnqueue with nil", log: log, type: .fault)
// nil value indicates end of batch of re-enqueues
self.reEnqueuesDone()
return
}
os_log("TaskId %@ waiting to re-enqueue", log: log, type: .fault, reEnqueueData.task.taskId)
let timeSinceCreated = Date().timeIntervalSince(reEnqueueData.created)
if timeSinceCreated < 0.3 {
Thread.sleep(forTimeInterval: 0.3 - timeSinceCreated)
}
os_log("TaskId %@ re-enqueueing", log: log, type: .fault, reEnqueueData.task.taskId)
BDPlugin.instance.doEnqueue(taskJsonString: jsonStringFor(task: reEnqueueData.task) ?? "", notificationConfigJsonString: reEnqueueData.notificationConfigJsonString, resumeDataAsBase64String: reEnqueueData.resumeDataAsBase64String, result: nil)
Thread.sleep(forTimeInterval: 0.02)
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: background_downloader
description: A multi-platform background file downloader and uploader. Define the task, enqueue and monitor progress

version: 8.1.0
version: 8.2.0
repository: https://github.com/781flyingdutchman/background_downloader

environment:
Expand Down

0 comments on commit 11941aa

Please sign in to comment.