mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-29 12:45:37 +08:00
Support cookies on Android
Summary: This adds a persistent cookie store that shares cookies with WebView. Add a `ForwardingCookieHandler` to OkHttp that uses the underlying Android webkit `CookieManager`. Use a `LazyCookieHandler` to defer initialization of `CookieManager` as this will in turn trigger initialization of the Chromium stack in KitKat+ which takes some time. This was we will incur this cost on a background network thread instead of during startup. Also add a `clearCookies()` method to the network module. Add a cookies example to the XHR example. This example should also work for iOS (except for the clear cookies part). They are for now just scoped to Android. Closes #2792. public Reviewed By: andreicoman11 Differential Revision: D2615550 fb-gh-sync-id: ff726a35f0fc3c7124d2f755448fe24c9d1caf21
This commit is contained in:
committed by
facebook-github-bot-6
parent
f57c2a9140
commit
274c5c78c4
@@ -27,6 +27,8 @@ var {
|
|||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
var XHRExampleHeaders = require('./XHRExampleHeaders');
|
var XHRExampleHeaders = require('./XHRExampleHeaders');
|
||||||
|
var XHRExampleCookies = require('./XHRExampleCookies');
|
||||||
|
|
||||||
|
|
||||||
// TODO t7093728 This is a simlified XHRExample.ios.js.
|
// TODO t7093728 This is a simlified XHRExample.ios.js.
|
||||||
// Once we have Camera roll, Toast, Intent (for opening URLs)
|
// Once we have Camera roll, Toast, Intent (for opening URLs)
|
||||||
@@ -284,6 +286,11 @@ exports.examples = [{
|
|||||||
render() {
|
render() {
|
||||||
return <XHRExampleHeaders/>;
|
return <XHRExampleHeaders/>;
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
title: 'Cookies',
|
||||||
|
render() {
|
||||||
|
return <XHRExampleCookies/>;
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
|
|||||||
128
Examples/UIExplorer/XHRExampleCookies.js
Normal file
128
Examples/UIExplorer/XHRExampleCookies.js
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/**
|
||||||
|
* The examples provided by Facebook are for non-commercial testing and
|
||||||
|
* evaluation purposes only.
|
||||||
|
*
|
||||||
|
* Facebook reserves all rights not expressly granted.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* @flow
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var React = require('react-native');
|
||||||
|
var {
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableHighlight,
|
||||||
|
View,
|
||||||
|
} = React;
|
||||||
|
|
||||||
|
var RCTNetworking = require('RCTNetworking');
|
||||||
|
|
||||||
|
class XHRExampleCookies extends React.Component {
|
||||||
|
constructor(props: any) {
|
||||||
|
super(props);
|
||||||
|
this.cancelled = false;
|
||||||
|
this.state = {
|
||||||
|
status: '',
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
setCookie(domain: string) {
|
||||||
|
var {a, b} = this.state;
|
||||||
|
var url = `https://${domain}/cookies/set?a=${a}&b=${b}`;
|
||||||
|
fetch(url).then((response) => {
|
||||||
|
this.setStatus(`Cookies a=${a}, b=${b} set`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
status: 'Setting cookies...',
|
||||||
|
a: a + 1,
|
||||||
|
b: b + 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCookies(domain: string) {
|
||||||
|
fetch(`https://${domain}/cookies`).then((response) => {
|
||||||
|
return response.json();
|
||||||
|
}).then((data) => {
|
||||||
|
this.setStatus(`Got cookies ${JSON.stringify(data.cookies)} from server`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.setStatus('Getting cookies...');
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCookies() {
|
||||||
|
RCTNetworking.clearCookies((cleared) => {
|
||||||
|
this.setStatus('Cookies cleared, had cookies=' + cleared);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(status: string) {
|
||||||
|
this.setState({status});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={this.setCookie.bind(this, 'httpbin.org')}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text>Set cookie</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={this.setCookie.bind(this, 'eu.httpbin.org')}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text>Set cookie (EU)</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={this.getCookies.bind(this, 'httpbin.org')}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text>Get cookies</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={this.getCookies.bind(this, 'eu.httpbin.org')}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text>Get cookies (EU)</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.wrapper}
|
||||||
|
onPress={this.clearCookies.bind(this)}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text>Clear cookies</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
<Text>{this.state.status}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var styles = StyleSheet.create({
|
||||||
|
wrapper: {
|
||||||
|
borderRadius: 5,
|
||||||
|
marginBottom: 5,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: '#eeeeee',
|
||||||
|
padding: 8,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = XHRExampleCookies;
|
||||||
@@ -40,6 +40,10 @@ class RCTNetworking {
|
|||||||
static abortRequest(requestId) {
|
static abortRequest(requestId) {
|
||||||
RCTNetworkingNative.abortRequest(requestId);
|
RCTNetworkingNative.abortRequest(requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static clearCookies(callback) {
|
||||||
|
RCTNetworkingNative.clearCookies(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = RCTNetworking;
|
module.exports = RCTNetworking;
|
||||||
|
|||||||
@@ -80,7 +80,8 @@ public class FrescoModule extends ReactContextBaseJavaModule implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
Context context = this.getReactApplicationContext().getApplicationContext();
|
Context context = this.getReactApplicationContext().getApplicationContext();
|
||||||
OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
|
OkHttpClient okHttpClient =
|
||||||
|
OkHttpClientProvider.getCookieAwareOkHttpClient(getReactApplicationContext());
|
||||||
ImagePipelineConfig.Builder builder =
|
ImagePipelineConfig.Builder builder =
|
||||||
OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
|
OkHttpImagePipelineConfigFactory.newBuilder(context, okHttpClient);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.react.modules.network;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.CookieHandler;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.webkit.CookieManager;
|
||||||
|
import android.webkit.CookieSyncManager;
|
||||||
|
import android.webkit.ValueCallback;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Callback;
|
||||||
|
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||||
|
import com.facebook.react.bridge.GuardedResultAsyncTask;
|
||||||
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie handler that forwards all cookies to the WebView CookieManager.
|
||||||
|
*
|
||||||
|
* This class relies on CookieManager to persist cookies to disk so cookies may be lost if the
|
||||||
|
* application is terminated before it syncs.
|
||||||
|
*/
|
||||||
|
public class ForwardingCookieHandler extends CookieHandler {
|
||||||
|
private static final String VERSION_ZERO_HEADER = "Set-cookie";
|
||||||
|
private static final String VERSION_ONE_HEADER = "Set-cookie2";
|
||||||
|
private static final String COOKIE_HEADER = "Cookie";
|
||||||
|
|
||||||
|
// As CookieManager was synchronous before API 21 this class emulates the async behavior on <21.
|
||||||
|
private static final boolean USES_LEGACY_STORE = Build.VERSION.SDK_INT < 21;
|
||||||
|
|
||||||
|
private final CookieSaver mCookieSaver;
|
||||||
|
private final ReactContext mContext;
|
||||||
|
private @Nullable CookieManager mCookieManager;
|
||||||
|
|
||||||
|
public ForwardingCookieHandler(ReactContext context) {
|
||||||
|
mContext = context;
|
||||||
|
mCookieSaver = new CookieSaver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> get(URI uri, Map<String, List<String>> headers)
|
||||||
|
throws IOException {
|
||||||
|
String cookies = getCookieManager().getCookie(uri.toString());
|
||||||
|
if (TextUtils.isEmpty(cookies)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.singletonMap(COOKIE_HEADER, Collections.singletonList(cookies));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(URI uri, Map<String, List<String>> headers) throws IOException {
|
||||||
|
String url = uri.toString();
|
||||||
|
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if (key != null && isCookieHeader(key)) {
|
||||||
|
addCookies(url, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCookies(final Callback callback) {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
new GuardedResultAsyncTask<Boolean>(mContext) {
|
||||||
|
@Override
|
||||||
|
protected Boolean doInBackgroundGuarded() {
|
||||||
|
getCookieManager().removeAllCookie();
|
||||||
|
mCookieSaver.onCookiesModified();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecuteGuarded(Boolean result) {
|
||||||
|
callback.invoke(result);
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
} else {
|
||||||
|
clearCookiesAsync(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearCookiesAsync(final Callback callback) {
|
||||||
|
getCookieManager().removeAllCookies(
|
||||||
|
new ValueCallback<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void onReceiveValue(Boolean value) {
|
||||||
|
mCookieSaver.onCookiesModified();
|
||||||
|
callback.invoke(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
getCookieManager().removeExpiredCookie();
|
||||||
|
mCookieSaver.persistCookies();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCookies(final String url, final List<String> cookies) {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
runInBackground(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (String cookie : cookies) {
|
||||||
|
getCookieManager().setCookie(url, cookie);
|
||||||
|
}
|
||||||
|
mCookieSaver.onCookiesModified();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
for (String cookie : cookies) {
|
||||||
|
addCookieAsync(url, cookie);
|
||||||
|
}
|
||||||
|
mCookieSaver.onCookiesModified();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
private void addCookieAsync(String url, String cookie) {
|
||||||
|
getCookieManager().setCookie(url, cookie, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isCookieHeader(String name) {
|
||||||
|
return name.equalsIgnoreCase(VERSION_ZERO_HEADER) || name.equalsIgnoreCase(VERSION_ONE_HEADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runInBackground(final Runnable runnable) {
|
||||||
|
new GuardedAsyncTask<Void, Void>(mContext) {
|
||||||
|
@Override
|
||||||
|
protected void doInBackgroundGuarded(Void... params) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiating CookieManager in KitKat+ will load the Chromium task taking a 100ish ms so we
|
||||||
|
* do it lazily to make sure it's done on a background thread as needed.
|
||||||
|
*/
|
||||||
|
private CookieManager getCookieManager() {
|
||||||
|
if (mCookieManager == null) {
|
||||||
|
possiblyWorkaroundSyncManager(mContext);
|
||||||
|
mCookieManager = CookieManager.getInstance();
|
||||||
|
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
mCookieManager.removeExpiredCookie();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mCookieManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void possiblyWorkaroundSyncManager(Context context) {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
// This is to work around a bug where CookieManager may fail to instantiate if
|
||||||
|
// CookieSyncManager has never been created. Note that the sync() may not be required but is
|
||||||
|
// here of legacy reasons.
|
||||||
|
CookieSyncManager syncManager = CookieSyncManager.createInstance(context);
|
||||||
|
syncManager.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responsible for flushing cookies to disk. Flushes to disk with a maximum delay of 30 seconds.
|
||||||
|
* This class is only active if we are on API < 21.
|
||||||
|
*/
|
||||||
|
private class CookieSaver {
|
||||||
|
private static final int MSG_PERSIST_COOKIES = 1;
|
||||||
|
|
||||||
|
private static final int TIMEOUT = 30 * 1000; // 30 seconds
|
||||||
|
|
||||||
|
private final Handler mHandler;
|
||||||
|
|
||||||
|
public CookieSaver() {
|
||||||
|
mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
|
||||||
|
@Override
|
||||||
|
public boolean handleMessage(Message msg) {
|
||||||
|
if (msg.what == MSG_PERSIST_COOKIES) {
|
||||||
|
persistCookies();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onCookiesModified() {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
mHandler.sendEmptyMessageDelayed(MSG_PERSIST_COOKIES, TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void persistCookies() {
|
||||||
|
mHandler.removeMessages(MSG_PERSIST_COOKIES);
|
||||||
|
runInBackground(
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (USES_LEGACY_STORE) {
|
||||||
|
CookieSyncManager syncManager = CookieSyncManager.getInstance();
|
||||||
|
syncManager.sync();
|
||||||
|
} else {
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(21)
|
||||||
|
private void flush() {
|
||||||
|
getCookieManager().flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import javax.annotation.Nullable;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.net.CookieHandler;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.GuardedAsyncTask;
|
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||||
@@ -72,19 +73,19 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param reactContext the ReactContext of the application
|
* @param context the ReactContext of the application
|
||||||
*/
|
*/
|
||||||
public NetworkingModule(ReactApplicationContext reactContext) {
|
public NetworkingModule(final ReactApplicationContext context) {
|
||||||
this(reactContext, null, OkHttpClientProvider.getOkHttpClient());
|
this(context, null, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param reactContext the ReactContext of the application
|
* @param context the ReactContext of the application
|
||||||
* @param defaultUserAgent the User-Agent header that will be set for all requests where the
|
* @param defaultUserAgent the User-Agent header that will be set for all requests where the
|
||||||
* caller does not provide one explicitly
|
* caller does not provide one explicitly
|
||||||
*/
|
*/
|
||||||
public NetworkingModule(ReactApplicationContext reactContext, String defaultUserAgent) {
|
public NetworkingModule(ReactApplicationContext context, String defaultUserAgent) {
|
||||||
this(reactContext, defaultUserAgent, OkHttpClientProvider.getOkHttpClient());
|
this(context, defaultUserAgent, OkHttpClientProvider.getCookieAwareOkHttpClient(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkingModule(ReactApplicationContext reactContext, OkHttpClient client) {
|
public NetworkingModule(ReactApplicationContext reactContext, OkHttpClient client) {
|
||||||
@@ -100,6 +101,11 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
|||||||
public void onCatalystInstanceDestroy() {
|
public void onCatalystInstanceDestroy() {
|
||||||
mShuttingDown = true;
|
mShuttingDown = true;
|
||||||
mClient.cancel(null);
|
mClient.cancel(null);
|
||||||
|
|
||||||
|
CookieHandler cookieHandler = mClient.getCookieHandler();
|
||||||
|
if (cookieHandler instanceof ForwardingCookieHandler) {
|
||||||
|
((ForwardingCookieHandler) cookieHandler).destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReactMethod
|
@ReactMethod
|
||||||
@@ -311,6 +317,14 @@ public final class NetworkingModule extends ReactContextBaseJavaModule {
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void clearCookies(com.facebook.react.bridge.Callback callback) {
|
||||||
|
CookieHandler cookieHandler = mClient.getCookieHandler();
|
||||||
|
if (cookieHandler instanceof ForwardingCookieHandler) {
|
||||||
|
((ForwardingCookieHandler) cookieHandler).clearCookies(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable MultipartBuilder constructMultipartBody(
|
private @Nullable MultipartBuilder constructMultipartBody(
|
||||||
ReadableArray body,
|
ReadableArray body,
|
||||||
String contentType,
|
String contentType,
|
||||||
|
|||||||
@@ -9,7 +9,12 @@
|
|||||||
|
|
||||||
package com.facebook.react.modules.network;
|
package com.facebook.react.modules.network;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
|
||||||
import com.squareup.okhttp.OkHttpClient;
|
import com.squareup.okhttp.OkHttpClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,18 +24,33 @@ import com.squareup.okhttp.OkHttpClient;
|
|||||||
public class OkHttpClientProvider {
|
public class OkHttpClientProvider {
|
||||||
|
|
||||||
// Centralized OkHttpClient for all networking requests.
|
// Centralized OkHttpClient for all networking requests.
|
||||||
private static OkHttpClient sClient;
|
private static @Nullable OkHttpClient sClient;
|
||||||
|
private static ForwardingCookieHandler sCookieHandler;
|
||||||
|
|
||||||
public static OkHttpClient getOkHttpClient() {
|
public static OkHttpClient getOkHttpClient() {
|
||||||
if (sClient == null) {
|
if (sClient == null) {
|
||||||
// TODO: #7108751 plug in stetho
|
sClient = createClient();
|
||||||
sClient = new OkHttpClient();
|
|
||||||
|
|
||||||
// No timeouts by default
|
|
||||||
sClient.setConnectTimeout(0, TimeUnit.MILLISECONDS);
|
|
||||||
sClient.setReadTimeout(0, TimeUnit.MILLISECONDS);
|
|
||||||
sClient.setWriteTimeout(0, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
return sClient;
|
return sClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OkHttpClient getCookieAwareOkHttpClient(ReactContext context) {
|
||||||
|
if (sCookieHandler == null) {
|
||||||
|
sCookieHandler = new ForwardingCookieHandler(context);
|
||||||
|
getOkHttpClient().setCookieHandler(sCookieHandler);
|
||||||
|
}
|
||||||
|
return getOkHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static OkHttpClient createClient() {
|
||||||
|
// TODO: #7108751 plug in stetho
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user