Skip to content

Commit c74001d

Browse files
author
Adam Comella
committed
Android: Support HTTP headers for source prop on <Image> components
Allows developers to specify headers to include in the HTTP request when fetching a remote image. For example, one might leverage this when fetching an image from an endpoint that requires authentication: ``` <Image style={styles.logo} source={{ uri: 'http://facebook.github.io/react/img/logo_og.png', headers: { Authorization: 'someAuthToken' } }} /> ``` Note that the header values must be strings.
1 parent 85a6f01 commit c74001d

File tree

5 files changed

+70
-0
lines changed

5 files changed

+70
-0
lines changed

Libraries/Image/Image.android.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,14 @@ var Image = React.createClass({
8585
* This prop can also contain several remote `uri`, specified together with
8686
* their width and height. The native side will then choose the best `uri` to display
8787
* based on the measured size of the image container.
88+
*
89+
* `headers` is an object representing the HTTP headers to send along with the request
90+
* for a remote image.
8891
*/
8992
source: PropTypes.oneOfType([
9093
PropTypes.shape({
9194
uri: PropTypes.string,
95+
headers: PropTypes.objectOf(PropTypes.string),
9296
}),
9397
// Opaque type returned by require('./image.jpg')
9498
PropTypes.number,
@@ -268,6 +272,7 @@ var Image = React.createClass({
268272
style,
269273
shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
270274
src: sources,
275+
headers: source.headers,
271276
loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
272277
});
273278

@@ -314,6 +319,7 @@ var styles = StyleSheet.create({
314319
var cfg = {
315320
nativeOnly: {
316321
src: true,
322+
headers: true,
317323
loadingIndicatorSrc: true,
318324
defaultImageSrc: true,
319325
imageTag: true,

ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.facebook.drawee.backends.pipeline.Fresco;
2121
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
2222
import com.facebook.react.bridge.ReadableArray;
23+
import com.facebook.react.bridge.ReadableMap;
2324
import com.facebook.react.common.MapBuilder;
2425
import com.facebook.react.uimanager.PixelUtil;
2526
import com.facebook.react.uimanager.SimpleViewManager;
@@ -155,6 +156,11 @@ public void setLoadHandlersRegistered(ReactImageView view, boolean shouldNotifyL
155156
view.setShouldNotifyLoadEvents(shouldNotifyLoadEvents);
156157
}
157158

159+
@ReactProp(name = "headers")
160+
public void setHeaders(ReactImageView view, ReadableMap headers) {
161+
view.setHeaders(headers);
162+
}
163+
158164
@Override
159165
public @Nullable Map getExportedCustomDirectEventTypeConstants() {
160166
return MapBuilder.of(

ReactAndroid/src/main/java/com/facebook/react/views/image/ReactImageView.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import javax.annotation.Nullable;
1313

1414
import java.util.Arrays;
15+
import java.util.HashMap;
1516
import java.util.LinkedList;
1617
import java.util.List;
18+
import java.util.Map;
1719

1820
import android.content.Context;
1921
import android.graphics.Bitmap;
@@ -51,6 +53,7 @@
5153
import com.facebook.react.bridge.ReactContext;
5254
import com.facebook.react.bridge.ReadableArray;
5355
import com.facebook.react.bridge.ReadableMap;
56+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
5457
import com.facebook.react.uimanager.PixelUtil;
5558
import com.facebook.react.uimanager.UIManagerModule;
5659
import com.facebook.react.uimanager.events.EventDispatcher;
@@ -160,6 +163,7 @@ public void process(Bitmap output, Bitmap source) {
160163
private final @Nullable Object mCallerContext;
161164
private int mFadeDurationMs = -1;
162165
private boolean mProgressiveRenderingEnabled;
166+
private @Nullable Map<String, String> mHeaders;
163167

164168
// We can't specify rounding in XML, so have to do so here
165169
private static GenericDraweeHierarchy buildHierarchy(Context context) {
@@ -168,6 +172,20 @@ private static GenericDraweeHierarchy buildHierarchy(Context context) {
168172
.build();
169173
}
170174

175+
private static @Nullable Map<String, String> headersAsMap(ReadableMap readableMap) {
176+
if (readableMap == null) {
177+
return null;
178+
}
179+
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
180+
Map<String, String> map = new HashMap<>();
181+
while (iterator.hasNextKey()) {
182+
String key = iterator.nextKey();
183+
String value = readableMap.getString(key);
184+
map.put(key, value);
185+
}
186+
return map;
187+
}
188+
171189
public ReactImageView(
172190
Context context,
173191
AbstractDraweeControllerBuilder draweeControllerBuilder,
@@ -305,6 +323,10 @@ private void cornerRadii(float[] computedCorners) {
305323
computedCorners[2] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[2]) ? mBorderCornerRadii[2] : defaultBorderRadius;
306324
computedCorners[3] = mBorderCornerRadii != null && !CSSConstants.isUndefined(mBorderCornerRadii[3]) ? mBorderCornerRadii[3] : defaultBorderRadius;
307325
}
326+
327+
public void setHeaders(ReadableMap headers) {
328+
mHeaders = headersAsMap(headers);
329+
}
308330

309331
public void maybeUpdateView() {
310332
if (!mIsDirty) {
@@ -369,6 +391,7 @@ public void maybeUpdateView() {
369391
.setPostprocessor(postprocessor)
370392
.setResizeOptions(resizeOptions)
371393
.setAutoRotateEnabled(true)
394+
.setHeaders(mHeaders)
372395
.setProgressiveRenderingEnabled(mProgressiveRenderingEnabled)
373396
.build();
374397

ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageShadowNode.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.facebook.csslayout.CSSNode;
2222
import com.facebook.drawee.controller.AbstractDraweeControllerBuilder;
2323
import com.facebook.react.bridge.ReadableArray;
24+
import com.facebook.react.bridge.ReadableMap;
2425
import com.facebook.react.uimanager.annotations.ReactProp;
2526
import com.facebook.react.views.text.ReactTextInlineImageShadowNode;
2627
import com.facebook.react.views.text.TextInlineImageSpan;
@@ -33,6 +34,7 @@
3334
public class FrescoBasedReactTextInlineImageShadowNode extends ReactTextInlineImageShadowNode {
3435

3536
private @Nullable Uri mUri;
37+
private ReadableMap mHeaders;
3638
private final AbstractDraweeControllerBuilder mDraweeControllerBuilder;
3739
private final @Nullable Object mCallerContext;
3840

@@ -68,10 +70,19 @@ public void setSource(@Nullable ReadableArray sources) {
6870
mUri = uri;
6971
}
7072

73+
@ReactProp(name = "headers")
74+
public void setHeaders(ReadableMap headers) {
75+
mHeaders = headers;
76+
}
77+
7178
public @Nullable Uri getUri() {
7279
return mUri;
7380
}
7481

82+
public ReadableMap getHeaders() {
83+
return mHeaders;
84+
}
85+
7586
// TODO: t9053573 is tracking that this code should be shared
7687
private static @Nullable Uri getResourceDrawableUri(Context context, @Nullable String name) {
7788
if (name == null || name.isEmpty()) {
@@ -103,6 +114,7 @@ public TextInlineImageSpan buildInlineImageSpan() {
103114
height,
104115
width,
105116
getUri(),
117+
getHeaders(),
106118
getDraweeControllerBuilder(),
107119
getCallerContext());
108120
}

ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageSpan.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@
2525
import com.facebook.drawee.view.DraweeHolder;
2626
import com.facebook.imagepipeline.request.ImageRequest;
2727
import com.facebook.imagepipeline.request.ImageRequestBuilder;
28+
import com.facebook.react.bridge.ReadableMap;
29+
import com.facebook.react.bridge.ReadableMapKeySetIterator;
2830
import com.facebook.react.views.text.TextInlineImageSpan;
2931

32+
import java.util.HashMap;
33+
import java.util.Map;
34+
3035
/**
3136
* FrescoBasedTextInlineImageSpan is a span for Images that are inside <Text/>. It computes
3237
* its size based on the input size. When it is time to draw, it will use the Fresco framework to
@@ -48,14 +53,30 @@ public class FrescoBasedReactTextInlineImageSpan extends TextInlineImageSpan {
4853
private int mHeight;
4954
private Uri mUri;
5055
private int mWidth;
56+
private @Nullable Map<String, String> mHeaders;
5157

5258
private @Nullable TextView mTextView;
5359

60+
private static @Nullable Map<String, String> headersAsMap(ReadableMap readableMap) {
61+
if (readableMap == null) {
62+
return null;
63+
}
64+
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
65+
Map<String, String> map = new HashMap<>();
66+
while (iterator.hasNextKey()) {
67+
String key = iterator.nextKey();
68+
String value = readableMap.getString(key);
69+
map.put(key, value);
70+
}
71+
return map;
72+
}
73+
5474
public FrescoBasedReactTextInlineImageSpan(
5575
Resources resources,
5676
int height,
5777
int width,
5878
@Nullable Uri uri,
79+
ReadableMap headers,
5980
AbstractDraweeControllerBuilder draweeControllerBuilder,
6081
@Nullable Object callerContext) {
6182
mDraweeHolder = new DraweeHolder(
@@ -68,6 +89,7 @@ public FrescoBasedReactTextInlineImageSpan(
6889
mHeight = height;
6990
mWidth = width;
7091
mUri = (uri != null) ? uri : Uri.EMPTY;
92+
mHeaders = headersAsMap(headers);
7193
}
7294

7395
/**
@@ -127,6 +149,7 @@ public void draw(
127149
Paint paint) {
128150
if (mDrawable == null) {
129151
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(mUri)
152+
.setHeaders(mHeaders)
130153
.build();
131154

132155
DraweeController draweeController = mDraweeControllerBuilder

0 commit comments

Comments
 (0)