iOS: Introduced RCTImageURLLoaderWithAttribution

Summary:
Changelog: [iOS] [Changed] - New internal image attribution support, but files importing RCTImageLoader.h must be converted to ObjC++

This new interface is the same as RCTImageURLLoader, but with additional support to pass in optional attribution information. The attribution info is not strictly defined (we may do so in the future though), and it's up to the hosting application and RCTImageURLLoader classes to handle it.

Reviewed By: sammy-SC

Differential Revision: D18492882

fbshipit-source-id: c3870c60e6c2e7c65758fc3235ebf5db369e07dc
This commit is contained in:
Kevin Gozali 2019-11-16 00:10:25 -08:00 коммит произвёл Facebook Github Bot
Родитель 806a2b8103
Коммит fdcdca4cfa
6 изменённых файлов: 136 добавлений и 11 удалений

Просмотреть файл

@ -15,6 +15,7 @@
#import <React/RCTDefines.h> #import <React/RCTDefines.h>
#import <React/RCTImageCache.h> #import <React/RCTImageCache.h>
#import <React/RCTImageLoader.h> #import <React/RCTImageLoader.h>
#import <React/RCTImageLoaderWithAttributionProtocol.h>
#import <React/RCTImageUtils.h> #import <React/RCTImageUtils.h>
#import <React/RCTLog.h> #import <React/RCTLog.h>
#import <React/RCTNetworking.h> #import <React/RCTNetworking.h>
@ -22,13 +23,15 @@
#import "RCTImagePlugins.h" #import "RCTImagePlugins.h"
using namespace facebook::react;
static NSInteger RCTImageBytesForImage(UIImage *image) static NSInteger RCTImageBytesForImage(UIImage *image)
{ {
NSInteger singleImageBytes = image.size.width * image.size.height * image.scale * image.scale * 4; NSInteger singleImageBytes = image.size.width * image.size.height * image.scale * image.scale * 4;
return image.images ? image.images.count * singleImageBytes : singleImageBytes; return image.images ? image.images.count * singleImageBytes : singleImageBytes;
} }
@interface RCTImageLoader() <NativeImageLoaderIOSSpec> @interface RCTImageLoader() <NativeImageLoaderIOSSpec, RCTImageLoaderWithAttributionProtocol>
@end @end
@ -288,11 +291,32 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
scale:1 scale:1
clipped:YES clipped:YES
resizeMode:RCTResizeModeStretch resizeMode:RCTResizeModeStretch
attribution:{}
progressBlock:nil progressBlock:nil
partialLoadBlock:nil partialLoadBlock:nil
completionBlock:callback]; completionBlock:callback];
} }
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
size:(CGSize)size
scale:(CGFloat)scale
clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
{
return [self loadImageWithURLRequest:imageURLRequest
size:size
scale:scale
clipped:clipped
resizeMode:resizeMode
attribution:{}
progressBlock:progressBlock
partialLoadBlock:partialLoadBlock
completionBlock:completionBlock];
}
- (void)dequeueTasks - (void)dequeueTasks
{ {
dispatch_async(_URLRequestQueue, ^{ dispatch_async(_URLRequestQueue, ^{
@ -363,6 +387,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
size:(CGSize)size size:(CGSize)size
scale:(CGFloat)scale scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode resizeMode:(RCTResizeMode)resizeMode
attribution:(const ImageURLLoaderAttribution &)attribution
progressBlock:(RCTImageLoaderProgressBlock)progressHandler progressBlock:(RCTImageLoaderProgressBlock)progressHandler
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response))completionBlock completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSURLResponse *response))completionBlock
@ -383,6 +408,9 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
request = mutableRequest; request = mutableRequest;
} }
// Create a copy here so the value is retained when accessed in the blocks below.
ImageURLLoaderAttribution attributionCopy(attribution);
// Find suitable image URL loader // Find suitable image URL loader
id<RCTImageURLLoader> loadHandler = [self imageURLLoaderForURL:request.URL]; id<RCTImageURLLoader> loadHandler = [self imageURLLoaderForURL:request.URL];
BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ? BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ?
@ -417,13 +445,25 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
// If the loader doesn't require scheduling we call it directly on // If the loader doesn't require scheduling we call it directly on
// the main queue. // the main queue.
if (loadHandler && !requiresScheduling) { if (loadHandler && !requiresScheduling) {
if ([loadHandler conformsToProtocol:@protocol(RCTImageURLLoaderWithAttribution)]) {
return [(id<RCTImageURLLoaderWithAttribution>)loadHandler loadImageForURL:request.URL
size:size
scale:scale
resizeMode:resizeMode
attribution:attributionCopy
progressHandler:progressHandler
partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image) {
completionHandler(error, image, nil);
}];
}
return [loadHandler loadImageForURL:request.URL return [loadHandler loadImageForURL:request.URL
size:size size:size
scale:scale scale:scale
resizeMode:resizeMode resizeMode:resizeMode
progressHandler:progressHandler progressHandler:progressHandler
partialLoadHandler:partialLoadHandler partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image){ completionHandler:^(NSError *error, UIImage *image) {
completionHandler(error, image, nil); completionHandler(error, image, nil);
}]; }];
} }
@ -441,15 +481,29 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
} }
if (loadHandler) { if (loadHandler) {
dispatch_block_t cancelLoadLocal = [loadHandler loadImageForURL:request.URL dispatch_block_t cancelLoadLocal;
size:size if ([loadHandler conformsToProtocol:@protocol(RCTImageURLLoaderWithAttribution)]) {
scale:scale cancelLoadLocal = [(id<RCTImageURLLoaderWithAttribution>)loadHandler loadImageForURL:request.URL
resizeMode:resizeMode size:size
progressHandler:progressHandler scale:scale
partialLoadHandler:partialLoadHandler resizeMode:resizeMode
completionHandler:^(NSError *error, UIImage *image) { attribution:attributionCopy
completionHandler(error, image, nil); progressHandler:progressHandler
}]; partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image) {
completionHandler(error, image, nil);
}];
} else {
cancelLoadLocal = [loadHandler loadImageForURL:request.URL
size:size
scale:scale
resizeMode:resizeMode
progressHandler:progressHandler
partialLoadHandler:partialLoadHandler
completionHandler:^(NSError *error, UIImage *image) {
completionHandler(error, image, nil);
}];
}
[cancelLoadLock lock]; [cancelLoadLock lock];
cancelLoad = cancelLoadLocal; cancelLoad = cancelLoadLocal;
[cancelLoadLock unlock]; [cancelLoadLock unlock];
@ -607,6 +661,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
scale:(CGFloat)scale scale:(CGFloat)scale
clipped:(BOOL)clipped clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode resizeMode:(RCTResizeMode)resizeMode
attribution:(const ImageURLLoaderAttribution &)attribution
progressBlock:(RCTImageLoaderProgressBlock)progressBlock progressBlock:(RCTImageLoaderProgressBlock)progressBlock
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock completionBlock:(RCTImageLoaderCompletionBlock)completionBlock
@ -673,6 +728,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
size:size size:size
scale:scale scale:scale
resizeMode:resizeMode resizeMode:resizeMode
attribution:attribution
progressBlock:progressBlock progressBlock:progressBlock
partialLoadBlock:partialLoadBlock partialLoadBlock:partialLoadBlock
completionBlock:completionHandler]; completionBlock:completionHandler];
@ -830,6 +886,7 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
size:CGSizeZero size:CGSizeZero
scale:1 scale:1
resizeMode:RCTResizeModeStretch resizeMode:RCTResizeModeStretch
attribution:{}
progressBlock:NULL progressBlock:NULL
partialLoadBlock:NULL partialLoadBlock:NULL
completionBlock:completion]; completionBlock:completion];

