Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit cf80430

Browse files
authored
[image_picker] Image picker fix camera device (#3898)
1 parent fbb4b3a commit cf80430

File tree

6 files changed

+123
-42
lines changed

6 files changed

+123
-42
lines changed

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
## 0.8.1+4
2+
3+
* Fixes an issue where `preferredCameraDevice` option is not working for `getVideo` method.
4+
* Refactor unit tests that were device-only before.
5+
16
## 0.8.1+3
27

38
* Fix image picker causing a crash when the cache directory is deleted.
49

510
## 0.8.1+2
6-
711
* Update the example app to support the multi-image feature.
812

913
## 0.8.1+1

packages/image_picker/image_picker/example/ios/Podfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ target 'Runner' do
3131
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
3232

3333
target 'RunnerTests' do
34+
platform :ios, '9.0'
3435
inherit! :search_paths
36+
# Pods for testing
37+
pod 'OCMock', '~> 3.8.1'
3538
end
3639
target 'RunnerUITests' do
3740
inherit! :search_paths

packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@
877877
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
878878
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
879879
CODE_SIGN_STYLE = Automatic;
880-
DEVELOPMENT_TEAM = NHAKRD9N7D;
880+
DEVELOPMENT_TEAM = "";
881881
GCC_C_LANGUAGE_STANDARD = gnu11;
882882
INFOPLIST_FILE = RunnerUITestiOS14/Info.plist;
883883
IPHONEOS_DEPLOYMENT_TARGET = 14.1;

packages/image_picker/image_picker/example/ios/RunnerTests/ImagePickerPluginTests.m

Lines changed: 87 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
@import image_picker;
88
@import XCTest;
9+
#import <OCMock/OCMock.h>
910

1011
@interface MockViewController : UIViewController
1112
@property(nonatomic, retain) UIViewController *mockPresented;
@@ -27,90 +28,152 @@ - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
2728
@end
2829

2930
@interface ImagePickerPluginTests : XCTestCase
31+
@property(readonly, nonatomic) id mockUIImagePicker;
32+
@property(readonly, nonatomic) id mockAVCaptureDevice;
3033
@end
3134

3235
@implementation ImagePickerPluginTests
3336

34-
#pragma mark - Test camera devices, no op on simulators
37+
- (void)setUp {
38+
_mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
39+
_mockAVCaptureDevice = OCMClassMock([AVCaptureDevice class]);
40+
}
41+
3542
- (void)testPluginPickImageDeviceBack {
36-
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
37-
return;
38-
}
43+
// UIImagePickerControllerSourceTypeCamera is supported
44+
OCMStub(ClassMethod(
45+
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
46+
.andReturn(YES);
47+
48+
// UIImagePickerControllerCameraDeviceRear is supported
49+
OCMStub(ClassMethod(
50+
[_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]))
51+
.andReturn(YES);
52+
53+
// AVAuthorizationStatusAuthorized is supported
54+
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
55+
.andReturn(AVAuthorizationStatusAuthorized);
56+
57+
// Run test
3958
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
4059
FlutterMethodCall *call =
4160
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
4261
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
4362
[plugin handleMethodCall:call
4463
result:^(id _Nullable r){
4564
}];
65+
4666
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
4767
UIImagePickerControllerCameraDeviceRear);
4868
}
4969

5070
- (void)testPluginPickImageDeviceFront {
51-
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
52-
return;
53-
}
71+
// UIImagePickerControllerSourceTypeCamera is supported
72+
OCMStub(ClassMethod(
73+
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
74+
.andReturn(YES);
75+
76+
// UIImagePickerControllerCameraDeviceFront is supported
77+
OCMStub(ClassMethod([_mockUIImagePicker
78+
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]))
79+
.andReturn(YES);
80+
81+
// AVAuthorizationStatusAuthorized is supported
82+
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
83+
.andReturn(AVAuthorizationStatusAuthorized);
84+
85+
// Run test
5486
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
5587
FlutterMethodCall *call =
5688
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
5789
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
5890
[plugin handleMethodCall:call
5991
result:^(id _Nullable r){
6092
}];
93+
6194
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
6295
UIImagePickerControllerCameraDeviceFront);
6396
}
6497

6598
- (void)testPluginPickVideoDeviceBack {
66-
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
67-
return;
68-
}
99+
// UIImagePickerControllerSourceTypeCamera is supported
100+
OCMStub(ClassMethod(
101+
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
102+
.andReturn(YES);
103+
104+
// UIImagePickerControllerCameraDeviceRear is supported
105+
OCMStub(ClassMethod(
106+
[_mockUIImagePicker isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]))
107+
.andReturn(YES);
108+
109+
// AVAuthorizationStatusAuthorized is supported
110+
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
111+
.andReturn(AVAuthorizationStatusAuthorized);
112+
113+
// Run test
69114
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
70115
FlutterMethodCall *call =
71116
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
72117
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
73118
[plugin handleMethodCall:call
74119
result:^(id _Nullable r){
75120
}];
121+
76122
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
77123
UIImagePickerControllerCameraDeviceRear);
78124
}
79125

80-
- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
81-
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
82-
return;
83-
}
126+
- (void)testPluginPickVideoDeviceFront {
127+
// UIImagePickerControllerSourceTypeCamera is supported
128+
OCMStub(ClassMethod(
129+
[_mockUIImagePicker isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]))
130+
.andReturn(YES);
131+
132+
// UIImagePickerControllerCameraDeviceFront is supported
133+
OCMStub(ClassMethod([_mockUIImagePicker
134+
isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]))
135+
.andReturn(YES);
136+
137+
// AVAuthorizationStatusAuthorized is supported
138+
OCMStub([_mockAVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
139+
.andReturn(AVAuthorizationStatusAuthorized);
140+
141+
// Run test
84142
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
85143
FlutterMethodCall *call =
86-
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
144+
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
87145
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
88146
[plugin handleMethodCall:call
89147
result:^(id _Nullable r){
90148
}];
91-
plugin.result = ^(id result) {
92149

93-
};
94-
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
95-
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
150+
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
151+
UIImagePickerControllerCameraDeviceFront);
96152
}
97153

98-
- (void)testPluginPickVideoDeviceFront {
99-
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
154+
#pragma mark - Test camera devices, no op on simulators
155+
156+
- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
157+
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
100158
return;
101159
}
102160
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
103161
FlutterMethodCall *call =
104-
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
162+
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
105163
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
106164
[plugin handleMethodCall:call
107165
result:^(id _Nullable r){
108166
}];
109-
XCTAssertEqual([plugin getImagePickerController].cameraDevice,
110-
UIImagePickerControllerCameraDeviceFront);
167+
plugin.result = ^(id result) {
168+
169+
};
170+
// To ensure the flow does not crash by multiple cancel call
171+
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
172+
[plugin imagePickerControllerDidCancel:[plugin getImagePickerController]];
111173
}
112174

