diff --git a/.circleci/config.yml b/.circleci/config.yml index b9056680af6708..18448d2a1955e8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -451,6 +451,12 @@ jobs: # Keep configuring Android dependencies while AVD boots up + # Install Android NDK + - run: *create-ndk-directory + - restore-cache: *restore-cache-ndk + - run: *install-ndk + - save-cache: *save-cache-ndk + # Fetch dependencies using BUCK - restore-cache: *restore-cache-buck - run: *install-buck @@ -463,12 +469,6 @@ jobs: - run: buck fetch ReactAndroid/src/androidTest/... - run: ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog :ReactAndroid:downloadJSCHeaders - # Install Android NDK - - run: *create-ndk-directory - - restore-cache: *restore-cache-ndk - - run: *install-ndk - - save-cache: *save-cache-ndk - # Build and compile - run: *build-android-app - run: *compile-native-libs diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK index 16cd0430661520..4ce467af900c7e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/BUCK @@ -11,7 +11,6 @@ rn_android_library( ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/internal:internal"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index fe379bb1f2e414..3f483798c81162 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -343,11 +343,11 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } } - RequestBody requestBody; if (data == null) { - requestBody = RequestBodyUtil.getEmptyBody(method); + requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } else if (handler != null) { - requestBody = handler.toRequestBody(data, contentType); + RequestBody requestBody = handler.toRequestBody(data, contentType); + requestBuilder.method(method, requestBody); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { ResponseUtil.onRequestError( @@ -360,13 +360,14 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { String body = data.getString(REQUEST_BODY_KEY_STRING); MediaType contentMediaType = MediaType.parse(contentType); if (RequestBodyUtil.isGzipEncoding(contentEncoding)) { - requestBody = RequestBodyUtil.createGzip(contentMediaType, body); + RequestBody requestBody = RequestBodyUtil.createGzip(contentMediaType, body); if (requestBody == null) { ResponseUtil.onRequestError(eventEmitter, requestId, "Failed to gzip request body", null); return; } + requestBuilder.method(method, requestBody); } else { - requestBody = RequestBody.create(contentMediaType, body); + requestBuilder.method(method, RequestBody.create(contentMediaType, body)); } } else if (data.hasKey(REQUEST_BODY_KEY_BASE64)) { if (contentType == null) { @@ -379,7 +380,9 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } String base64String = data.getString(REQUEST_BODY_KEY_BASE64); MediaType contentMediaType = MediaType.parse(contentType); - requestBody = RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String)); + requestBuilder.method( + method, + RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); } else if (data.hasKey(REQUEST_BODY_KEY_URI)) { if (contentType == null) { ResponseUtil.onRequestError( @@ -400,7 +403,9 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { null); return; } - requestBody = RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream); + requestBuilder.method( + method, + RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; @@ -411,16 +416,28 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { if (multipartBuilder == null) { return; } - requestBody = multipartBuilder.build(); + + requestBuilder.method( + method, + RequestBodyUtil.createProgressRequest( + multipartBuilder.build(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (done || shouldDispatch(now, last)) { + ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); + last = now; + } + } + })); } else { // Nothing in data payload, at least nothing we could understand anyway. - requestBody = RequestBodyUtil.getEmptyBody(method); + requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } - requestBuilder.method( - method, - wrapRequestBodyWithProgressEmitter(requestBody, eventEmitter, requestId)); - addRequest(requestId); client.newCall(requestBuilder.build()).enqueue( new Callback() { @@ -498,29 +515,6 @@ public void onResponse(Call call, Response response) throws IOException { }); } - private RequestBody wrapRequestBodyWithProgressEmitter( - final RequestBody requestBody, - final RCTDeviceEventEmitter eventEmitter, - final int requestId) { - if(requestBody == null) { - return null; - } - return RequestBodyUtil.createProgressRequest( - requestBody, - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (done || shouldDispatch(now, last)) { - ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); - last = now; - } - } - }); - } - private void readWithProgress( RCTDeviceEventEmitter eventEmitter, int requestId, diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java index 0611e2ffc8093f..c519cfeb4155df 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java @@ -9,75 +9,60 @@ package com.facebook.react.modules.network; -import com.facebook.common.internal.CountingOutputStream; - import java.io.IOException; - import okhttp3.MediaType; import okhttp3.RequestBody; import okio.BufferedSink; -import okio.Okio; +import okio.Buffer; import okio.Sink; +import okio.ForwardingSink; +import okio.Okio; public class ProgressRequestBody extends RequestBody { private final RequestBody mRequestBody; private final ProgressListener mProgressListener; private BufferedSink mBufferedSink; - private long mContentLength = 0L; public ProgressRequestBody(RequestBody requestBody, ProgressListener progressListener) { - mRequestBody = requestBody; - mProgressListener = progressListener; + mRequestBody = requestBody; + mProgressListener = progressListener; } @Override public MediaType contentType() { - return mRequestBody.contentType(); + return mRequestBody.contentType(); } @Override public long contentLength() throws IOException { - if (mContentLength == 0) { - mContentLength = mRequestBody.contentLength(); - } - return mContentLength; + return mRequestBody.contentLength(); } @Override public void writeTo(BufferedSink sink) throws IOException { - if (mBufferedSink == null) { - mBufferedSink = Okio.buffer(outputStreamSink(sink)); - } - - // contentLength changes for input streams, since we're using inputStream.available(), - // so get the length before writing to the sink - contentLength(); - - mRequestBody.writeTo(mBufferedSink); - mBufferedSink.flush(); + if (mBufferedSink == null) { + mBufferedSink = Okio.buffer(sink(sink)); + } + mRequestBody.writeTo(mBufferedSink); + mBufferedSink.flush(); } - private Sink outputStreamSink(BufferedSink sink) { - return Okio.sink(new CountingOutputStream(sink.outputStream()) { - @Override - public void write(byte[] data, int offset, int byteCount) throws IOException { - super.write(data, offset, byteCount); - sendProgressUpdate(); - } + private Sink sink(Sink sink) { + return new ForwardingSink(sink) { + long bytesWritten = 0L; + long contentLength = 0L; - @Override - public void write(int data) throws IOException { - super.write(data); - sendProgressUpdate(); - } - - private void sendProgressUpdate() throws IOException { - long bytesWritten = getCount(); - long contentLength = contentLength(); - mProgressListener.onProgress( - bytesWritten, contentLength, bytesWritten == contentLength); - } - }); + @Override + public void write(Buffer source, long byteCount) throws IOException { + super.write(source, byteCount); + if (contentLength == 0) { + contentLength = contentLength(); + } + bytesWritten += byteCount; + mProgressListener.onProgress( + bytesWritten, contentLength, bytesWritten == contentLength); + } + }; } -} +} \ No newline at end of file diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java index 8ad39cd16e2070..a42231b55fd5be 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/network/NetworkingModuleTest.java @@ -200,10 +200,6 @@ public WritableMap answer(InvocationOnMock invocation) throws Throwable { @Test public void testSuccessfulPostRequest() throws Exception { - RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class); - ReactApplicationContext context = mock(ReactApplicationContext.class); - when(context.getJSModule(any(Class.class))).thenReturn(emitter); - OkHttpClient httpClient = mock(OkHttpClient.class); when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer() { @Override @@ -215,13 +211,12 @@ public Object answer(InvocationOnMock invocation) throws Throwable { OkHttpClient.Builder clientBuilder = mock(OkHttpClient.Builder.class); when(clientBuilder.build()).thenReturn(httpClient); when(httpClient.newBuilder()).thenReturn(clientBuilder); - NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient); + NetworkingModule networkingModule = + new NetworkingModule(mock(ReactApplicationContext.class), "", httpClient); JavaOnlyMap body = new JavaOnlyMap(); body.putString("string", "This is request body"); - mockEvents(); - networkingModule.sendRequest( "POST", "http://somedomain/bar", @@ -635,4 +630,4 @@ public Object answer(InvocationOnMock invocation) throws Throwable { assertThat(requestIdArguments.getAllValues().contains(idx + 1)).isTrue(); } } -} +} \ No newline at end of file