Просмотреть файл

@ -113,4 +113,5 @@
* protocol. This method should be called in bridgeDidInitializeModule. * protocol. This method should be called in bridgeDidInitializeModule.
*/ */
- (void)setImageCache:(id<RCTImageCache>)cache; - (void)setImageCache:(id<RCTImageCache>)cache;
@end @end

Просмотреть файл

@ -0,0 +1,29 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTImageURLLoaderWithAttribution.h>
@protocol RCTImageLoaderWithAttributionProtocol<RCTImageLoaderProtocol>
/**
* Same as the variant in RCTImageURLLoaderProtocol, but allows passing attribution
* information that each image URL loader can process.
*/
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
size:(CGSize)size
scale:(CGFloat)scale
clipped:(BOOL)clipped
resizeMode:(RCTResizeMode)resizeMode
attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
@end

Просмотреть файл

@ -0,0 +1,38 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTImageURLLoader.h>
namespace facebook {
namespace react {
struct ImageURLLoaderAttribution {
int32_t surfaceId = 0;
};
} // namespace react
} // namespace facebook
/**
* Same as the RCTImageURLLoader interface, but allows passing in optional `attribution` information.
* This is useful for per-app logging and other instrumentation.
*/
@protocol RCTImageURLLoaderWithAttribution <RCTImageURLLoader>
/**
* Same as the RCTImageURLLoader variant above, but allows optional `attribution` information.
*/
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
attribution:(const facebook::react::ImageURLLoaderAttribution &)attribution
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
@end

Просмотреть файл