diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 3dbf2c51690e..992c8b299345 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.8.4+8 + +* Configures the `UIImagePicker` to default to gallery instead of camera when +picking multiple images on pre-iOS 14 devices. + ## 0.8.4+7 * Refactors unit test to expose private interface via a separate test header instead of the inline declaration. diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/ImagePickerPluginTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/ImagePickerPluginTests.m index bcaf2d1da37b..5f3287400c5e 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/ImagePickerPluginTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/ImagePickerPluginTests.m @@ -23,30 +23,26 @@ - (UIViewController *)presentedViewController { @end @interface ImagePickerPluginTests : XCTestCase -@property(readonly, nonatomic) id mockUIImagePicker; -@property(readonly, nonatomic) id mockAVCaptureDevice; + @end @implementation ImagePickerPluginTests -- (void)setUp { - _mockUIImagePicker = OCMClassMock([UIImagePickerController class]); - _mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]); -} - - (void)testPluginPickImageDeviceBack { + id mockUIImagePicker = OCMClassMock([UIImagePickerController class]); + id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]); // UIImagePickerControllerSourceTypeCamera is supported OCMStub(ClassMethod( - [_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) + [mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) .andReturn(YES); // UIImagePickerControllerCameraDeviceRear is supported OCMStub(ClassMethod( - [_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])) + [mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])) .andReturn(YES); // AVAuthorizationStatusAuthorized is supported - OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) + OCMStub([mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) .andReturn(AVAuthorizationStatusAuthorized); // Run test @@ -54,27 +50,30 @@ - (void)testPluginPickImageDeviceBack { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + [plugin setImagePickerControllerOverrides:@[ controller ]]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; - XCTAssertEqual([plugin getImagePickerController].cameraDevice, - UIImagePickerControllerCameraDeviceRear); + XCTAssertEqual(controller.cameraDevice, UIImagePickerControllerCameraDeviceRear); } - (void)testPluginPickImageDeviceFront { + id mockUIImagePicker = OCMClassMock([UIImagePickerController class]); + id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]); // UIImagePickerControllerSourceTypeCamera is supported OCMStub(ClassMethod( - [_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) + [mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) .andReturn(YES); // UIImagePickerControllerCameraDeviceFront is supported - OCMStub(ClassMethod([_mockUIImagePicker - isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront])) + OCMStub(ClassMethod( + [mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront])) .andReturn(YES); // AVAuthorizationStatusAuthorized is supported - OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) + OCMStub([mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) .andReturn(AVAuthorizationStatusAuthorized); // Run test @@ -82,27 +81,30 @@ - (void)testPluginPickImageDeviceFront { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + [plugin setImagePickerControllerOverrides:@[ controller ]]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; - XCTAssertEqual([plugin getImagePickerController].cameraDevice, - UIImagePickerControllerCameraDeviceFront); + XCTAssertEqual(controller.cameraDevice, UIImagePickerControllerCameraDeviceFront); } - (void)testPluginPickVideoDeviceBack { + id mockUIImagePicker = OCMClassMock([UIImagePickerController class]); + id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]); // UIImagePickerControllerSourceTypeCamera is supported OCMStub(ClassMethod( - [_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) + [mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) .andReturn(YES); // UIImagePickerControllerCameraDeviceRear is supported OCMStub(ClassMethod( - [_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])) + [mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear])) .andReturn(YES); // AVAuthorizationStatusAuthorized is supported - OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) + OCMStub([mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) .andReturn(AVAuthorizationStatusAuthorized); // Run test @@ -110,27 +112,31 @@ - (void)testPluginPickVideoDeviceBack { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + [plugin setImagePickerControllerOverrides:@[ controller ]]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; - XCTAssertEqual([plugin getImagePickerController].cameraDevice, - UIImagePickerControllerCameraDeviceRear); + XCTAssertEqual(controller.cameraDevice, UIImagePickerControllerCameraDeviceRear); } - (void)testPluginPickVideoDeviceFront { + id mockUIImagePicker = OCMClassMock([UIImagePickerController class]); + id mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]); + // UIImagePickerControllerSourceTypeCamera is supported OCMStub(ClassMethod( - [_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) + [mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) .andReturn(YES); // UIImagePickerControllerCameraDeviceFront is supported - OCMStub(ClassMethod([_mockUIImagePicker - isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront])) + OCMStub(ClassMethod( + [mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront])) .andReturn(YES); // AVAuthorizationStatusAuthorized is supported - OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) + OCMStub([mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]) .andReturn(AVAuthorizationStatusAuthorized); // Run test @@ -138,12 +144,40 @@ - (void)testPluginPickVideoDeviceFront { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + [plugin setImagePickerControllerOverrides:@[ controller ]]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; - XCTAssertEqual([plugin getImagePickerController].cameraDevice, - UIImagePickerControllerCameraDeviceFront); + XCTAssertEqual(controller.cameraDevice, UIImagePickerControllerCameraDeviceFront); +} + +- (void)testPickMultiImageShouldUseUIImagePickerControllerOnPreiOS14 { + if (@available(iOS 14, *)) { + return; + } + + id mockUIImagePicker = OCMClassMock([UIImagePickerController class]); + id photoLibrary = OCMClassMock([PHPhotoLibrary class]); + OCMStub(ClassMethod([photoLibrary authorizationStatus])) + .andReturn(PHAuthorizationStatusAuthorized); + + FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new]; + [plugin setImagePickerControllerOverrides:@[ mockUIImagePicker ]]; + FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickMultiImage" + arguments:@{ + @"maxWidth" : @(100), + @"maxHeight" : @(200), + @"imageQuality" : @(50), + }]; + + [plugin handleMethodCall:call + result:^(id _Nullable r){ + }]; + + OCMVerify(times(1), + [mockUIImagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]); } #pragma mark - Test camera devices, no op on simulators @@ -156,15 +190,18 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickImage" arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + plugin.imagePickerControllerOverrides = @[ controller ]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; plugin.result = ^(id result) { }; + // To ensure the flow does not crash by multiple cancel call - [plugin imagePickerControllerDidCancel:[plugin getImagePickerController]]; - [plugin imagePickerControllerDidCancel:[plugin getImagePickerController]]; + [plugin imagePickerControllerDidCancel:controller]; + [plugin imagePickerControllerDidCancel:controller]; } #pragma mark - Test video duration @@ -174,10 +211,12 @@ - (void)testPickingVideoWithDuration { FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"pickVideo" arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}]; + UIImagePickerController *controller = [[UIImagePickerController alloc] init]; + [plugin setImagePickerControllerOverrides:@[ controller ]]; [plugin handleMethodCall:call result:^(id _Nullable r){ }]; - XCTAssertEqual([plugin getImagePickerController].videoMaximumDuration, 95); + XCTAssertEqual(controller.videoMaximumDuration, 95); } - (void)testViewController { diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h index ffd23cd3df6a..c88db0bad72f 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h @@ -8,7 +8,6 @@ @interface FLTImagePickerPlugin : NSObject // For testing only. -- (UIImagePickerController *)getImagePickerController; - (UIViewController *)viewControllerWithWindow:(UIWindow *)window; @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 1301398fb0c1..cc841d6db447 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -31,12 +31,31 @@ @interface FLTImagePickerPlugin () +/** + * The maximum amount of images that are allowed to be picked. + */ @property(assign, nonatomic) int maxImagesAllowed; +/** + * The arguments that are passed in from the Flutter method call. + */ @property(copy, nonatomic) NSDictionary *arguments; +/** + * The PHPickerViewController instance used to pick multiple + * images. + */ @property(strong, nonatomic) PHPickerViewController *pickerViewController API_AVAILABLE(ios(14)); +/** + * The UIImagePickerController instances that will be used when a new + * controller would normally be created. Each call to + * createImagePickerController will remove the current first element from + * the array. + */ +@property(strong, nonatomic) + NSMutableArray *imagePickerControllerOverrides; + @end static const int SOURCE_CAMERA = 0; @@ -44,9 +63,7 @@ @interface FLTImagePickerPlugin () *)registrar { FlutterMethodChannel *channel = @@ -56,8 +73,19 @@ + (void)registerWithRegistrar:(NSObject *)registrar { [registrar addMethodCallDelegate:instance channel:channel]; } -- (UIImagePickerController *)getImagePickerController { - return _imagePickerController; +- (UIImagePickerController *)createImagePickerController { + if ([self.imagePickerControllerOverrides count] > 0) { + UIImagePickerController *controller = [self.imagePickerControllerOverrides firstObject]; + [self.imagePickerControllerOverrides removeObjectAtIndex:0]; + return controller; + } + + return [[UIImagePickerController alloc] init]; +} + +- (void)setImagePickerControllerOverrides: + (NSArray *)imagePickerControllers { + _imagePickerControllerOverrides = [imagePickerControllers mutableCopy]; } - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { @@ -88,7 +116,7 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window { * @param arguments that should be used to get cameraDevice value. */ - (UIImagePickerControllerCameraDevice)getCameraDeviceFromArguments:(NSDictionary *)arguments { - NSInteger cameraDevice = [[arguments objectForKey:@"cameraDevice"] intValue]; + NSInteger cameraDevice = [arguments[@"cameraDevice"] intValue]; return (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront : UIImagePickerControllerCameraDeviceRear; } @@ -108,22 +136,20 @@ - (void)pickImageWithPHPicker:(int)maxImagesAllowed API_AVAILABLE(ios(14)) { [self checkPhotoAuthorizationForAccessLevel]; } -- (void)pickImageWithUIImagePicker { - _imagePickerController = [[UIImagePickerController alloc] init]; - _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; - _imagePickerController.delegate = self; - _imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; - - int imageSource = [[_arguments objectForKey:@"source"] intValue]; +- (void)launchUIImagePickerWithSource:(int)imageSource { + UIImagePickerController *imagePickerController = [self createImagePickerController]; + imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; + imagePickerController.delegate = self; + imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ]; self.maxImagesAllowed = 1; switch (imageSource) { case SOURCE_CAMERA: - [self checkCameraAuthorization]; + [self checkCameraAuthorizationWithImagePicker:imagePickerController]; break; case SOURCE_GALLERY: - [self checkPhotoAuthorization]; + [self checkPhotoAuthorizationWithImagePicker:imagePickerController]; break; default: self.result([FlutterError errorWithCode:@"invalid_source" @@ -141,10 +167,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result self.result = nil; } + self.result = result; + _arguments = call.arguments; + if ([@"pickImage" isEqualToString:call.method]) { - self.result = result; - _arguments = call.arguments; - int imageSource = [[_arguments objectForKey:@"source"] intValue]; + int imageSource = [call.arguments[@"source"] intValue]; if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker if (@available(iOS 14, *)) { @@ -152,44 +179,39 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result [self pickImageWithPHPicker:1]; } else { // UIImagePicker is used - [self pickImageWithUIImagePicker]; + [self launchUIImagePickerWithSource:imageSource]; } } else { - [self pickImageWithUIImagePicker]; + [self launchUIImagePickerWithSource:imageSource]; } } else if ([@"pickMultiImage" isEqualToString:call.method]) { if (@available(iOS 14, *)) { - self.result = result; - _arguments = call.arguments; [self pickImageWithPHPicker:0]; } else { - [self pickImageWithUIImagePicker]; + [self launchUIImagePickerWithSource:SOURCE_GALLERY]; } } else if ([@"pickVideo" isEqualToString:call.method]) { - _imagePickerController = [[UIImagePickerController alloc] init]; - _imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; - _imagePickerController.delegate = self; - _imagePickerController.mediaTypes = @[ + UIImagePickerController *imagePickerController = [self createImagePickerController]; + imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext; + imagePickerController.delegate = self; + imagePickerController.mediaTypes = @[ (NSString *)kUTTypeMovie, (NSString *)kUTTypeAVIMovie, (NSString *)kUTTypeVideo, (NSString *)kUTTypeMPEG4 ]; - _imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; - - self.result = result; - _arguments = call.arguments; + imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh; - int imageSource = [[_arguments objectForKey:@"source"] intValue]; - if ([[_arguments objectForKey:@"maxDuration"] isKindOfClass:[NSNumber class]]) { - NSTimeInterval max = [[_arguments objectForKey:@"maxDuration"] doubleValue]; - _imagePickerController.videoMaximumDuration = max; + int imageSource = [call.arguments[@"source"] intValue]; + if ([call.arguments[@"maxDuration"] isKindOfClass:[NSNumber class]]) { + NSTimeInterval max = [call.arguments[@"maxDuration"] doubleValue]; + imagePickerController.videoMaximumDuration = max; } switch (imageSource) { case SOURCE_CAMERA: - [self checkCameraAuthorization]; + [self checkCameraAuthorizationWithImagePicker:imagePickerController]; break; case SOURCE_GALLERY: - [self checkPhotoAuthorization]; + [self checkPhotoAuthorizationWithImagePicker:imagePickerController]; break; default: result([FlutterError errorWithCode:@"invalid_source" @@ -202,9 +224,9 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result } } -- (void)showCamera { +- (void)showCameraWithImagePicker:(UIImagePickerController *)imagePickerController { @synchronized(self) { - if (_imagePickerController.beingPresented) { + if (imagePickerController.beingPresented) { return; } } @@ -212,9 +234,9 @@ - (void)showCamera { // Camera is not available on simulators if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] && [UIImagePickerController isCameraDeviceAvailable:device]) { - _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; - _imagePickerController.cameraDevice = device; - [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController + imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; + imagePickerController.cameraDevice = device; + [[self viewControllerWithWindow:nil] presentViewController:imagePickerController animated:YES completion:nil]; } else { @@ -238,19 +260,19 @@ - (void)showCamera { } } -- (void)checkCameraAuthorization { +- (void)checkCameraAuthorizationWithImagePicker:(UIImagePickerController *)imagePickerController { AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; switch (status) { case AVAuthorizationStatusAuthorized: - [self showCamera]; + [self showCameraWithImagePicker:imagePickerController]; break; case AVAuthorizationStatusNotDetermined: { [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { - [self showCamera]; + [self showCameraWithImagePicker:imagePickerController]; } else { [self errorNoCameraAccess:AVAuthorizationStatusDenied]; } @@ -266,14 +288,14 @@ - (void)checkCameraAuthorization { } } -- (void)checkPhotoAuthorization { +- (void)checkPhotoAuthorizationWithImagePicker:(UIImagePickerController *)imagePickerController { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; switch (status) { case PHAuthorizationStatusNotDetermined: { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusAuthorized) { - [self showPhotoLibrary:UIImagePickerClassType]; + [self showPhotoLibraryWithImagePicker:imagePickerController]; } else { [self errorNoPhotoAccess:status]; } @@ -282,7 +304,7 @@ - (void)checkPhotoAuthorization { break; } case PHAuthorizationStatusAuthorized: - [self showPhotoLibrary:UIImagePickerClassType]; + [self showPhotoLibraryWithImagePicker:imagePickerController]; break; case PHAuthorizationStatusDenied: case PHAuthorizationStatusRestricted: @@ -301,9 +323,13 @@ - (void)checkPhotoAuthorizationForAccessLevel API_AVAILABLE(ios(14)) { handler:^(PHAuthorizationStatus status) { dispatch_async(dispatch_get_main_queue(), ^{ if (status == PHAuthorizationStatusAuthorized) { - [self showPhotoLibrary:PHPickerClassType]; + [self + showPhotoLibraryWithPHPicker:self-> + _pickerViewController]; } else if (status == PHAuthorizationStatusLimited) { - [self showPhotoLibrary:PHPickerClassType]; + [self + showPhotoLibraryWithPHPicker:self-> + _pickerViewController]; } else { [self errorNoPhotoAccess:status]; } @@ -313,7 +339,7 @@ - (void)checkPhotoAuthorizationForAccessLevel API_AVAILABLE(ios(14)) { } case PHAuthorizationStatusAuthorized: case PHAuthorizationStatusLimited: - [self showPhotoLibrary:PHPickerClassType]; + [self showPhotoLibraryWithPHPicker:_pickerViewController]; break; case PHAuthorizationStatusDenied: case PHAuthorizationStatusRestricted: @@ -355,21 +381,18 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status { } } -- (void)showPhotoLibrary:(ImagePickerClassType)imagePickerClassType { - // No need to check if SourceType is available. It always is. - switch (imagePickerClassType) { - case PHPickerClassType: - [[self viewControllerWithWindow:nil] presentViewController:_pickerViewController - animated:YES - completion:nil]; - break; - case UIImagePickerClassType: - _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; - [[self viewControllerWithWindow:nil] presentViewController:_imagePickerController - animated:YES - completion:nil]; - break; - } +- (void)showPhotoLibraryWithPHPicker:(PHPickerViewController *)pickerViewController + API_AVAILABLE(ios(14)) { + [[self viewControllerWithWindow:nil] presentViewController:pickerViewController + animated:YES + completion:nil]; +} + +- (void)showPhotoLibraryWithImagePicker:(UIImagePickerController *)imagePickerController { + imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + [[self viewControllerWithWindow:nil] presentViewController:imagePickerController + animated:YES + completion:nil]; } - (NSNumber *)getDesiredImageQuality:(NSNumber *)imageQuality { @@ -449,8 +472,8 @@ - (NSMutableArray *)createNSMutableArrayWithSize:(NSUInteger)size { - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { - NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL]; - [_imagePickerController dismissViewControllerAnimated:YES completion:nil]; + NSURL *videoURL = info[UIImagePickerControllerMediaURL]; + [picker dismissViewControllerAnimated:YES completion:nil]; // The method dismissViewControllerAnimated does not immediately prevent // further didFinishPickingMediaWithInfo invocations. A nil check is necessary // to prevent below code to be unwantly executed multiple times and cause a @@ -484,9 +507,9 @@ - (void)imagePickerController:(UIImagePickerController *)picker self.result = nil; _arguments = nil; } else { - UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage]; + UIImage *image = info[UIImagePickerControllerEditedImage]; if (image == nil) { - image = [info objectForKey:UIImagePickerControllerOriginalImage]; + image = info[UIImagePickerControllerOriginalImage]; } NSNumber *maxWidth = GetNullableValueForKey(_arguments, @"maxWidth"); NSNumber *maxHeight = GetNullableValueForKey(_arguments, @"maxHeight"); @@ -523,7 +546,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { - [_imagePickerController dismissViewControllerAnimated:YES completion:nil]; + [picker dismissViewControllerAnimated:YES completion:nil]; if (!self.result) { return; } diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin_Test.h b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin_Test.h index 94eca425eb5e..5442f7d089c6 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin_Test.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin_Test.h @@ -40,4 +40,15 @@ */ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker; +/** + * Sets UIImagePickerController instances that will be used when a new + * controller would normally be created. Each call to + * createImagePickerController will remove the current first element from + * the array. + * + * Should be used for testing purposes only. + */ +- (void)setImagePickerControllerOverrides: + (NSArray *)imagePickerControllers; + @end diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 7142d8238b30..43143f1dbd57 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. repository: https://github.com/flutter/plugins/tree/main/packages/image_picker/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.4+7 +version: 0.8.4+8 environment: sdk: ">=2.14.0 <3.0.0"