Skip to content

Added useBackgroundUrSession key for default and background session configuration #254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions ios/Classes/SwiftFlutterUploaderPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
return
}

guard let useBackgroundUrSession = args["useBackgroundUrSession"] as? Bool else {
result(FlutterError(code: "invalid_flag", message: "useBackgroundUrSession must be set", details: nil))
return
}

uploadTaskWithURLWithCompletion(
url: url,
files: files,
Expand All @@ -136,6 +141,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
parameters: data,
tag: tag,
allowCellular: allowCellular,
useBackgroundUrSession: useBackgroundUrSession,
completion: { (task, error) in
if error != nil {
result(error!)
Expand Down Expand Up @@ -185,7 +191,12 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
return
}

binaryUploadTaskWithURLWithCompletion(url: url, file: fileUrl, method: method, headers: headers, tag: tag, allowCellular: allowCellular, completion: { (task, error) in
guard let useBackgroundUrSession = args["useBackgroundUrSession"] as? Bool else {
result(FlutterError(code: "invalid_flag", message: "useBackgroundUrSession must be set", details: nil))
return
}

binaryUploadTaskWithURLWithCompletion(url: url, file: fileUrl, method: method, headers: headers, tag: tag, allowCellular: allowCellular, useBackgroundUrSession: useBackgroundUrSession, completion: { (task, error) in
if error != nil {
result(error!)
} else if let uploadTask = task {
Expand Down Expand Up @@ -215,6 +226,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
headers: [String: Any?]?,
tag: String?,
allowCellular: Bool,
useBackgroundUrSession: Bool,
completion completionHandler:@escaping (URLSessionUploadTask?, FlutterError?) -> Void) {
let request = NSMutableURLRequest(url: url)
request.httpMethod = method
Expand All @@ -226,7 +238,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
}
}

completionHandler(self.urlSessionUploader.enqueueUploadTask(request as URLRequest, path: file.path, wifiOnly: !allowCellular), nil)
completionHandler(self.urlSessionUploader.enqueueUploadTask(request as URLRequest, path: file.path, wifiOnly: !allowCellular, backgroundConfigOnly: useBackgroundUrSession), nil)
}

private func uploadTaskWithURLWithCompletion(
Expand All @@ -237,6 +249,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
parameters data: [String: Any?]?,
tag: String?,
allowCellular: Bool,
useBackgroundUrSession: Bool,
completion completionHandler:@escaping (URLSessionUploadTask?, FlutterError?) -> Void) {
var flutterError: FlutterError?
let fileManager = FileManager.default
Expand Down Expand Up @@ -303,7 +316,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
return
}

self.makeRequest(path, url, method, headers, formData.contentType, formData.contentLength, allowCellular: allowCellular, completion: { (task, error) in
self.makeRequest(path, url, method, headers, formData.contentType, formData.contentLength, allowCellular: allowCellular, useBackgroundUrSession: useBackgroundUrSession, completion: { (task, error) in
completionHandler(task, error)
})
}
Expand All @@ -316,6 +329,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
_ contentType: String,
_ contentLength: UInt64,
allowCellular: Bool,
useBackgroundUrSession: Bool,
completion completionHandler: (URLSessionUploadTask?, FlutterError?) -> Void) {
let request = NSMutableURLRequest(url: url)
request.httpMethod = method
Expand All @@ -338,7 +352,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
return
}

completionHandler(urlSessionUploader.enqueueUploadTask(request as URLRequest, path: path, wifiOnly: !allowCellular), nil)
completionHandler(urlSessionUploader.enqueueUploadTask(request as URLRequest, path: path, wifiOnly: !allowCellular, backgroundConfigOnly: useBackgroundUrSession), nil)
}
}

Expand Down
57 changes: 37 additions & 20 deletions ios/Classes/URLSessionUploader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ struct Keys {
class URLSessionUploader: NSObject {
static let shared = URLSessionUploader()

var session: URLSession?
var wifiSession: URLSession?
var sessionBackground: URLSession?
var sessionDefault: URLSession?
var wifiSessionBackground: URLSession?
var wifiSessionDefault: URLSession?
let queue = OperationQueue()

// Accessing uploadedData & runningTaskById will require exclusive access
Expand All @@ -45,9 +47,9 @@ class URLSessionUploader: NSObject {
delegates.append(delegate)
}

func enqueueUploadTask(_ request: URLRequest, path: String, wifiOnly: Bool) -> URLSessionUploadTask? {
guard let session = self.session,
let wifiSession = self.wifiSession else {
func enqueueUploadTask(_ request: URLRequest, path: String, wifiOnly: Bool, backgroundConfigOnly: Bool) -> URLSessionUploadTask? {
guard let session = backgroundConfigOnly ? self.sessionBackground : self.sessionDefault,
let wifiSession = backgroundConfigOnly ? self.wifiSessionBackground : self.wifiSessionDefault else {
return nil
}

Expand Down Expand Up @@ -76,12 +78,12 @@ class URLSessionUploader: NSObject {
///
/// The description on URLSessionTask.taskIdentifier explains how the task is only unique within a session.
public func identifierForTask(_ task: URLSessionUploadTask) -> String {
return "\(self.session?.configuration.identifier ?? "chillisoure.flutter_uploader").\(task.taskDescription!)"
return "\(self.sessionDefault?.configuration.identifier ?? "chillisoure.flutter_uploader").\(task.taskDescription!)"
}

/// Cancel a task by ID. Complete with `true`/`false` depending on whether the task was running.
func cancelWithTaskId(_ taskId: String) {
guard let session = session else {
guard let session = sessionDefault else {
return
}

Expand All @@ -100,7 +102,7 @@ class URLSessionUploader: NSObject {

/// Cancel all running tasks & return the list of canceled tasks.
func cancelAllTasks() {
session?.getTasksWithCompletionHandler { (_, uploadTasks, _) in
sessionDefault?.getTasksWithCompletionHandler { (_, uploadTasks, _) in
for uploadTask in uploadTasks {
let state = uploadTask.state
let taskId = self.identifierForTask(uploadTask)
Expand Down Expand Up @@ -145,18 +147,33 @@ class URLSessionUploader: NSObject {

self.queue.maxConcurrentOperationCount = maxUploadOperation.intValue

// configure session for wifi only uploads
let wifiConfiguration = URLSessionConfiguration.background(withIdentifier: Keys.wifiBackgroundSessionIdentifier)
wifiConfiguration.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
wifiConfiguration.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
wifiConfiguration.allowsCellularAccess = false
self.wifiSession = URLSession(configuration: wifiConfiguration, delegate: self, delegateQueue: queue)

// configure regular session
let sessionConfiguration = URLSessionConfiguration.background(withIdentifier: Keys.backgroundSessionIdentifier)
sessionConfiguration.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
sessionConfiguration.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
self.session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: queue)
// configure background session for wifi only uploads
let wifiConfigurationBackground = URLSessionConfiguration.background(withIdentifier: Keys.wifiBackgroundSessionIdentifier)
wifiConfigurationBackground.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
wifiConfigurationBackground.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
wifiConfigurationBackground.allowsCellularAccess = false
self.wifiSessionBackground = URLSession(configuration: wifiConfigurationBackground, delegate: self, delegateQueue: queue)

// configure default session for wifi only uploads
let wifiConfigurationDefault = URLSessionConfiguration.default
wifiConfigurationDefault.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
wifiConfigurationDefault.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
wifiConfigurationDefault.allowsCellularAccess = false
wifiConfigurationDefault.waitsForConnectivity = true
self.wifiSessionDefault = URLSession(configuration: wifiConfigurationDefault, delegate: self, delegateQueue: queue)

// configure background regular session
let sessionConfigurationBackground = URLSessionConfiguration.background(withIdentifier: Keys.backgroundSessionIdentifier)
sessionConfigurationBackground.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
sessionConfigurationBackground.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
self.sessionBackground = URLSession(configuration: sessionConfigurationBackground, delegate: self, delegateQueue: queue)

// configure default regular session
let sessionConfigurationDefault = URLSessionConfiguration.default
sessionConfigurationDefault.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
sessionConfigurationDefault.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
sessionConfigurationDefault.waitsForConnectivity = true
self.sessionDefault = URLSession(configuration: sessionConfigurationDefault, delegate: self, delegateQueue: queue)
}

private static func determineTimeout() -> Double {
Expand Down
4 changes: 3 additions & 1 deletion ios/Classes/UploadTask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ struct UploadTask {
let progress: Int
let tag: String?
let allowCellular: Bool
let useBackgroundUrSession: Bool

init(taskId: String, status: UploadTaskStatus, progress: Int, tag: String? = nil, allowCellular: Bool = true) {
init(taskId: String, status: UploadTaskStatus, progress: Int, tag: String? = nil, allowCellular: Bool = true, useBackgroundUrSession: Bool = true) {
self.taskId = taskId
self.status = status
self.progress = progress
self.tag = tag
self.allowCellular = allowCellular
self.useBackgroundUrSession = useBackgroundUrSession
}
}
2 changes: 2 additions & 0 deletions lib/src/flutter_uploader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class FlutterUploader {
'data': upload.data,
'tag': upload.tag,
'allowCellular': upload.allowCellular,
'useBackgroundUrSession': upload.useBackgroundUrSession,
}))!;
}
if (upload is RawUpload) {
Expand All @@ -118,6 +119,7 @@ class FlutterUploader {
'headers': upload.headers,
'tag': upload.tag,
'allowCellular': upload.allowCellular,
'useBackgroundUrSession': upload.useBackgroundUrSession,
}))!;
}

Expand Down
10 changes: 10 additions & 0 deletions lib/src/upload.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ abstract class Upload {
this.headers = const <String, String>{},
this.tag,
this.allowCellular = true,
this.useBackgroundUrSession = true,
});

/// Upload link
Expand All @@ -27,6 +28,11 @@ abstract class Upload {
/// If uploads are allowed to use cellular connections
/// Defaults to true. If false, uploads will only use wifi connections
final bool allowCellular;

/// iOS Only
/// If uploads are done using UrlSessionConfig set to background mode.
/// Defaults to true. If false, default UrlSessionConfig is used
final bool useBackgroundUrSession;
}

/// Standard RFC 2388 multipart/form-data upload.
Expand All @@ -42,13 +48,15 @@ class MultipartFormDataUpload extends Upload {
this.files,
this.data,
bool allowCellular = true,
bool useBackgroundUrSession = true,
}) : assert(files != null || data != null),
super(
url: url,
method: method,
headers: headers,
tag: tag,
allowCellular: allowCellular,
useBackgroundUrSession: useBackgroundUrSession,
) {
// Need to specify either files or data.
assert(files!.isNotEmpty || data!.isNotEmpty);
Expand All @@ -71,12 +79,14 @@ class RawUpload extends Upload {
String? tag,
this.path,
bool allowCellular = true,
bool useBackgroundUrSession = true,
}) : super(
url: url,
method: method,
headers: headers,
tag: tag,
allowCellular: allowCellular,
useBackgroundUrSession: useBackgroundUrSession,
);

/// single file to upload
Expand Down