document-picker/ios/RNDocumentPicker/RNDocumentPicker.m
2018-10-31 22:22:18 +10:00

183 lines
6.2 KiB
Objective-C

#import "RNDocumentPicker.h"
#import <MobileCoreServices/MobileCoreServices.h>
#if __has_include(<React/RCTConvert.h>)
#import <React/RCTConvert.h>
#import <React/RCTBridge.h>
#else // back compatibility for RN version < 0.40
#import "RCTConvert.h"
#import "RCTBridge.h"
#endif
static NSString *const E_DOCUMENT_PICKER_CANCELED = @"DOCUMENT_PICKER_CANCELED";
static NSString *const E_INVALID_DATA_RETURNED = @"INVALID_DATA_RETURNED";
static NSString *const OPTION_TYPE = @"type";
static NSString *const OPTION_MULIPLE = @"multiple";
static NSString *const FIELD_URI = @"uri";
static NSString *const FIELD_NAME = @"name";
static NSString *const FIELD_TYPE = @"type";
static NSString *const FIELD_SIZE = @"size";
@interface RNDocumentPicker () <UIDocumentPickerDelegate>
@end
@implementation RNDocumentPicker {
NSMutableArray *composeViews;
NSMutableArray *composeResolvers;
NSMutableArray *composeRejecters;
}
@synthesize bridge = _bridge;
- (instancetype)init
{
if ((self = [super init])) {
composeResolvers = [[NSMutableArray alloc] init];
composeRejecters = [[NSMutableArray alloc] init];
composeViews = [[NSMutableArray alloc] init];
}
return self;
}
+ (BOOL)requiresMainQueueSetup {
return NO;
}
- (dispatch_queue_t)methodQueue
{
return dispatch_get_main_queue();
}
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(pick:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *allowedUTIs = [RCTConvert NSArray:options[OPTION_TYPE]];
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:(NSArray *)allowedUTIs inMode:UIDocumentPickerModeImport];
[composeResolvers addObject:resolve];
[composeRejecters addObject:reject];
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
if (@available(iOS 11, *)) {
documentPicker.allowsMultipleSelection = [RCTConvert BOOL:options[OPTION_MULIPLE]];
}
#endif
UIViewController *rootViewController = [[[[UIApplication sharedApplication]delegate] window] rootViewController];
while (rootViewController.presentedViewController) {
rootViewController = rootViewController.presentedViewController;
}
[rootViewController presentViewController:documentPicker animated:YES completion:nil];
}
- (NSMutableDictionary *)getMetadataForUrl:(NSURL *)url error:(NSError **)error
{
__block NSMutableDictionary* result = [NSMutableDictionary dictionary];
[url startAccessingSecurityScopedResource];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] init];
__block NSError *fileError;
[coordinator coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingResolvesSymbolicLink error:&fileError byAccessor:^(NSURL *newURL) {
if (!fileError) {
[result setValue:newURL.absoluteString forKey:FIELD_URI];
[result setValue:[newURL lastPathComponent] forKey:FIELD_NAME];
NSError *attributesError = nil;
NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:newURL.path error:&attributesError];
if(!attributesError) {
[result setValue:[fileAttributes objectForKey:NSFileSize] forKey:FIELD_SIZE];
} else {
NSLog(@"%@", attributesError);
}
if ( newURL.pathExtension != nil ) {
CFStringRef extension = (__bridge CFStringRef)[newURL pathExtension];
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
CFStringRef mimeType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
CFRelease(uti);
NSString *mimeTypeString = (__bridge_transfer NSString *)mimeType;
[result setValue:mimeTypeString forKey:FIELD_TYPE];
}
}
}];
[url stopAccessingSecurityScopedResource];
if (fileError) {
*error = fileError;
return nil;
} else {
return result;
}
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url
{
if (controller.documentPickerMode == UIDocumentPickerModeImport) {
RCTPromiseResolveBlock resolve = [composeResolvers lastObject];
RCTPromiseRejectBlock reject = [composeRejecters lastObject];
[composeResolvers removeLastObject];
[composeRejecters removeLastObject];
NSError *error;
NSMutableDictionary* result = [self getMetadataForUrl:url error:&error];
if (result) {
NSArray *results = @[result];
resolve(results);
} else {
reject(E_INVALID_DATA_RETURNED, error.localizedDescription, error);
}
}
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
{
if (controller.documentPickerMode == UIDocumentPickerModeImport) {
RCTPromiseResolveBlock resolve = [composeResolvers lastObject];
RCTPromiseRejectBlock reject = [composeRejecters lastObject];
[composeResolvers removeLastObject];
[composeRejecters removeLastObject];
NSMutableArray *results = [NSMutableArray array];
for (id url in urls) {
NSError *error;
NSMutableDictionary* result = [self getMetadataForUrl:url error:&error];
if (result) {
[results addObject:result];
} else {
reject(E_INVALID_DATA_RETURNED, error.localizedDescription, error);
return;
}
}
resolve(results);
}
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
if (controller.documentPickerMode == UIDocumentPickerModeImport) {
RCTPromiseRejectBlock reject = [composeRejecters lastObject];
[composeResolvers removeLastObject];
[composeRejecters removeLastObject];
reject(E_DOCUMENT_PICKER_CANCELED, @"User canceled document picker", nil);
}
}
@end