diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index bf5888a4720..808feef7253 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 1E76D5232522316A005A268F /* GTAmericaExp-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = AE65058949E14DA5A2D5435D /* GTAmericaExp-Medium.otf */; }; 1E76D5242522316A005A268F /* GTAmericaExp-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 8C7003903C1E4957824899BB /* GTAmericaExp-Regular.otf */; }; 1E76D5252522316A005A268F /* GTAmericaExp-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = A292718541C841859D97DF2F /* GTAmericaExp-Thin.otf */; }; + 374FB8D728A133FE000D84EF /* OriginImageRequestHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */; }; 425866037F4C482AAB46CB8B /* GTAmericaExp-BdIt.otf in Resources */ = {isa = PBXBuildFile; fileRef = A8D6F2F722FD4E66A38EBBB6 /* GTAmericaExp-BdIt.otf */; }; 51A507DCDB4AFAE4CE18F09C /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F365B4C53B0AD330B82D09E5 /* libPods-NewExpensify-NewExpensifyTests.a */; }; 52477A09739546F4814EA25F /* GTAmericaExpMono-Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0DE5D096095C41EE96746C9E /* GTAmericaExpMono-Bd.otf */; }; @@ -65,6 +66,8 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NewExpensify/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NewExpensify/main.m; sourceTree = ""; }; 18D050DF262400AF000D658B /* BridgingFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BridgingFile.swift; sourceTree = ""; }; + 374FB8D528A133A7000D84EF /* OriginImageRequestHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OriginImageRequestHandler.h; path = NewExpensify/OriginImageRequestHandler.h; sourceTree = ""; }; + 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = OriginImageRequestHandler.mm; path = NewExpensify/OriginImageRequestHandler.mm; sourceTree = ""; }; 3981452A2C7340EBBA2B9BD1 /* GTAmericaExpMono-BdIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExpMono-BdIt.otf"; path = "../assets/fonts/GTAmericaExpMono-BdIt.otf"; sourceTree = ""; }; 5150E5D0D7F74DBA8D7C1914 /* GTAmericaExpMono-RgIt.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "GTAmericaExpMono-RgIt.otf"; path = "../assets/fonts/GTAmericaExpMono-RgIt.otf"; sourceTree = ""; }; 5DADA231C0DAA1842EE3E945 /* Pods-NewExpensify-NewExpensifyTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debug.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debug.xcconfig"; sourceTree = ""; }; @@ -169,6 +172,8 @@ 83CBB9F61A601CBA00E9B192 = { isa = PBXGroup; children = ( + 374FB8D528A133A7000D84EF /* OriginImageRequestHandler.h */, + 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */, F0C450E92705020500FD2970 /* colors.json */, DD7904292792E76D004484B4 /* RCTBootSplash.h */, DD79042A2792E76D004484B4 /* RCTBootSplash.m */, @@ -582,6 +587,7 @@ files = ( 18D050E0262400AF000D658B /* BridgingFile.swift in Sources */, 0F5E5350263B73FD004CA14F /* EnvironmentChecker.m in Sources */, + 374FB8D728A133FE000D84EF /* OriginImageRequestHandler.mm in Sources */, 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */, DD79042B2792E76D004484B4 /* RCTBootSplash.m in Sources */, 0CDA8E34287DD650004ECBEC /* AppDelegate.mm in Sources */, diff --git a/ios/NewExpensify/OriginImageRequestHandler.h b/ios/NewExpensify/OriginImageRequestHandler.h new file mode 100644 index 00000000000..999d8abc7bb --- /dev/null +++ b/ios/NewExpensify/OriginImageRequestHandler.h @@ -0,0 +1,12 @@ +// +// OriginImageRequestHandler.h +// NewExpensify +// +// Created by ntdiary on 2022/8/8. +// + +#import + +@interface OriginImageRequestHandler : NSObject + +@end diff --git a/ios/NewExpensify/OriginImageRequestHandler.mm b/ios/NewExpensify/OriginImageRequestHandler.mm new file mode 100644 index 00000000000..81b7c309520 --- /dev/null +++ b/ios/NewExpensify/OriginImageRequestHandler.mm @@ -0,0 +1,131 @@ +// +// OriginImageRequestHandler.mm +// NewExpensify +// +// Created by ntdiary on 2022/8/8. +// +// Use this handler to parse images uri returned by react-native-image-picker +// instead of the default `RCTImageLoader.mm` +// See https://github.com/facebook/react-native/issues/33760#issuecomment-1196562161 + +#import +#import + +#import +#import + +#import "OriginImageRequestHandler.h" + +@interface OriginImageRequestHandler() + +@end + +@implementation OriginImageRequestHandler +{ + NSOperationQueue *_fileQueue; +} + +RCT_EXPORT_MODULE() + +- (void)invalidate +{ + [_fileQueue cancelAllOperations]; + _fileQueue = nil; +} + +/** + * Only used for parsing the png/jpg image in the application home directory + */ +- (BOOL)canHandleRequest:(NSURLRequest *)request +{ + return [request.URL.scheme caseInsensitiveCompare:@"file"] == NSOrderedSame + && RCTIsLocalAssetURL(request.URL) + && !RCTIsBundleAssetURL(request.URL); +} + + +/** + * Send a network request and call the delegate with the response data. + */ +- (NSOperation *)sendRequest:(NSURLRequest *)request + withDelegate:(id)delegate +{ + // Lazy setup + if (!_fileQueue) { + _fileQueue = [NSOperationQueue new]; + _fileQueue.maxConcurrentOperationCount = 4; + } + + __weak __block NSBlockOperation *weakOp; + __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + + // Get content length + NSError *error = nil; + NSFileManager *fileManager = [NSFileManager new]; + NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:request.URL.path error:&error]; + if (!fileAttributes) { + [delegate URLRequest:weakOp didCompleteWithError:error]; + return; + } + + // Get mime type + NSString *fileExtension = [request.URL pathExtension]; + NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag( + kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL); + NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass( + (__bridge CFStringRef)UTI, kUTTagClassMIMEType); + + // Send response + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL + MIMEType:contentType + expectedContentLength:[fileAttributes[NSFileSize] ?: @-1 integerValue] + textEncodingName:nil]; + + [delegate URLRequest:weakOp didReceiveResponse:response]; + + // Load data + NSData *data = [NSData dataWithContentsOfURL:request.URL + options:NSDataReadingMappedIfSafe + error:&error]; + if (data) { + [delegate URLRequest:weakOp didReceiveData:data]; + } + [delegate URLRequest:weakOp didCompleteWithError:error]; + }]; + + weakOp = op; + [_fileQueue addOperation:op]; + return op; +} + +/** + * Cancel the request + */ +- (void)cancelRequest:(NSOperation *)op +{ + [op cancel]; +} + +/** + * Should return nullptr. This method may be used later to support C++ TurboModules. + * See https://reactnative.dev/docs/new-architecture-app-modules-ios + */ +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return nullptr; +} + +/** + * Should have higher priority than RCTImageLoader.mm + */ +- (float)handlerPriority +{ + return 4; +} + +@end + +Class OriginImageRequestHandlerCls(void) { + return OriginImageRequestHandler.class; +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 493ba2c6c52..2a2b9a87a51 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -464,7 +464,7 @@ PODS: - React-Core - react-native-image-manipulator (1.0.5): - React - - react-native-image-picker (4.7.3): + - react-native-image-picker (4.8.5): - React-Core - react-native-netinfo (8.3.0): - React-Core @@ -972,7 +972,7 @@ SPEC CHECKSUMS: react-native-document-picker: 772d04a4bc5c35da9abe27b08ac271420ae3f9ef react-native-flipper: 4bfe0a324e663f1ae2f76ad0da75673de6895efe react-native-image-manipulator: db28c0cc09d89e740974c9bb2f13175eb48f1ef2 - react-native-image-picker: ae1202414bd5c37c00b2a701daa5b6194a06b7d9 + react-native-image-picker: 24a36044140202085113ce99b57bf52c62dc339e react-native-netinfo: ebbcd8fbe1a0ce7035e43cd18c5a545dcb93dd08 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-plaid-link-sdk: 9e0ebdaed648a237b36d5f6f6292b5147af92da7 diff --git a/package-lock.json b/package-lock.json index 943f860af92..a280166046e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42102,9 +42102,9 @@ "integrity": "sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==" }, "react-native-image-picker": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-4.7.3.tgz", - "integrity": "sha512-eRKm4wlsmZHmsWFyv77kYc2F+ZyEVqe0m7mqhsMzWk6TQT4FBDtEDxmRDDFq+ivCu/1QD+EPhmYcAIpeGr7Ekg==" + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-4.8.5.tgz", + "integrity": "sha512-+pQxkjO8cKv4RKTHOFS0fSHQ11HkWgb+imUPSOS8mwoChkR33aSuzV/6P4t9JCJgsus4qLAlB6BUosdIxw7GTA==" }, "react-native-image-size": { "version": "git+https://github.com/Expensify/react-native-image-size.git#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", diff --git a/package.json b/package.json index 31a903c06f8..a9865b3a6e6 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#3bbd17d63e6c38d38d857b50f6037c1c0376ff06", "react-native-haptic-feedback": "^1.13.0", "react-native-image-pan-zoom": "^2.1.12", - "react-native-image-picker": "^4.7.3", + "react-native-image-picker": "^4.8.5", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.10",