113175
#pragma mark - Test video duration
176+
114177
- (void)testPickingVideoWithDuration {
115178
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
116179
FlutterMethodCall *call = [FlutterMethodCall

packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ @interface FLTImagePickerPlugin () <UINavigationControllerDelegate,
3737

3838
@implementation FLTImagePickerPlugin {
3939
UIImagePickerController *_imagePickerController;
40-
UIImagePickerControllerCameraDevice _device;
4140
}
4241

4342
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
@@ -70,6 +69,21 @@ - (UIViewController *)viewControllerWithWindow:(UIWindow *)window {
7069
return topController;
7170
}
7271

72+
/**
73+
* Returns the UIImagePickerControllerCameraDevice to use given [arguments].
74+
*
75+
* If the cameraDevice value that is fetched from arguments is 1 then returns
76+
* UIImagePickerControllerCameraDeviceFront. If the cameraDevice value that is fetched
77+
* from arguments is 0 then returns UIImagePickerControllerCameraDeviceRear.
78+
*
79+
* @param arguments that should be used to get cameraDevice value.
80+
*/
81+
- (UIImagePickerControllerCameraDevice)getCameraDeviceFromArguments:(NSDictionary *)arguments {
82+
NSInteger cameraDevice = [[arguments objectForKey:@"cameraDevice"] intValue];
83+
return (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront
84+
: UIImagePickerControllerCameraDeviceRear;
85+
}
86+
7387
- (void)pickImageWithPHPicker:(int)maxImagesAllowed API_AVAILABLE(ios(14)) {
7488
PHPickerConfiguration *config =
7589
[[PHPickerConfiguration alloc] initWithPhotoLibrary:PHPhotoLibrary.sharedPhotoLibrary];
@@ -95,13 +109,9 @@ - (void)pickImageWithUIImagePicker {
95109
self.maxImagesAllowed = 1;
96110

97111
switch (imageSource) {
98-
case SOURCE_CAMERA: {
99-
NSInteger cameraDevice = [[_arguments objectForKey:@"cameraDevice"] intValue];
100-
_device = (cameraDevice == 1) ? UIImagePickerControllerCameraDeviceFront
101-
: UIImagePickerControllerCameraDeviceRear;
112+
case SOURCE_CAMERA:
102113
[self checkCameraAuthorization];
103114
break;
104-
}
105115
case SOURCE_GALLERY:
106116
[self checkPhotoAuthorization];
107117
break;
@@ -188,11 +198,12 @@ - (void)showCamera {
188198
return;
189199
}
190200
}
201+
UIImagePickerControllerCameraDevice device = [self getCameraDeviceFromArguments:_arguments];
191202
// Camera is not available on simulators
192203
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] &&
193-
[UIImagePickerController isCameraDeviceAvailable:_device]) {
204+
[UIImagePickerController isCameraDeviceAvailable:device]) {
194205
_imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
195-
_imagePickerController.cameraDevice = _device;
206+
_imagePickerController.cameraDevice = device;
196207
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
197208
animated:YES
198209
completion:nil];
@@ -406,8 +417,8 @@ - (void)picker:(PHPickerViewController *)picker
406417
* The difference with initWithCapacity is that initWithCapacity still gives an empty array making
407418
* it impossible to add objects on an index larger than the size.
408419
*
409-
* @param @size The length of the required array
410-
* @return @NSMutableArray An array of a specified size
420+
* @param size The length of the required array
421+
* @return NSMutableArray An array of a specified size
411422
*/
412423
- (NSMutableArray *)createNSMutableArrayWithSize:(NSUInteger)size {
413424
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:size];
@@ -528,14 +539,14 @@ - (void)saveImageWithPickerInfo:(NSDictionary *)info
528539
* Applies NSMutableArray on the FLutterResult.
529540
*
530541
* NSString must be returned by FlutterResult if the single image
531-
* mode is active. It is checked by @c maxImagesAllowed and
532-
* returns the first object of the @c pathlist.
542+
* mode is active. It is checked by maxImagesAllowed and
543+
* returns the first object of the pathlist.
533544
*
534545
* NSMutableArray must be returned by FlutterResult if the multi-image
535-
* mode is active. After the @c pathlist count is checked then it returns
536-
* the @c pathlist.
546+
* mode is active. After the pathlist count is checked then it returns
547+
* the pathlist.
537548
*
538-
* @param @pathList that should be applied to FlutterResult.
549+
* @param pathList that should be applied to FlutterResult.
539550
*/
540551
- (void)handleSavedPathList:(NSArray *)pathList {
541552
if (!self.result) {

packages/image_picker/image_picker/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image
33
library, and taking new pictures with the camera.
44
repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
55
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
6-
version: 0.8.1+3
6+
version: 0.8.1+4
77

88
environment:
99
sdk: ">=2.12.0 <3.0.0"

0 commit comments

Comments
 (0)