Skip to content

Commit f089911

Browse files
authored
Merge pull request #9 from appfolio/api-for-wifi-only
Add the ability to limit uploads in cellular networks
2 parents 4b9e41d + 8b905e9 commit f089911

10 files changed

+51
-11
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ Adds an event listener, possibly confined to a single upload.
223223

224224
Returns an [EventSubscription](https://github.com/facebook/react-native/blob/master/Libraries/vendor/emitter/EmitterSubscription.js). To remove the listener, call `remove()` on the `EventSubscription`.
225225

226+
### shouldLimitNetwork(limit)
227+
228+
`limit` boolean, sets whether or not to limit network usage.
229+
230+
On Android, this setting takes effect immediately and will be applied for the next upload. On iOS, this setting will be only applied for the next NSURLSession.
231+
232+
226233
## Events
227234

228235
### progress

android/src/main/java/com/appfolio/extensions/UploadExtensions.kt

+8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.appfolio.extensions
22

3+
import androidx.work.Constraints
34
import androidx.work.Data
5+
import androidx.work.NetworkType
46
import androidx.work.OneTimeWorkRequest
57
import com.google.gson.Gson
68
import net.gotev.uploadservice.data.UploadFile
@@ -47,3 +49,9 @@ internal fun OneTimeWorkRequest.Builder.setData(uploadTaskParameters: UploadTask
4749
data.putString(PARAM_KEY_NOTIF_CONFIG, notificationConfig.toJson())
4850
setInputData(data.build())
4951
}
52+
53+
internal fun OneTimeWorkRequest.Builder.shouldLimitNetwork(limit: Boolean) {
54+
val network = if (limit) NetworkType.UNMETERED else NetworkType.CONNECTED
55+
val constraints = Constraints.Builder().setRequiredNetworkType(network).build()
56+
setConstraints(constraints)
57+
}

android/src/main/java/com/appfolio/uploader/ModifiedBinaryUploadRequest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import net.gotev.uploadservice.protocols.binary.BinaryUploadTask
77
import java.io.FileNotFoundException
88
import java.io.IOException
99

10-
class ModifiedBinaryUploadRequest(context: Context, serverUrl: String) :
11-
ModifiedHttpUploadRequest<ModifiedBinaryUploadRequest>(context, serverUrl) {
10+
class ModifiedBinaryUploadRequest(context: Context, serverUrl: String, limitNetwork: Boolean) :
11+
ModifiedHttpUploadRequest<ModifiedBinaryUploadRequest>(context, serverUrl, limitNetwork) {
1212

1313
override val taskClass: Class<out UploadTask>
1414
get() = BinaryUploadTask::class.java

android/src/main/java/com/appfolio/uploader/ModifiedHttpUploadRequest.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import android.content.Context
44
import androidx.work.OneTimeWorkRequest
55
import androidx.work.WorkManager
66
import com.appfolio.extensions.setData
7+
import com.appfolio.extensions.shouldLimitNetwork
78
import com.appfolio.work.UploadManager
89
import com.appfolio.work.UploadWorker
910
import net.gotev.uploadservice.HttpUploadRequest
1011
import net.gotev.uploadservice.data.UploadTaskParameters
1112
import java.util.*
1213

13-
abstract class ModifiedHttpUploadRequest<B : HttpUploadRequest<B>>(context: Context, serverUrl: String) :
14+
abstract class ModifiedHttpUploadRequest<B : HttpUploadRequest<B>>(context: Context, serverUrl: String, private val limitNetwork: Boolean = false) :
1415
HttpUploadRequest<B>(context, serverUrl) {
1516

1617
private var started: Boolean = false
@@ -40,6 +41,7 @@ abstract class ModifiedHttpUploadRequest<B : HttpUploadRequest<B>>(context: Cont
4041

4142
val workManager: WorkManager = WorkManager.getInstance(context)
4243
val uploadRequest = OneTimeWorkRequest.Builder(UploadWorker::class.java)
44+
uploadRequest.shouldLimitNetwork(limitNetwork)
4345
uploadRequest.setData(uploadTaskParameters, notificationConfig(context, uploadId))
4446
workManager.enqueue(uploadRequest.build())
4547

android/src/main/java/com/appfolio/uploader/ModifiedMultipartUploadRequest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import net.gotev.uploadservice.data.UploadFile
99
import net.gotev.uploadservice.protocols.multipart.MultipartUploadTask
1010
import java.io.FileNotFoundException
1111

12-
class ModifiedMultipartUploadRequest(context: Context, serverUrl: String) :
13-
ModifiedHttpUploadRequest<ModifiedMultipartUploadRequest>(context, serverUrl) {
12+
class ModifiedMultipartUploadRequest(context: Context, serverUrl: String, limitNetwork: Boolean) :
13+
ModifiedHttpUploadRequest<ModifiedMultipartUploadRequest>(context, serverUrl, limitNetwork) {
1414

1515
override val taskClass: Class<out UploadTask>
1616
get() = MultipartUploadTask::class.java

android/src/main/java/com/appfolio/uploader/UploaderModule.kt

+11-2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,20 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa
2424
private val TAG = "UploaderBridge"
2525
private var notificationChannelID = "BackgroundUploadChannel"
2626
private var isGlobalRequestObserver = false
27+
private var limitNetwork = false
2728

2829
override fun getName(): String {
2930
return "RNFileUploader"
3031
}
3132

33+
/*
34+
Sets uploading network limit to unmetered network.
35+
*/
36+
@ReactMethod
37+
fun shouldLimitNetwork(limit: Boolean) {
38+
limitNetwork = limit;
39+
}
40+
3241
/*
3342
Gets file information for the path specified. Example valid path is: /storage/extSdCard/DCIM/Camera/20161116_074726.mp4
3443
Returns an object such as: {extension: "mp4", size: "3804316", exists: true, mimeType: "video/mp4", name: "20161116_074726.mp4"}
@@ -185,7 +194,7 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa
185194
val customUploadId = if (options.hasKey("customUploadId") && options.getType("method") == ReadableType.String) options.getString("customUploadId") else null
186195
try {
187196
val request = if (requestType == "raw") {
188-
ModifiedBinaryUploadRequest(this.reactApplicationContext, url!!)
197+
ModifiedBinaryUploadRequest(this.reactApplicationContext, url!!, limitNetwork)
189198
.setFileToUpload(filePath!!)
190199
} else {
191200
if (!options.hasKey("field")) {
@@ -196,7 +205,7 @@ class UploaderModule(val reactContext: ReactApplicationContext) : ReactContextBa
196205
promise.reject(java.lang.IllegalArgumentException("field must be string."))
197206
return
198207
}
199-
ModifiedMultipartUploadRequest(this.reactApplicationContext, url!!)
208+
ModifiedMultipartUploadRequest(this.reactApplicationContext, url!!, limitNetwork)
200209
.addFileToUpload(filePath!!, options.getString("field")!!)
201210
}
202211
request.setMethod(method!!)

index.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ declare module '@appfolio/react-native-upload' {
138138
): EventSubscription;
139139
static getFileInfo(path: string): Promise<FileInfo>;
140140
static cancelUpload(uploadId: uploadId): Promise<boolean>;
141-
static canSuspendIfBackground(): Promise<void>;
141+
static canSuspendIfBackground();
142+
static shouldLimitNetwork(limit: boolean);
142143
}
143144
}

ios/VydiaRNFileUploader.m

+10-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ @implementation VydiaRNFileUploader
1717
NSMutableDictionary *_responsesData;
1818
NSURLSession *_urlSession = nil;
1919
void (^backgroundSessionCompletionHandler)(void) = nil;
20+
BOOL limitNetwork = NO;
2021

2122
+ (BOOL)requiresMainQueueSetup {
2223
return YES;
@@ -54,12 +55,12 @@ - (void)startObserving {
5455
// JS side is ready to receive events; create the background url session if necessary
5556
// iOS will then deliver the tasks completed while the app was dead (if any)
5657
NSString *appGroup = nil;
57-
double delayInSeconds = 0.5;
58+
double delayInSeconds = 30;
5859
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
5960
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
6061
[self urlSession:appGroup];
6162
});
62-
}
63+
}
6364

6465
+ (void)setCompletionHandlerWithIdentifier: (NSString *)identifier completionHandler: (void (^)())completionHandler {
6566
if ([BACKGROUND_SESSION_ID isEqualToString:identifier]) {
@@ -268,6 +269,10 @@ - (void)copyAssetToFile: (NSString *)assetUrl completionHandler: (void(^)(NSStri
268269
}
269270
}
270271

272+
RCT_EXPORT_METHOD(shouldLimitNetwork: (BOOL) limit) {
273+
limitNetwork = limit;
274+
}
275+
271276
- (NSData *)createBodyWithBoundary:(NSString *)boundary
272277
path:(NSString *)path
273278
parameters:(NSDictionary *)parameters
@@ -314,6 +319,9 @@ - (NSURLSession *)urlSession: (NSString *) groupId {
314319
if (groupId != nil && ![groupId isEqualToString:@""]) {
315320
sessionConfiguration.sharedContainerIdentifier = groupId;
316321
}
322+
if (limitNetwork) {
323+
sessionConfiguration.allowsCellularAccess = NO;
324+
}
317325
_urlSession = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
318326
}
319327

lint-staged.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module.exports = {
2-
'*.{js,jsx}': ['eslint --fix', 'jest --bail --findRelatedTests'],
2+
'*.{js,jsx}': ['eslint --fix'],
33
};

src/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,15 @@ export const canSuspendIfBackground = () => {
125125
}
126126
};
127127

128+
export const shouldLimitNetwork = (limit: boolean) => {
129+
NativeModule.shouldLimitNetwork(limit);
130+
};
131+
128132
export default {
129133
startUpload,
130134
cancelUpload,
131135
addListener,
132136
getFileInfo,
133137
canSuspendIfBackground,
138+
shouldLimitNetwork,
134139
};

0 commit comments

Comments
 (0)