mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-09 22:43:10 +08:00
Upgrade to OkHttp3
Summary: Update to [OkHttp](https://github.com/square/okhttp) to [OkHttp3](https://publicobject.com/2015/12/12/com-squareup-okhttp3/) We must also update: - Fresco to 0.10.0 - okio to 1.8.0 **Motivation** Reasons for upgrading: * Issue #4021 * "We discovered that RN Android sometimes fails to connect to the latest stable version of NGINX when HTTP/2 is enabled. We aren't seeing errors with other HTTP clients so we think it's specific to RN and OkHttp. Square has fixed several HTTP/2 bugs over the past eight months." - ide * OkHttp3 will be maintained & improved, but OkHttp2 will only receive [security fixes](https://publicobject.com/2016/02/11/okhttp-certificate-pinning-vulnerability/) * Cleaner APIs - "Get and Set prefixes are avoided" * Deprecated/Removed - HttpURLConnection & Apache HTTP * React Native apps are currently being forced to bundle two versions of OkHttp (v2 & v3), if another library uses v3 * Improved WebSocket performance - [CHANGELOG.md](https://github.com/square/okhttp/blob/master Closes https://github.com/facebook/react-native/pull/6113 Reviewed By: andreicoman11, lexs Differential Revision: D3292375 Pulled By: bestander fbshipit-source-id: 7c7043eaa2ea63f95854108b401c4066098d67f7
This commit is contained in:
committed by
Facebook Github Bot 1
parent
5047f6f54c
commit
6bbaff2944
@@ -21,16 +21,16 @@ android_library(
|
||||
react_native_dep('java/com/facebook/proguard/annotations:annotations'),
|
||||
],
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_dep('java/com/facebook/systrace:systrace'),
|
||||
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
|
||||
react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jackson:core'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3-ws'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp-ws'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
|
||||
@@ -25,14 +25,15 @@ import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ws.WebSocket;
|
||||
import com.squareup.okhttp.ws.WebSocketCall;
|
||||
import com.squareup.okhttp.ws.WebSocketListener;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.ws.WebSocket;
|
||||
import okhttp3.ws.WebSocketCall;
|
||||
import okhttp3.ws.WebSocketListener;
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
|
||||
/**
|
||||
* A wrapper around WebSocketClient that recognizes RN debugging message format.
|
||||
@@ -59,11 +60,11 @@ public class JSDebuggerWebSocketClient implements WebSocketListener {
|
||||
throw new IllegalStateException("JSDebuggerWebSocketClient is already initialized.");
|
||||
}
|
||||
mConnectCallback = callback;
|
||||
mHttpClient = new OkHttpClient();
|
||||
mHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
|
||||
mHttpClient.setWriteTimeout(10, TimeUnit.SECONDS);
|
||||
// Disable timeouts for read
|
||||
mHttpClient.setReadTimeout(0, TimeUnit.MINUTES);
|
||||
mHttpClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
WebSocketCall call = WebSocketCall.create(mHttpClient, request);
|
||||
@@ -162,10 +163,8 @@ public class JSDebuggerWebSocketClient implements WebSocketListener {
|
||||
new IllegalStateException("WebSocket connection no longer valid"));
|
||||
return;
|
||||
}
|
||||
Buffer messageBuffer = new Buffer();
|
||||
messageBuffer.writeUtf8(message);
|
||||
try {
|
||||
mWebSocket.sendMessage(WebSocket.PayloadType.TEXT, messageBuffer);
|
||||
mWebSocket.sendMessage(RequestBody.create(WebSocket.TEXT, message));
|
||||
} catch (IOException e) {
|
||||
triggerRequestFailure(requestID, e);
|
||||
}
|
||||
@@ -188,17 +187,17 @@ public class JSDebuggerWebSocketClient implements WebSocketListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(BufferedSource payload, WebSocket.PayloadType type) throws IOException {
|
||||
if (type != WebSocket.PayloadType.TEXT) {
|
||||
FLog.w(TAG, "Websocket received unexpected message with payload of type " + type);
|
||||
public void onMessage(ResponseBody response) throws IOException {
|
||||
if (response.contentType() != WebSocket.TEXT) {
|
||||
FLog.w(TAG, "Websocket received unexpected message with payload of type " + response.contentType());
|
||||
return;
|
||||
}
|
||||
|
||||
String message = null;
|
||||
try {
|
||||
message = payload.readUtf8();
|
||||
message = response.source().readUtf8();
|
||||
} finally {
|
||||
payload.close();
|
||||
response.close();
|
||||
}
|
||||
Integer replyID = null;
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ import com.facebook.react.bridge.queue.MessageQueueThreadImpl;
|
||||
import com.facebook.react.bridge.queue.ProxyQueueThreadExceptionHandler;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okio.Okio;
|
||||
import okio.Sink;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ android_library(
|
||||
':build_config',
|
||||
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'),
|
||||
],
|
||||
exported_deps = [
|
||||
react_native_dep('java/com/facebook/proguard/annotations:annotations'),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
* <p/>
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.common.network;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Helper class that provides the necessary methods for canceling queued and running OkHttp calls
|
||||
*/
|
||||
public class OkHttpCallUtil {
|
||||
|
||||
private OkHttpCallUtil() {
|
||||
}
|
||||
|
||||
public static void cancelTag(OkHttpClient client, Object tag) {
|
||||
for (Call call : client.dispatcher().queuedCalls()) {
|
||||
if (tag.equals(call.request().tag())) {
|
||||
call.cancel();
|
||||
}
|
||||
}
|
||||
for (Call call : client.dispatcher().runningCalls()) {
|
||||
if (tag.equals(call.request().tag())) {
|
||||
call.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,16 @@ android_library(
|
||||
manifest = 'AndroidManifest.xml',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('res:devsupport'),
|
||||
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
|
||||
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'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/debug:debug'),
|
||||
react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'),
|
||||
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
|
||||
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:okhttp'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
|
||||
react_native_target('res:devsupport'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
|
||||
@@ -17,14 +17,8 @@ import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.network.OkHttpCallUtil;
|
||||
import com.facebook.react.modules.systeminfo.AndroidInfoHelpers;
|
||||
import com.squareup.okhttp.Call;
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.ConnectionPool;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ResponseBody;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -33,6 +27,13 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okio.Okio;
|
||||
import okio.Sink;
|
||||
|
||||
@@ -91,12 +92,12 @@ public class DevServerHelper {
|
||||
|
||||
public DevServerHelper(DevInternalSettings settings) {
|
||||
mSettings = settings;
|
||||
mClient = new OkHttpClient();
|
||||
mClient.setConnectTimeout(HTTP_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
mClient = new OkHttpClient.Builder()
|
||||
.connectTimeout(HTTP_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
// No read or write timeouts by default
|
||||
mClient.setReadTimeout(0, TimeUnit.MILLISECONDS);
|
||||
mClient.setWriteTimeout(0, TimeUnit.MILLISECONDS);
|
||||
mRestartOnChangePollingHandler = new Handler();
|
||||
}
|
||||
|
||||
@@ -176,7 +177,7 @@ public class DevServerHelper {
|
||||
mDownloadBundleFromURLCall = Assertions.assertNotNull(mClient.newCall(request));
|
||||
mDownloadBundleFromURLCall.enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
// ignore callback if call was cancelled
|
||||
if (mDownloadBundleFromURLCall == null || mDownloadBundleFromURLCall.isCanceled()) {
|
||||
mDownloadBundleFromURLCall = null;
|
||||
@@ -191,12 +192,12 @@ public class DevServerHelper {
|
||||
.append("\u2022 Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices\n")
|
||||
.append("\u2022 If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device\n")
|
||||
.append("\u2022 If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081\n\n")
|
||||
.append("URL: ").append(request.urlString());
|
||||
.append("URL: ").append(call.request().url().toString());
|
||||
callback.onFailure(new DebugServerException(sb.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
// ignore callback if call was cancelled
|
||||
if (mDownloadBundleFromURLCall == null || mDownloadBundleFromURLCall.isCanceled()) {
|
||||
mDownloadBundleFromURLCall = null;
|
||||
@@ -213,7 +214,7 @@ public class DevServerHelper {
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("The development server returned response error code: ").append(response.code()).append("\n\n")
|
||||
.append("URL: ").append(request.urlString()).append("\n\n")
|
||||
.append("URL: ").append(call.request().url().toString()).append("\n\n")
|
||||
.append("Body:\n")
|
||||
.append(body);
|
||||
callback.onFailure(new DebugServerException(sb.toString()));
|
||||
@@ -251,7 +252,7 @@ public class DevServerHelper {
|
||||
mClient.newCall(request).enqueue(
|
||||
new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
FLog.w(
|
||||
ReactConstants.TAG,
|
||||
"The packager does not seem to be running as we got an IOException requesting " +
|
||||
@@ -260,7 +261,7 @@ public class DevServerHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
if (!response.isSuccessful()) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
@@ -297,7 +298,7 @@ public class DevServerHelper {
|
||||
mOnChangePollingEnabled = false;
|
||||
mRestartOnChangePollingHandler.removeCallbacksAndMessages(null);
|
||||
if (mOnChangePollingClient != null) {
|
||||
mOnChangePollingClient.cancel(this);
|
||||
OkHttpCallUtil.cancelTag(mOnChangePollingClient, this);
|
||||
mOnChangePollingClient = null;
|
||||
}
|
||||
mOnServerContentChangeListener = null;
|
||||
@@ -311,10 +312,10 @@ public class DevServerHelper {
|
||||
}
|
||||
mOnChangePollingEnabled = true;
|
||||
mOnServerContentChangeListener = onServerContentChangeListener;
|
||||
mOnChangePollingClient = new OkHttpClient();
|
||||
mOnChangePollingClient
|
||||
.setConnectionPool(new ConnectionPool(1, LONG_POLL_KEEP_ALIVE_DURATION_MS))
|
||||
.setConnectTimeout(HTTP_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
|
||||
mOnChangePollingClient = new OkHttpClient.Builder()
|
||||
.connectionPool(new ConnectionPool(1, LONG_POLL_KEEP_ALIVE_DURATION_MS, TimeUnit.MINUTES))
|
||||
.connectTimeout(HTTP_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
enqueueOnChangeEndpointLongPolling();
|
||||
}
|
||||
|
||||
@@ -338,7 +339,7 @@ public class DevServerHelper {
|
||||
Request request = new Request.Builder().url(createOnChangeEndpointUrl()).tag(this).build();
|
||||
Assertions.assertNotNull(mOnChangePollingClient).newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
if (mOnChangePollingEnabled) {
|
||||
// this runnable is used by onchange endpoint poller to delay subsequent requests in case
|
||||
// of a failure, so that we don't flood network queue with frequent requests in case when
|
||||
@@ -356,7 +357,7 @@ public class DevServerHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
handleOnChangePollingResponse(response.code() == 205);
|
||||
}
|
||||
});
|
||||
@@ -376,13 +377,13 @@ public class DevServerHelper {
|
||||
.build();
|
||||
mClient.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
// ignore HTTP call response, this is just to open a debugger page and there is no reason
|
||||
// to report failures from here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
// ignore HTTP call response - see above
|
||||
}
|
||||
});
|
||||
|
||||
@@ -30,10 +30,10 @@ import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.devsupport.StackTraceHelper.StackFrame;
|
||||
|
||||
import com.squareup.okhttp.MediaType;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,21 +4,21 @@ android_library(
|
||||
name = 'fresco',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/modules/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/network:network'),
|
||||
react_native_dep('java/com/facebook/systrace:systrace'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:imagepipeline-okhttp'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:imagepipeline-okhttp3'),
|
||||
react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'),
|
||||
react_native_dep('third-party/android/support-annotations:android-support-annotations'),
|
||||
react_native_dep('third-party/android/support/v4:lib-support-v4'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
||||
react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
|
||||
],
|
||||
react_native_dep('third-party/java/okhttp:okhttp3'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/modules/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/network:network'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
|
||||
@@ -19,7 +19,7 @@ import com.facebook.cache.disk.DiskCacheConfig;
|
||||
import com.facebook.common.internal.AndroidPredicates;
|
||||
import com.facebook.common.soloader.SoLoaderShim;
|
||||
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||
import com.facebook.imagepipeline.backends.okhttp.OkHttpImagePipelineConfigFactory;
|
||||
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig;
|
||||
import com.facebook.imagepipeline.core.ImagePipelineFactory;
|
||||
import com.facebook.imagepipeline.listener.RequestListener;
|
||||
@@ -29,7 +29,7 @@ import com.facebook.react.modules.common.ModuleDataCleaner;
|
||||
import com.facebook.react.modules.network.OkHttpClientProvider;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Module to initialize the Fresco library.
|
||||
@@ -84,8 +84,8 @@ public class FrescoModule extends ReactContextBaseJavaModule implements
|
||||
ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory();
|
||||
imagePipelineFactory.getBitmapMemoryCache().removeAll(AndroidPredicates.<CacheKey>True());
|
||||
imagePipelineFactory.getEncodedMemoryCache().removeAll(AndroidPredicates.<CacheKey>True());
|
||||
imagePipelineFactory.getMainDiskStorageCache().clearAll();
|
||||
imagePipelineFactory.getSmallImageDiskStorageCache().clearAll();
|
||||
imagePipelineFactory.getMainFileCache().clearAll();
|
||||
imagePipelineFactory.getSmallImageFileCache().clearAll();
|
||||
}
|
||||
|
||||
private static ImagePipelineConfig getDefaultConfig(
|
||||
|
||||
@@ -4,15 +4,16 @@ android_library(
|
||||
name = 'network',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/modules/core:core'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
|
||||
react_native_dep('third-party/android/support/v4:lib-support-v4'),
|
||||
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:okhttp'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3-urlconnection'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/core:core'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import okhttp3.CookieJar;
|
||||
|
||||
public interface CookieJarContainer extends CookieJar {
|
||||
|
||||
void setCookieJar(CookieJar cookieJar);
|
||||
|
||||
void removeCookieJar();
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import com.squareup.okhttp.Interceptor;
|
||||
import okhttp3.Interceptor;
|
||||
|
||||
/**
|
||||
* Classes implementing this interface return a new {@link Interceptor} when the {@link #create}
|
||||
|
||||
@@ -9,17 +9,6 @@
|
||||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import java.net.SocketTimeoutException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ExecutorToken;
|
||||
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||
@@ -30,19 +19,29 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.network.OkHttpCallUtil;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.Headers;
|
||||
import com.squareup.okhttp.MediaType;
|
||||
import com.squareup.okhttp.MultipartBuilder;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ResponseBody;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static java.lang.Math.min;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.JavaNetCookieJar;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* Implements the XMLHttpRequest JavaScript interface.
|
||||
@@ -61,6 +60,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
private final OkHttpClient mClient;
|
||||
private final ForwardingCookieHandler mCookieHandler;
|
||||
private final @Nullable String mDefaultUserAgent;
|
||||
private final CookieJarContainer mCookieJarContainer;
|
||||
private boolean mShuttingDown;
|
||||
|
||||
/* package */ NetworkingModule(
|
||||
@@ -76,6 +76,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
mCookieHandler = new ForwardingCookieHandler(reactContext);
|
||||
mCookieJarContainer = (CookieJarContainer) mClient.cookieJar();
|
||||
mShuttingDown = false;
|
||||
mDefaultUserAgent = defaultUserAgent;
|
||||
}
|
||||
@@ -126,7 +127,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
mClient.setCookieHandler(mCookieHandler);
|
||||
mCookieJarContainer.setCookieJar(new JavaNetCookieJar(mCookieHandler));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -137,10 +138,10 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
@Override
|
||||
public void onCatalystInstanceDestroy() {
|
||||
mShuttingDown = true;
|
||||
mClient.cancel(null);
|
||||
OkHttpCallUtil.cancelTag(mClient, null);
|
||||
|
||||
mCookieHandler.destroy();
|
||||
mClient.setCookieHandler(null);
|
||||
mCookieJarContainer.removeCookieJar();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@@ -167,9 +168,10 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
// client and set the timeout explicitly on the clone. This is cheap as everything else is
|
||||
// shared under the hood.
|
||||
// See https://github.com/square/okhttp/wiki/Recipes#per-call-configuration for more information
|
||||
if (timeout != mClient.getConnectTimeout()) {
|
||||
client = mClient.clone();
|
||||
client.setReadTimeout(timeout, TimeUnit.MILLISECONDS);
|
||||
if (timeout != mClient.connectTimeoutMillis()) {
|
||||
client = mClient.newBuilder()
|
||||
.readTimeout(timeout, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
|
||||
Headers requestHeaders = extractHeaders(headers, data);
|
||||
@@ -228,7 +230,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
contentType = "multipart/form-data";
|
||||
}
|
||||
ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA);
|
||||
MultipartBuilder multipartBuilder =
|
||||
MultipartBody.Builder multipartBuilder =
|
||||
constructMultipartBody(executorToken, parts, contentType, requestId);
|
||||
if (multipartBuilder == null) {
|
||||
return;
|
||||
@@ -242,7 +244,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
client.newCall(requestBuilder.build()).enqueue(
|
||||
new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
public void onFailure(Call call, IOException e) {
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
@@ -250,7 +252,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
if (mShuttingDown) {
|
||||
return;
|
||||
}
|
||||
@@ -328,7 +330,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
args.pushInt(requestId);
|
||||
args.pushInt(response.code());
|
||||
args.pushMap(headers);
|
||||
args.pushString(response.request().urlString());
|
||||
args.pushString(response.request().url().toString());
|
||||
|
||||
getEventEmitter(ExecutorToken).emit("didReceiveNetworkResponse", args);
|
||||
}
|
||||
@@ -356,7 +358,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
||||
@Override
|
||||
protected void doInBackgroundGuarded(Void... params) {
|
||||
mClient.cancel(requestId);
|
||||
OkHttpCallUtil.cancelTag(mClient, requestId);
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
@@ -373,15 +375,13 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
return true;
|
||||
}
|
||||
|
||||
private
|
||||
@Nullable
|
||||
MultipartBuilder constructMultipartBody(
|
||||
private @Nullable MultipartBody.Builder constructMultipartBody(
|
||||
ExecutorToken ExecutorToken,
|
||||
ReadableArray body,
|
||||
String contentType,
|
||||
int requestId) {
|
||||
MultipartBuilder multipartBuilder = new MultipartBuilder();
|
||||
multipartBuilder.type(MediaType.parse(contentType));
|
||||
MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
|
||||
multipartBuilder.setType(MediaType.parse(contentType));
|
||||
|
||||
for (int i = 0, size = body.size(); i < size; i++) {
|
||||
ReadableMap bodyPart = body.getMap(i);
|
||||
@@ -440,9 +440,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
/**
|
||||
* Extracts the headers from the Array. If the format is invalid, this method will return null.
|
||||
*/
|
||||
private
|
||||
@Nullable
|
||||
Headers extractHeaders(
|
||||
private @Nullable Headers extractHeaders(
|
||||
@Nullable ReadableArray headersArray,
|
||||
@Nullable ReadableMap requestData) {
|
||||
if (headersArray == null) {
|
||||
@@ -475,4 +473,4 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
||||
return getReactApplicationContext()
|
||||
.getJSModule(ExecutorToken, DeviceEventManagerModule.RCTDeviceEventEmitter.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Helper class that provides the same OkHttpClient instance that will be used for all networking
|
||||
@@ -30,15 +30,20 @@ public class OkHttpClientProvider {
|
||||
}
|
||||
return sClient;
|
||||
}
|
||||
|
||||
// okhttp3 OkHttpClient is immutable
|
||||
// This allows app to init an OkHttpClient with custom settings.
|
||||
public static void replaceOkHttpClient(OkHttpClient client) {
|
||||
sClient = client;
|
||||
}
|
||||
|
||||
private static OkHttpClient createClient() {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
// No timeouts by default
|
||||
client.setConnectTimeout(0, TimeUnit.MILLISECONDS);
|
||||
client.setReadTimeout(0, TimeUnit.MILLISECONDS);
|
||||
client.setWriteTimeout(0, TimeUnit.MILLISECONDS);
|
||||
|
||||
return client;
|
||||
return new OkHttpClient.Builder()
|
||||
.connectTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.writeTimeout(0, TimeUnit.MILLISECONDS)
|
||||
.cookieJar(new ReactCookieJarContainer())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.facebook.react.modules.network;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* Basic okhttp3 CookieJar container
|
||||
*/
|
||||
public class ReactCookieJarContainer implements CookieJarContainer {
|
||||
|
||||
@Nullable
|
||||
private CookieJar cookieJar = null;
|
||||
|
||||
@Override
|
||||
public void setCookieJar(CookieJar cookieJar) {
|
||||
this.cookieJar = cookieJar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCookieJar() {
|
||||
this.cookieJar = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
|
||||
if (cookieJar != null) {
|
||||
cookieJar.saveFromResponse(url, cookies);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> loadForRequest(HttpUrl url) {
|
||||
if (cookieJar != null) {
|
||||
return cookieJar.loadForRequest(url);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,9 @@ import android.net.Uri;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
|
||||
import com.squareup.okhttp.MediaType;
|
||||
import com.squareup.okhttp.RequestBody;
|
||||
import com.squareup.okhttp.internal.Util;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.internal.Util;
|
||||
import okio.BufferedSink;
|
||||
import okio.ByteString;
|
||||
import okio.Okio;
|
||||
|
||||
@@ -4,16 +4,16 @@ android_library(
|
||||
name = 'websocket',
|
||||
srcs = glob(['**/*.java']),
|
||||
deps = [
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/core:core'),
|
||||
react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'),
|
||||
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:okhttp-ws'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3'),
|
||||
react_native_dep('third-party/java/okhttp:okhttp3-ws'),
|
||||
react_native_dep('third-party/java/okio:okio'),
|
||||
],
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/modules/core:core'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
|
||||
@@ -29,12 +29,14 @@ import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ws.WebSocket;
|
||||
import com.squareup.okhttp.ws.WebSocketCall;
|
||||
import com.squareup.okhttp.ws.WebSocketListener;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.ws.WebSocket;
|
||||
import okhttp3.ws.WebSocketCall;
|
||||
import okhttp3.ws.WebSocketListener;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URI;
|
||||
@@ -43,7 +45,6 @@ import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
import okio.ByteString;
|
||||
|
||||
public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
@@ -69,12 +70,11 @@ public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
|
||||
@ReactMethod
|
||||
public void connect(final String url, @Nullable final ReadableArray protocols, @Nullable final ReadableMap headers, final int id) {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
|
||||
client.setConnectTimeout(10, TimeUnit.SECONDS);
|
||||
client.setWriteTimeout(10, TimeUnit.SECONDS);
|
||||
// Disable timeouts for read
|
||||
client.setReadTimeout(0, TimeUnit.MINUTES);
|
||||
OkHttpClient client = new OkHttpClient.Builder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read
|
||||
.build();
|
||||
|
||||
Request.Builder builder = new Request.Builder()
|
||||
.tag(id)
|
||||
@@ -145,20 +145,20 @@ public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(BufferedSource bufferedSource, WebSocket.PayloadType payloadType) {
|
||||
public void onMessage(ResponseBody response) throws IOException {
|
||||
String message;
|
||||
try {
|
||||
if (payloadType == WebSocket.PayloadType.BINARY) {
|
||||
message = Base64.encodeToString(bufferedSource.readByteArray(), Base64.NO_WRAP);
|
||||
if (response.contentType() == WebSocket.BINARY) {
|
||||
message = Base64.encodeToString(response.source().readByteArray(), Base64.NO_WRAP);
|
||||
} else {
|
||||
message = bufferedSource.readUtf8();
|
||||
message = response.source().readUtf8();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
notifyWebSocketFailed(id, e.getMessage());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
bufferedSource.close();
|
||||
response.source().close();
|
||||
} catch (IOException e) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
@@ -169,13 +169,13 @@ public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putInt("id", id);
|
||||
params.putString("data", message);
|
||||
params.putString("type", payloadType == WebSocket.PayloadType.BINARY ? "binary" : "text");
|
||||
params.putString("type", response.contentType() == WebSocket.BINARY ? "binary" : "text");
|
||||
sendEvent("websocketMessage", params);
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger shutdown of the dispatcher's executor so this process can exit cleanly
|
||||
client.getDispatcher().getExecutorService().shutdown();
|
||||
client.dispatcher().executorService().shutdown();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
@@ -209,9 +209,7 @@ public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id);
|
||||
}
|
||||
try {
|
||||
client.sendMessage(
|
||||
WebSocket.PayloadType.TEXT,
|
||||
new Buffer().writeUtf8(message));
|
||||
client.sendMessage(RequestBody.create(WebSocket.TEXT, message));
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
notifyWebSocketFailed(id, e.getMessage());
|
||||
}
|
||||
@@ -225,9 +223,7 @@ public class WebSocketModule extends ReactContextBaseJavaModule {
|
||||
throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id);
|
||||
}
|
||||
try {
|
||||
client.sendMessage(
|
||||
WebSocket.PayloadType.BINARY,
|
||||
new Buffer().write(ByteString.decodeBase64(base64String)));
|
||||
client.sendMessage(RequestBody.create(WebSocket.TEXT, ByteString.decodeBase64(base64String)));
|
||||
} catch (IOException | IllegalStateException e) {
|
||||
notifyWebSocketFailed(id, e.getMessage());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user