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

Commit ff53b70

Browse files
[image_picker] fixes for iOS which doesn't present camera/albums with more complex navigation (#2755)
1 parent 90462df commit ff53b70

File tree

6 files changed

+65
-32
lines changed

6 files changed

+65
-32
lines changed

AUTHORS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,5 @@ Giancarlo Rocha <giancarloiff@gmail.com>
5656
Ryo Miyake <ryo@miyake.id>
5757
Théo Champion <contact.theochampion@gmail.com>
5858
Kazuki Yamaguchi <y.kazuki0614n@gmail.com>
59-
Eitan Schwartz <eshvartz@gmail.com>
59+
Eitan Schwartz <eshvartz@gmail.com>
60+
Chris Rutkowski <chrisrutkowski89@gmail.com>

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.6.7+2
2+
3+
* iOS: Fixes unpresentable album/image picker if window's root view controller is already presenting other view controller.
4+
15
## 0.6.7+1
26

37
* Add web support to the example app.

packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
@interface FLTImagePickerPlugin : NSObject <FlutterPlugin>
88

99
// For testing only.
10-
- (instancetype)initWithViewController:(UIViewController *)viewController;
1110
- (UIImagePickerController *)getImagePickerController;
11+
- (UIViewController *)viewControllerWithWindow:(UIWindow *)window;
1212

1313
@end

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,33 +25,39 @@ @interface FLTImagePickerPlugin () <UINavigationControllerDelegate, UIImagePicke
2525
@implementation FLTImagePickerPlugin {
2626
NSDictionary *_arguments;
2727
UIImagePickerController *_imagePickerController;
28-
UIViewController *_viewController;
2928
UIImagePickerControllerCameraDevice _device;
3029
}
3130

3231
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
3332
FlutterMethodChannel *channel =
3433
[FlutterMethodChannel methodChannelWithName:@"plugins.flutter.io/image_picker"
3534
binaryMessenger:[registrar messenger]];
36-
UIViewController *viewController =
37-
[UIApplication sharedApplication].delegate.window.rootViewController;
38-
FLTImagePickerPlugin *instance =
39-
[[FLTImagePickerPlugin alloc] initWithViewController:viewController];
35+
FLTImagePickerPlugin *instance = [FLTImagePickerPlugin new];
4036
[registrar addMethodCallDelegate:instance channel:channel];
4137
}
4238

43-
- (instancetype)initWithViewController:(UIViewController *)viewController {
44-
self = [super init];
45-
if (self) {
46-
_viewController = viewController;
47-
}
48-
return self;
49-
}
50-
5139
- (UIImagePickerController *)getImagePickerController {
5240
return _imagePickerController;
5341
}
5442

