Fix permissions regression in RCTCameraRollManager

Summary:
In the past (pre D13593314), ALAssetsLibrary camera operations would pop up a permissions dialogue when appropriate and block until the user responded to the dialogue. The calls that we're now using with PHPhotoLibrary immediately return if we don't have permission to access the photo library or haven't asked before, and then asynchronously pop up a permissions dialogue, causing every first photo interaction to fail. Instead we now explicitly check for permissions or request
permissions before any operations.

Reviewed By: PeteTheHeat

Differential Revision: D13620079

fbshipit-source-id: e1befc0ddaec2c1b3334e361f5ae3a3efc5da71d
This commit is contained in:
Joshua Gross 2019-01-10 13:07:15 -08:00 committed by Facebook Github Bot
parent e172dc7b94
commit 8556340345
1 changed files with 131 additions and 105 deletions

View File

@ -76,6 +76,26 @@ RCT_EXPORT_MODULE()
static NSString *const kErrorUnableToSave = @"E_UNABLE_TO_SAVE";
static NSString *const kErrorUnableToLoad = @"E_UNABLE_TO_LOAD";
static NSString *const kErrorAuthRestricted = @"E_PHOTO_LIBRARY_AUTH_RESTRICTED";
static NSString *const kErrorAuthDenied = @"E_PHOTO_LIBRARY_AUTH_DENIED";
typedef void (^PhotosAuthorizedBlock)(void);
static void requestPhotoLibraryAccess(RCTPromiseRejectBlock reject, PhotosAuthorizedBlock authorizedBlock) {
PHAuthorizationStatus authStatus = [PHPhotoLibrary authorizationStatus];
if (authStatus == PHAuthorizationStatusRestricted) {
reject(kErrorAuthRestricted, @"Access to photo library is restricted", nil);
} else if (authStatus == PHAuthorizationStatusAuthorized) {
authorizedBlock();
} else if (authStatus == PHAuthorizationStatusNotDetermined) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
requestPhotoLibraryAccess(reject, authorizedBlock);
}];
} else {
reject(kErrorAuthDenied, @"Access to photo library was denied", nil);
}
}
RCT_EXPORT_METHOD(saveToCameraRoll:(NSURLRequest *)request
type:(NSString *)type
resolve:(RCTPromiseResolveBlock)resolve
@ -116,11 +136,12 @@ RCT_EXPORT_METHOD(saveToCameraRoll:(NSURLRequest *)request
}];
};
void (^loadBlock)(void) = ^void() {
if ([type isEqualToString:@"video"]) {
inputURI = request.URL;
saveBlock();
} else {
[_bridge.imageLoader loadImageWithURLRequest:request callback:^(NSError *error, UIImage *image) {
[self.bridge.imageLoader loadImageWithURLRequest:request callback:^(NSError *error, UIImage *image) {
if (error) {
reject(kErrorUnableToLoad, nil, error);
return;
@ -130,6 +151,9 @@ RCT_EXPORT_METHOD(saveToCameraRoll:(NSURLRequest *)request
saveBlock();
}];
}
};
requestPhotoLibraryAccess(reject, loadBlock);
}
static void RCTResolvePromise(RCTPromiseResolveBlock resolve,
@ -191,6 +215,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
collectionFetchOptions.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"localizedTitle == '%@'", groupName]];
}
requestPhotoLibraryAccess(reject, ^{
PHFetchResult<PHAssetCollection *> *const assetCollectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:collectionType subtype:collectionSubtype options:collectionFetchOptions];
[assetCollectionFetchResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull assetCollection, NSUInteger collectionIdx, BOOL * _Nonnull stopCollections) {
// Enumerate assets within the collection
@ -286,6 +311,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
RCTResolvePromise(resolve, assets, hasNextPage);
resolvedPromise = YES;
}
});
}
RCT_EXPORT_METHOD(deletePhotos:(NSArray<NSString *>*)assets