Skip to content

Commit 874f6a4

Browse files
authored
#187 Add allowCellular flag to Upload (#188)
#187 Add allowCellular flag to Upload
1 parent de6e842 commit 874f6a4

File tree

11 files changed

+141
-17
lines changed

11 files changed

+141
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## Unreleased
2+
3+
- Add flag to restrict uploads to wifi only
4+
15
## 3.0.0-beta.2
26

37
- Android: Restore concurrency setting for uploads (#174).

android/src/main/java/com/bluechilli/flutteruploader/MethodCallHandlerImpl.java

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ private void enqueue(MethodCall call, MethodChannel.Result result) {
9292
Map<String, String> parameters = call.argument("data");
9393
Map<String, String> headers = call.argument("headers");
9494
String tag = call.argument("tag");
95+
Boolean allowCellular = call.argument("allowCellular");
96+
if (allowCellular == null) {
97+
result.error("invalid_flag", "allowCellular must be set", null);
98+
return;
99+
}
95100

96101
if (method == null) {
97102
method = "POST";
@@ -115,7 +120,17 @@ private void enqueue(MethodCall call, MethodChannel.Result result) {
115120

116121
WorkRequest request =
117122
buildRequest(
118-
new UploadTask(url, method, items, headers, parameters, connectionTimeout, false, tag));
123+
new UploadTask(
124+
url,
125+
method,
126+
items,
127+
headers,
128+
parameters,
129+
connectionTimeout,
130+
false,
131+
tag,
132+
allowCellular));
133+
119134
WorkManager.getInstance(context)
120135
.enqueue(request)
121136
.getResult()
@@ -137,6 +152,12 @@ private void enqueueBinary(MethodCall call, MethodChannel.Result result) {
137152
String path = call.argument("path");
138153
Map<String, String> headers = call.argument("headers");
139154
String tag = call.argument("tag");
155+
Boolean allowCellular = call.argument("allowCellular");
156+
157+
if (allowCellular == null) {
158+
result.error("invalid_flag", "allowCellular must be set", null);
159+
return;
160+
}
140161

141162
if (method == null) {
142163
method = "POST";
@@ -162,7 +183,9 @@ private void enqueueBinary(MethodCall call, MethodChannel.Result result) {
162183
Collections.emptyMap(),
163184
connectionTimeout,
164185
true,
165-
tag));
186+
tag,
187+
allowCellular));
188+
166189
WorkManager.getInstance(context)
167190
.enqueue(request)
168191
.getResult()
@@ -231,9 +254,13 @@ private WorkRequest buildRequest(UploadTask task) {
231254
dataBuilder.putString(UploadWorker.ARG_DATA, parametersJson);
232255
}
233256

257+
Constraints constraints =
258+
new Constraints.Builder()
259+
.setRequiredNetworkType(
260+
task.isAllowCellular() ? NetworkType.CONNECTED : NetworkType.UNMETERED)
261+
.build();
234262
return new OneTimeWorkRequest.Builder(UploadWorker.class)
235-
.setConstraints(
236-
new Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build())
263+
.setConstraints(constraints)
237264
.addTag(FLUTTER_UPLOAD_WORK_TAG)
238265
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 5, TimeUnit.SECONDS)
239266
.setInputData(dataBuilder.build())

android/src/main/java/com/bluechilli/flutteruploader/UploadTask.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class UploadTask {
1414
private int requestTimeoutInSeconds;
1515
private boolean binaryUpload;
1616
private String tag;
17+
private boolean allowCellular;
1718

1819
public UploadTask(
1920
String url,
@@ -23,7 +24,8 @@ public UploadTask(
2324
Map<String, String> data,
2425
int requestTimeoutInSeconds,
2526
boolean binaryUpload,
26-
String tag) {
27+
String tag,
28+
boolean allowCellular) {
2729
this.url = url;
2830
this.method = method;
2931
this.files = files;
@@ -32,6 +34,7 @@ public UploadTask(
3234
this.requestTimeoutInSeconds = requestTimeoutInSeconds;
3335
this.binaryUpload = binaryUpload;
3436
this.tag = tag;
37+
this.allowCellular = allowCellular;
3538
}
3639

3740
public String getURL() {
@@ -69,4 +72,8 @@ public boolean isBinaryUpload() {
6972
public String getTag() {
7073
return tag;
7174
}
75+
76+
public boolean isAllowCellular() {
77+
return allowCellular;
78+
}
7279
}

example/lib/main.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class App extends StatefulWidget {
117117
class _AppState extends State<App> {
118118
int _currentIndex = 0;
119119

120+
bool allowCellular = true;
121+
120122
@override
121123
void initState() {
122124
super.initState();
@@ -139,6 +141,16 @@ class _AppState extends State<App> {
139141
initializationSettings,
140142
onSelectNotification: (payload) async {},
141143
);
144+
145+
SharedPreferences.getInstance()
146+
.then((sp) => sp.getBool('allowCellular') ?? true)
147+
.then((result) {
148+
if (mounted) {
149+
setState(() {
150+
allowCellular = result;
151+
});
152+
}
153+
});
142154
}
143155

144156
@override
@@ -149,6 +161,24 @@ class _AppState extends State<App> {
149161
primarySwatch: Colors.blue,
150162
),
151163
home: Scaffold(
164+
appBar: AppBar(
165+
actions: [
166+
IconButton(
167+
icon: Icon(allowCellular
168+
? Icons.signal_cellular_connected_no_internet_4_bar
169+
: Icons.wifi_outlined),
170+
onPressed: () async {
171+
final sp = await SharedPreferences.getInstance();
172+
await sp.setBool('allowCellular', !allowCellular);
173+
if (mounted) {
174+
setState(() {
175+
allowCellular = !allowCellular;
176+
});
177+
}
178+
},
179+
),
180+
],
181+
),
152182
body: _currentIndex == 0
153183
? UploadScreen(
154184
uploader: _uploader,

example/lib/upload_screen.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,19 @@ class _UploadScreenState extends State<UploadScreen> {
199199
void _handleFileUpload(List<String?> paths) async {
200200
final prefs = await SharedPreferences.getInstance();
201201
final binary = prefs.getBool('binary') ?? false;
202+
final allowCellular = prefs.getBool('allowCellular') ?? true;
202203

203204
await widget.uploader.enqueue(_buildUpload(
204205
binary,
205206
paths.whereType<String>().toList(),
207+
allowCellular,
206208
));
207209

208210
widget.onUploadStarted();
209211
}
210212

211-
Upload _buildUpload(bool binary, List<String> paths) {
213+
Upload _buildUpload(bool binary, List<String> paths,
214+
[bool allowCellular = true]) {
212215
final tag = 'upload';
213216

214217
var url = binary
@@ -225,6 +228,7 @@ class _UploadScreenState extends State<UploadScreen> {
225228
path: paths.first,
226229
method: UploadMethod.POST,
227230
tag: tag,
231+
allowCellular: allowCellular,
228232
);
229233
} else {
230234
return MultipartFormDataUpload(
@@ -233,6 +237,7 @@ class _UploadScreenState extends State<UploadScreen> {
233237
files: paths.map((e) => FileItem(path: e, field: 'file')).toList(),
234238
method: UploadMethod.POST,
235239
tag: tag,
240+
allowCellular: allowCellular,
236241
);
237242
}
238243
}

ios/Classes/SwiftFlutterUploaderPlugin.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,19 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
123123
return
124124
}
125125

126+
guard let allowCellular = args["allowCellular"] as? Bool else {
127+
result(FlutterError(code: "invalid_flag", message: "allowCellular must be set", details: nil))
128+
return
129+
}
130+
126131
uploadTaskWithURLWithCompletion(
127132
url: url,
128133
files: files,
129134
method: method,
130135
headers: headers,
131136
parameters: data,
132137
tag: tag,
138+
allowCellular: allowCellular,
133139
completion: { (task, error) in
134140
if error != nil {
135141
result(error!)
@@ -174,7 +180,12 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
174180
return
175181
}
176182

177-
binaryUploadTaskWithURLWithCompletion(url: url, file: fileUrl, method: method, headers: headers, tag: tag, completion: { (task, error) in
183+
guard let allowCellular = args["allowCellular"] as? Bool else {
184+
result(FlutterError(code: "invalid_flag", message: "allowCellular must be set", details: nil))
185+
return
186+
}
187+
188+
binaryUploadTaskWithURLWithCompletion(url: url, file: fileUrl, method: method, headers: headers, tag: tag, allowCellular: allowCellular, completion: { (task, error) in
178189
if error != nil {
179190
result(error!)
180191
} else if let uploadTask = task {
@@ -203,6 +214,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
203214
method: String,
204215
headers: [String: Any?]?,
205216
tag: String?,
217+
allowCellular: Bool,
206218
completion completionHandler:@escaping (URLSessionUploadTask?, FlutterError?) -> Void) {
207219
let request = NSMutableURLRequest(url: url)
208220
request.httpMethod = method
@@ -214,7 +226,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
214226
}
215227
}
216228

217-
completionHandler(self.urlSessionUploader.enqueueUploadTask(request as URLRequest, path: file.path), nil)
229+
completionHandler(self.urlSessionUploader.enqueueUploadTask(request as URLRequest, path: file.path, wifiOnly: !allowCellular), nil)
218230
}
219231

220232
private func uploadTaskWithURLWithCompletion(
@@ -224,6 +236,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
224236
headers: [String: Any?]?,
225237
parameters data: [String: Any?]?,
226238
tag: String?,
239+
allowCellular: Bool,
227240
completion completionHandler:@escaping (URLSessionUploadTask?, FlutterError?) -> Void) {
228241
var flutterError: FlutterError?
229242
let fileManager = FileManager.default
@@ -290,7 +303,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
290303
return
291304
}
292305

293-
self.makeRequest(path, url, method, headers, formData.contentType, formData.contentLength, completion: { (task, error) in
306+
self.makeRequest(path, url, method, headers, formData.contentType, formData.contentLength, allowCellular: allowCellular, completion: { (task, error) in
294307
completionHandler(task, error)
295308
})
296309
}
@@ -302,6 +315,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
302315
_ headers: [String: Any?]? = [:],
303316
_ contentType: String,
304317
_ contentLength: UInt64,
318+
allowCellular: Bool,
305319
completion completionHandler: (URLSessionUploadTask?, FlutterError?) -> Void) {
306320
let request = NSMutableURLRequest(url: url)
307321
request.httpMethod = method
@@ -324,7 +338,7 @@ public class SwiftFlutterUploaderPlugin: NSObject, FlutterPlugin {
324338
return
325339
}
326340

327-
completionHandler(urlSessionUploader.enqueueUploadTask(request as URLRequest, path: path), nil)
341+
completionHandler(urlSessionUploader.enqueueUploadTask(request as URLRequest, path: path, wifiOnly: !allowCellular), nil)
328342
}
329343
}
330344

ios/Classes/URLSessionUploader.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Foundation
99

1010
struct Keys {
1111
static let backgroundSessionIdentifier = "chillisource.flutter_uploader.upload.background"
12+
static let wifiBackgroundSessionIdentifier = "chillisource.flutter_uploader.upload.background.wifi"
1213
fileprivate static let maximumConcurrentTask = "FUMaximumConnectionsPerHost"
1314
fileprivate static let maximumConcurrentUploadOperation = "FUMaximumUploadOperation"
1415

@@ -20,6 +21,7 @@ class URLSessionUploader: NSObject {
2021
static let shared = URLSessionUploader()
2122

2223
var session: URLSession?
24+
var wifiSession: URLSession?
2325
let queue = OperationQueue()
2426

2527
// Accessing uploadedData & runningTaskById will require exclusive access
@@ -43,12 +45,17 @@ class URLSessionUploader: NSObject {
4345
delegates.append(delegate)
4446
}
4547

46-
func enqueueUploadTask(_ request: URLRequest, path: String) -> URLSessionUploadTask? {
47-
guard let session = self.session else {
48+
func enqueueUploadTask(_ request: URLRequest, path: String, wifiOnly: Bool) -> URLSessionUploadTask? {
49+
guard let session = self.session,
50+
let wifiSession = self.wifiSession else {
4851
return nil
4952
}
5053

51-
let uploadTask = session.uploadTask(with: request as URLRequest, fromFile: URL(fileURLWithPath: path))
54+
let activeSession = wifiOnly ? wifiSession : session
55+
let uploadTask = activeSession.uploadTask(
56+
with: request as URLRequest,
57+
fromFile: URL(fileURLWithPath: path)
58+
)
5259

5360
// Create a random UUID as task description (& ID).
5461
uploadTask.taskDescription = UUID().uuidString
@@ -138,6 +145,14 @@ class URLSessionUploader: NSObject {
138145

139146
self.queue.maxConcurrentOperationCount = maxUploadOperation.intValue
140147

148+
// configure session for wifi only uploads
149+
let wifiConfiguration = URLSessionConfiguration.background(withIdentifier: Keys.wifiBackgroundSessionIdentifier)
150+
wifiConfiguration.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
151+
wifiConfiguration.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()
152+
wifiConfiguration.allowsCellularAccess = false
153+
self.wifiSession = URLSession(configuration: wifiConfiguration, delegate: self, delegateQueue: queue)
154+
155+
// configure regular session
141156
let sessionConfiguration = URLSessionConfiguration.background(withIdentifier: Keys.backgroundSessionIdentifier)
142157
sessionConfiguration.httpMaximumConnectionsPerHost = maxConcurrentTasks.intValue
143158
sessionConfiguration.timeoutIntervalForRequest = URLSessionUploader.determineTimeout()

ios/Classes/UploadTask.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ struct UploadTask {
1616
let status: UploadTaskStatus
1717
let progress: Int
1818
let tag: String?
19+
let allowCellular: Bool
1920

20-
init(taskId: String, status: UploadTaskStatus, progress: Int, tag: String? = nil) {
21+
init(taskId: String, status: UploadTaskStatus, progress: Int, tag: String? = nil, allowCellular: Bool = true) {
2122
self.taskId = taskId
2223
self.status = status
2324
self.progress = progress
2425
self.tag = tag
26+
self.allowCellular = allowCellular
2527
}
2628
}

lib/src/flutter_uploader.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class FlutterUploader {
107107
'headers': upload.headers,
108108
'data': upload.data,
109109
'tag': upload.tag,
110+
'allowCellular': upload.allowCellular,
110111
}))!;
111112
}
112113
if (upload is RawUpload) {
@@ -115,7 +116,8 @@ class FlutterUploader {
115116
'method': describeEnum(upload.method),
116117
'path': upload.path,
117118
'headers': upload.headers,
118-
'tag': upload.tag
119+
'tag': upload.tag,
120+
'allowCellular': upload.allowCellular,
119121
}))!;
120122
}
121123

0 commit comments

Comments
 (0)