43+
- (UIViewController *)viewControllerWithWindow:(UIWindow *)window {
44+
UIWindow *windowToUse = window;
45+
if (windowToUse == nil) {
46+
for (UIWindow *window in [UIApplication sharedApplication].windows) {
47+
if (window.isKeyWindow) {
48+
windowToUse = window;
49+
break;
50+
}
51+
}
52+
}
53+
54+
UIViewController *topController = windowToUse.rootViewController;
55+
while (topController.presentedViewController) {
56+
topController = topController.presentedViewController;
57+
}
58+
return topController;
59+
}
60+
5561
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
5662
if (self.result) {
5763
self.result([FlutterError errorWithCode:@"multiple_request"
@@ -136,7 +142,9 @@ - (void)showCamera {
136142
[UIImagePickerController isCameraDeviceAvailable:_device]) {
137143
_imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
138144
_imagePickerController.cameraDevice = _device;
139-
[_viewController presentViewController:_imagePickerController animated:YES completion:nil];
145+
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
146+
animated:YES
147+
completion:nil];
140148
} else {
141149
[[[UIAlertView alloc] initWithTitle:@"Error"
142150
message:@"Camera not available."
@@ -241,7 +249,9 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status {
241249
- (void)showPhotoLibrary {
242250
// No need to check if SourceType is available. It always is.
243251
_imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
244-
[_viewController presentViewController:_imagePickerController animated:YES completion:nil];
252+
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
253+
animated:YES
254+
completion:nil];
245255
}
246256

247257
- (void)imagePickerController:(UIImagePickerController *)picker

packages/image_picker/image_picker/ios/Tests/ImagePickerPluginTests.m

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@
77
@import image_picker;
88
@import XCTest;
99

10+
@interface MockViewController : UIViewController
11+
@property(nonatomic, retain) UIViewController *mockPresented;
12+
@end
13+
14+
@implementation MockViewController
15+
@synthesize mockPresented;
16+
17+
- (UIViewController *)presentedViewController {
18+
return mockPresented;
19+
}
20+
21+
@end
22+
1023
@interface FLTImagePickerPlugin (Test)
1124
@property(copy, nonatomic) FlutterResult result;
1225
- (void)handleSavedPath:(NSString *)path;
@@ -23,8 +36,7 @@ - (void)testPluginPickImageDeviceBack {
2336
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
2437
return;
2538
}
26-
FLTImagePickerPlugin *plugin =
27-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
39+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
2840
FlutterMethodCall *call =
2941
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
3042
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
@@ -39,8 +51,7 @@ - (void)testPluginPickImageDeviceFront {
3951
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
4052
return;
4153
}
42-
FLTImagePickerPlugin *plugin =
43-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
54+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
4455
FlutterMethodCall *call =
4556
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
4657
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
@@ -55,8 +66,7 @@ - (void)testPluginPickVideoDeviceBack {
5566
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
5667
return;
5768
}
58-
FLTImagePickerPlugin *plugin =
59-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
69+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
6070
FlutterMethodCall *call =
6171
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
6272
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
@@ -71,8 +81,7 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes {
7181
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
7282
return;
7383
}
74-
FLTImagePickerPlugin *plugin =
75-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
84+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
7685
FlutterMethodCall *call =
7786
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
7887
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
@@ -90,8 +99,7 @@ - (void)testPluginPickVideoDeviceFront {
9099
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
91100
return;
92101
}
93-
FLTImagePickerPlugin *plugin =
94-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
102+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
95103
FlutterMethodCall *call =
96104
[FlutterMethodCall methodCallWithMethodName:@"pickVideo"
97105
arguments:@{@"source" : @(0), @"cameraDevice" : @(1)}];
@@ -104,8 +112,7 @@ - (void)testPluginPickVideoDeviceFront {
104112

105113
#pragma mark - Test video duration
106114
- (void)testPickingVideoWithDuration {
107-
FLTImagePickerPlugin *plugin =
108-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
115+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
109116
FlutterMethodCall *call = [FlutterMethodCall
110117
methodCallWithMethodName:@"pickVideo"
111118
arguments:@{@"source" : @(0), @"cameraDevice" : @(0), @"maxDuration" : @95}];
@@ -116,8 +123,7 @@ - (void)testPickingVideoWithDuration {
116123
}
117124

118125
- (void)testPluginPickImageSelectMultipleTimes {
119-
FLTImagePickerPlugin *plugin =
120-
[[FLTImagePickerPlugin alloc] initWithViewController:[UIViewController new]];
126+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
121127
FlutterMethodCall *call =
122128
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
123129
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
@@ -131,4 +137,16 @@ - (void)testPluginPickImageSelectMultipleTimes {
131137
[plugin handleSavedPath:@"test"];
132138
}
133139

140+
- (void)testViewController {
141+
UIWindow *window = [UIWindow new];
142+
MockViewController *vc1 = [MockViewController new];
143+
window.rootViewController = vc1;
144+
145+
UIViewController *vc2 = [UIViewController new];
146+
vc1.mockPresented = vc2;
147+
148+
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
149+
XCTAssertEqual([plugin viewControllerWithWindow:window], vc2);
150+
}
151+
134152
@end

packages/image_picker/image_picker/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: image_picker
22
description: Flutter plugin for selecting images from the Android and iOS image
33
library, and taking new pictures with the camera.
44
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker
5-
version: 0.6.7+1
5+
version: 0.6.7+2
66

77
flutter:
88
plugin:

0 commit comments

Comments
 (0)