Android: Support HTTP headers for source prop on <Image> components
Summary: A copy of https://github.com/facebook/react-native/pull/7791 because of our very imperfect tools that mirror the changes from pull requests in the fb monorepo. The internal Phabricator revision for #7791 is in an 'abandoned' state (by foghina probably because of changing teams) and Phabricator doesn't allow me to claim that revision and merge it. Therefore I'm creating a new one. (It's not foghina's fault, no one probably knew about this "abandoned Phabricator revision" edge case, don't remember we hit it before.) Will try to keep attribution (git blame) to rigdern when merging. Closes https://github.com/facebook/react-native/pull/12448 Differential Revision: D4584743 Pulled By: mkonicek fbshipit-source-id: 66e5b88134fca1980adc4cd8a2ff17c42e10022c
This commit is contained in:
parent
c7f2c53fbf
commit
8c0e6ecfc0
|
@ -83,6 +83,10 @@ var Image = React.createClass({
|
|||
* `uri` is a string representing the resource identifier for the image, which
|
||||
* could be an http address, a local file path, or a static image
|
||||
* resource (which should be wrapped in the `require('./path/to/image.png')` function).
|
||||
*
|
||||
* `headers` is an object representing the HTTP headers to send along with the request
|
||||
* for a remote image.
|
||||
*
|
||||
* This prop can also contain several remote `uri`, specified together with
|
||||
* their width and height. The native side will then choose the best `uri` to display
|
||||
* based on the measured size of the image container.
|
||||
|
@ -90,6 +94,7 @@ var Image = React.createClass({
|
|||
source: PropTypes.oneOfType([
|
||||
PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
headers: PropTypes.objectOf(PropTypes.string),
|
||||
}),
|
||||
// Opaque type returned by require('./image.jpg')
|
||||
PropTypes.number,
|
||||
|
@ -300,6 +305,7 @@ var Image = React.createClass({
|
|||
style,
|
||||
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd || onError),
|
||||
src: sources,
|
||||
headers: source.headers,
|
||||
loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
|
||||
});
|
||||
|
||||
|
@ -346,6 +352,7 @@ var styles = StyleSheet.create({
|
|||
var cfg = {
|
||||
nativeOnly: {
|
||||
src: true,
|
||||
headers: true,
|
||||
loadingIndicatorSrc: true,
|
||||
shouldNotifyLoadEvents: true,
|
||||
},
|
||||
|
|
|
@ -277,8 +277,8 @@ dependencies {
|
|||
compile 'com.android.support:appcompat-v7:23.0.1'
|
||||
compile 'com.android.support:recyclerview-v7:23.4.0'
|
||||
compile 'com.facebook.fbui.textlayoutbuilder:textlayoutbuilder:1.0.0'
|
||||
compile 'com.facebook.fresco:fresco:0.11.0'
|
||||
compile 'com.facebook.fresco:imagepipeline-okhttp3:0.11.0'
|
||||
compile 'com.facebook.fresco:fresco:1.0.1'
|
||||
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.0.1'
|
||||
compile 'com.facebook.soloader:soloader:0.1.0'
|
||||
compile 'com.google.code.findbugs:jsr305:3.0.0'
|
||||
compile 'com.squareup.okhttp3:okhttp:3.4.1'
|
||||
|
|
|
@ -28,6 +28,8 @@ import com.facebook.react.modules.common.ModuleDataCleaner;
|
|||
import com.facebook.react.modules.network.OkHttpClientProvider;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* Module to initialize the Fresco library.
|
||||
*
|
||||
|
@ -124,8 +126,10 @@ public class FrescoModule extends ReactContextBaseJavaModule implements
|
|||
HashSet<RequestListener> requestListeners = new HashSet<>();
|
||||
requestListeners.add(new SystraceRequestListener());
|
||||
|
||||
OkHttpClient okHttpClient = OkHttpClientProvider.getOkHttpClient();
|
||||
return OkHttpImagePipelineConfigFactory
|
||||
.newBuilder(context.getApplicationContext(), OkHttpClientProvider.getOkHttpClient())
|
||||
.newBuilder(context.getApplicationContext(), okHttpClient)
|
||||
.setNetworkFetcher(new ReactOkHttpNetworkFetcher(okHttpClient))
|
||||
.setDownsampleEnabled(false)
|
||||
.setRequestListeners(requestListeners);
|
||||
}
|
||||
|
|
|
@ -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.modules.fresco;
|
||||
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
/** Extended ImageRequest with request headers */
|
||||
public class ReactNetworkImageRequest extends ImageRequest {
|
||||
|
||||
/** Headers for the request */
|
||||
private final ReadableMap mHeaders;
|
||||
|
||||
public static ReactNetworkImageRequest fromBuilderWithHeaders(ImageRequestBuilder builder,
|
||||
ReadableMap headers) {
|
||||
return new ReactNetworkImageRequest(builder, headers);
|
||||
}
|
||||
|
||||
protected ReactNetworkImageRequest(ImageRequestBuilder builder, ReadableMap headers) {
|
||||
super(builder);
|
||||
this.mHeaders = headers;
|
||||
}
|
||||
|
||||
public ReadableMap getHeaders() {
|
||||
return mHeaders;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* 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.modules.fresco;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.facebook.imagepipeline.backends.okhttp3.OkHttpNetworkFetcher;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableMapKeySetIterator;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import okhttp3.CacheControl;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
|
||||
class ReactOkHttpNetworkFetcher extends OkHttpNetworkFetcher {
|
||||
|
||||
private static final String TAG = "ReactOkHttpNetworkFetcher";
|
||||
|
||||
private final OkHttpClient mOkHttpClient;
|
||||
private final Executor mCancellationExecutor;
|
||||
|
||||
/**
|
||||
* @param okHttpClient client to use
|
||||
*/
|
||||
public ReactOkHttpNetworkFetcher(OkHttpClient okHttpClient) {
|
||||
super(okHttpClient);
|
||||
mOkHttpClient = okHttpClient;
|
||||
mCancellationExecutor = okHttpClient.dispatcher().executorService();
|
||||
}
|
||||
|
||||
private Map<String, String> getHeaders(ReadableMap readableMap) {
|
||||
if (readableMap == null) {
|
||||
return null;
|
||||
}
|
||||
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
|
||||
Map<String, String> map = new HashMap<>();
|
||||
while (iterator.hasNextKey()) {
|
||||
String key = iterator.nextKey();
|
||||
String value = readableMap.getString(key);
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetch(final OkHttpNetworkFetchState fetchState, final Callback callback) {
|
||||
fetchState.submitTime = SystemClock.elapsedRealtime();
|
||||
final Uri uri = fetchState.getUri();
|
||||
Map<String, String> requestHeaders = null;
|
||||
if (fetchState.getContext().getImageRequest() instanceof ReactNetworkImageRequest) {
|
||||
ReactNetworkImageRequest networkImageRequest = (ReactNetworkImageRequest)
|
||||
fetchState.getContext().getImageRequest();
|
||||
requestHeaders = getHeaders(networkImageRequest.getHeaders());
|
||||
}
|
||||
if (requestHeaders == null) {
|
||||
requestHeaders = Collections.emptyMap();
|
||||
}
|
||||
final Request request = new Request.Builder()
|
||||
.cacheControl(new CacheControl.Builder().noStore().build())
|
||||
.url(uri.toString())
|
||||
.headers(Headers.of(requestHeaders))
|
||||
.get()
|
||||
.build();
|
||||
|
||||
fetchWithRequest(fetchState, callback, request);
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ android_library(
|
|||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/react/module/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||
react_native_target('java/com/facebook/react/modules/fresco:fresco'),
|
||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/views/imagehelper:withmultisource'),
|
||||
],
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.facebook.drawee.backends.pipeline.Fresco;
|
|||
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
@ -171,6 +172,11 @@ public class ReactImageManager extends SimpleViewManager<ReactImageView> {
|
|||
view.setShouldNotifyLoadEvents(shouldNotifyLoadEvents);
|
||||
}
|
||||
|
||||
@ReactProp(name = "headers")
|
||||
public void setHeaders(ReactImageView view, ReadableMap headers) {
|
||||
view.setHeaders(headers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.of(
|
||||
|
|
|
@ -54,6 +54,7 @@ import com.facebook.react.bridge.ReactContext;
|
|||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.FloatUtil;
|
||||
import com.facebook.react.modules.fresco.ReactNetworkImageRequest;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
|
@ -163,6 +164,7 @@ public class ReactImageView extends GenericDraweeView {
|
|||
private final @Nullable Object mCallerContext;
|
||||
private int mFadeDurationMs = -1;
|
||||
private boolean mProgressiveRenderingEnabled;
|
||||
private ReadableMap mHeaders;
|
||||
|
||||
// We can't specify rounding in XML, so have to do so here
|
||||
private static GenericDraweeHierarchy buildHierarchy(Context context) {
|
||||
|
@ -324,6 +326,10 @@ public class ReactImageView extends GenericDraweeView {
|
|||
computedCorners[2] = mBorderCornerRadii != null && !YogaConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius;
|
||||
computedCorners[3] = mBorderCornerRadii != null && !YogaConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius;
|
||||
}
|
||||
|
||||
public void setHeaders(ReadableMap headers) {
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
public void maybeUpdateView() {
|
||||
if (!mIsDirty) {
|
||||
|
@ -384,12 +390,13 @@ public class ReactImageView extends GenericDraweeView {
|
|||
|
||||
ResizeOptions resizeOptions = doResize ? new ResizeOptions(getWidth(), getHeight()) : null;
|
||||
|
||||
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri())
|
||||
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mImageSource.getUri())
|
||||
.setPostprocessor(postprocessor)
|
||||
.setResizeOptions(resizeOptions)
|
||||
.setAutoRotateEnabled(true)
|
||||
.setProgressiveRenderingEnabled(mProgressiveRenderingEnabled)
|
||||
.build();
|
||||
.setProgressiveRenderingEnabled(mProgressiveRenderingEnabled);
|
||||
|
||||
ImageRequest imageRequest = ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
|
||||
|
||||
// This builder is reused
|
||||
mDraweeControllerBuilder.reset();
|
||||
|
|
|
@ -14,6 +14,7 @@ android_library(
|
|||
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/module/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/modules/fresco:fresco'),
|
||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/views/text:text'),
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
|||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableType;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.views.text.ReactTextInlineImageShadowNode;
|
||||
import com.facebook.react.views.text.TextInlineImageSpan;
|
||||
|
@ -36,6 +37,7 @@ import com.facebook.react.views.text.TextInlineImageSpan;
|
|||
public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {
|
||||
|
||||
private @Nullable Uri mUri;
|
||||
private ReadableMap mHeaders;
|
||||
private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
|
||||
private final @Nullable Object mCallerContext;
|
||||
private float mWidth = YogaConstants.UNDEFINED;
|
||||
|
@ -73,6 +75,11 @@ public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineIm
|
|||
mUri = uri;
|
||||
}
|
||||
|
||||
@ReactProp(name = "headers")
|
||||
public void setHeaders(ReadableMap headers) {
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Besides width/height, all other layout props on inline images are ignored
|
||||
*/
|
||||
|
@ -100,6 +107,10 @@ public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineIm
|
|||
return mUri;
|
||||
}
|
||||
|
||||
public ReadableMap getHeaders() {
|
||||
return mHeaders;
|
||||
}
|
||||
|
||||
// TODO: t9053573 is tracking that this code should be shared
|
||||
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
|
@ -131,6 +142,7 @@ public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineIm
|
|||
height,
|
||||
width,
|
||||
getUri(),
|
||||
getHeaders(),
|
||||
getDraweeControllerBuilder(),
|
||||
getCallerContext());
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@ import com.facebook.drawee.interfaces.DraweeController;
|
|||
import com.facebook.drawee.view.DraweeHolder;
|
||||
import com.facebook.imagepipeline.request.ImageRequest;
|
||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.views.text.TextInlineImageSpan;
|
||||
import com.facebook.react.modules.fresco.ReactNetworkImageRequest;
|
||||
|
||||
/**
|
||||
* FrescoBasedTextInlineImageSpan is a span for Images that are inside <Text/>. It computes
|
||||
|
@ -48,6 +50,7 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
|
|||
private int mHeight;
|
||||
private Uri mUri;
|
||||
private int mWidth;
|
||||
private ReadableMap mHeaders;
|
||||
|
||||
private @Nullable TextView mTextView;
|
||||
|
||||
|
@ -56,6 +59,7 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
|
|||
int height,
|
||||
int width,
|
||||
@Nullable Uri uri,
|
||||
ReadableMap headers,
|
||||
AbstractDraweeControllerBuilder draweeControllerBuilder,
|
||||
@Nullable Object callerContext) {
|
||||
mDraweeHolder = new DraweeHolder(
|
||||
|
@ -68,6 +72,7 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
|
|||
mHeight = height;
|
||||
mWidth = width;
|
||||
mUri = (uri != null) ? uri : Uri.EMPTY;
|
||||
mHeaders = headers;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,8 +131,8 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
|
|||
int bottom,
|
||||
Paint paint) {
|
||||
if (mDrawable == null) {
|
||||
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
|
||||
.build();
|
||||
ImageRequestBuilder imageRequestBuilder = ImageRequestBuilder.newBuilderWithSource(mUri);
|
||||
ImageRequest imageRequest = ReactNetworkImageRequest.fromBuilderWithHeaders(imageRequestBuilder, mHeaders);
|
||||
|
||||
DraweeController draweeController = mDraweeControllerBuilder
|
||||
.reset()
|
||||
|
|
|
@ -6,6 +6,7 @@ android_library(
|
|||
deps = [
|
||||
YOGA_TARGET,
|
||||
react_native_dep('android_res/com/facebook/catalyst/appcompat:appcompat'),
|
||||
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'),
|
||||
|
|
|
@ -6,8 +6,8 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'fresco-binary-aar',
|
||||
url = 'mvn:com.facebook.fresco:fresco:aar:0.11.0',
|
||||
sha1 = '86df1ab4b0074e1aeceb419593d2ea6d97cdc3b4',
|
||||
url = 'mvn:com.facebook.fresco:fresco:aar:1.0.1',
|
||||
sha1 = '87d86ce36812b7b859f6176e253b71b54d4a39e3',
|
||||
)
|
||||
|
||||
android_prebuilt_aar(
|
||||
|
@ -18,8 +18,8 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'drawee-binary-aar',
|
||||
url = 'mvn:com.facebook.fresco:drawee:aar:0.11.0',
|
||||
sha1 = '7c8a4d211b2334b6d52b9de614b52423b16f7704',
|
||||
url = 'mvn:com.facebook.fresco:drawee:aar:1.0.1',
|
||||
sha1 = '7eea1c7dd619e7621f6e818c007c30970ac31575',
|
||||
)
|
||||
|
||||
android_library(
|
||||
|
@ -40,8 +40,8 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'imagepipeline-base-aar',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline-base:aar:0.11.0',
|
||||
sha1 = '0f450cd58350ef5d6734f9772bc780b67cc538c5',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline-base:aar:1.0.1',
|
||||
sha1 = '44d5e4b7c07afaee610ea2dda29535455cd1a20e',
|
||||
)
|
||||
|
||||
android_prebuilt_aar(
|
||||
|
@ -52,8 +52,8 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'imagepipeline-aar',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline:aar:0.11.0',
|
||||
sha1 = 'd57b234db14899af8c36876d7937d63fddca5b12',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline:aar:1.0.1',
|
||||
sha1 = '78e637099db724c3963df4515d014c9d7232469e',
|
||||
)
|
||||
|
||||
prebuilt_jar(
|
||||
|
@ -76,8 +76,8 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'fbcore-aar',
|
||||
url = 'mvn:com.facebook.fresco:fbcore:aar:0.11.0',
|
||||
sha1 = 'e732e63ea19b19d053eebfe46870157ee79ad034',
|
||||
url = 'mvn:com.facebook.fresco:fbcore:aar:1.0.1',
|
||||
sha1 = '25cdfb603c04e96486446da625cf8a90666eb55f',
|
||||
)
|
||||
|
||||
android_prebuilt_aar(
|
||||
|
@ -88,6 +88,6 @@ android_prebuilt_aar(
|
|||
|
||||
remote_file(
|
||||
name = 'imagepipeline-okhttp3-binary-aar',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:0.11.0',
|
||||
sha1 = '3d7e6d1a2f2e973a596aae7d523667b5a3d6d8a5',
|
||||
url = 'mvn:com.facebook.fresco:imagepipeline-okhttp3:aar:1.0.1',
|
||||
sha1 = '361e123fd114481ee037199db21337f06994f36e',
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue