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

Commit 4fbffad

Browse files
author
罗煌略
committed
change: fixed image picker
1 parent 23de0c6 commit 4fbffad

File tree

5 files changed

+99
-21
lines changed

5 files changed

+99
-21
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2019 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#import <UIKit/UIKit.h>
6+
7+
NS_ASSUME_NONNULL_BEGIN
8+
9+
@class FLTImagePickerPlugin;
10+
11+
@interface FLTImagePickerController : UIImagePickerController
12+
13+
- (instancetype)initWithPlugin:(FLTImagePickerPlugin *)plugin;
14+
15+
@end
16+
17+
NS_ASSUME_NONNULL_END
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2019 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#import "FLTImagePickerController.h"
6+
#import "FLTImagePickerPlugin.h"
7+
8+
@interface FLTImagePickerController ()
9+
10+
@property(weak, nonatomic) FLTImagePickerPlugin *plugin;
11+
12+
@end
13+
14+
@implementation FLTImagePickerController
15+
16+
- (instancetype)initWithPlugin:(FLTImagePickerPlugin *)plugin {
17+
self = [super init];
18+
if (self) {
19+
self.plugin = plugin;
20+
self.modalPresentationStyle = UIModalPresentationPopover;
21+
self.delegate = plugin;
22+
}
23+
return self;
24+
}
25+
26+
- (void)viewWillDisappear:(BOOL)animated {
27+
[super viewWillDisappear:animated];
28+
// When image picker is dismissed by the swiping down gesture,
29+
// the delegate method [imagePickerControllerDidCancel:] will not be called,
30+
// which results the method channel not getting responses.
31+
// This [viewWillDisappear:] will handle such cases.
32+
[self.plugin handleImagePickerControllerDismissed];
33+
}
34+
35+
@end

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
#import <Flutter/Flutter.h>
66

7-
@interface FLTImagePickerPlugin : NSObject <FlutterPlugin>
7+
@interface FLTImagePickerPlugin
8+
: NSObject <FlutterPlugin, UINavigationControllerDelegate, UIImagePickerControllerDelegate>
9+
10+
- (void)handleImagePickerControllerDismissed;
811

912
// For testing only.
1013
- (UIImagePickerController *)getImagePickerController;

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

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
#import <Photos/Photos.h>
1010
#import <UIKit/UIKit.h>
1111

12+
#import "FLTImagePickerController.h"
1213
#import "FLTImagePickerImageUtil.h"
1314
#import "FLTImagePickerMetaDataUtil.h"
1415
#import "FLTImagePickerPhotoAssetUtil.h"
1516

16-
@interface FLTImagePickerPlugin () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
17+
@interface FLTImagePickerPlugin ()
1718

1819
@property(copy, nonatomic) FlutterResult result;
1920

@@ -24,7 +25,7 @@ @interface FLTImagePickerPlugin () <UINavigationControllerDelegate, UIImagePicke
2425

2526
@implementation FLTImagePickerPlugin {
2627
NSDictionary *_arguments;
27-
UIImagePickerController *_imagePickerController;
28+
FLTImagePickerController *_imagePickerController;
2829
UIImagePickerControllerCameraDevice _device;
2930
}
3031

@@ -64,12 +65,12 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
6465
message:@"Cancelled by a second request"
6566
details:nil]);
6667
self.result = nil;
68+
return;
6769
}
6870

71+
_imagePickerController = [[FLTImagePickerController alloc] initWithPlugin:self];
72+
6973
if ([@"pickImage" isEqualToString:call.method]) {
70-
_imagePickerController = [[UIImagePickerController alloc] init];
71-
_imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
72-
_imagePickerController.delegate = self;
7374
_imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ];
7475

7576
self.result = result;
@@ -95,9 +96,6 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
9596
break;
9697
}
9798
} else if ([@"pickVideo" isEqualToString:call.method]) {
98-
_imagePickerController = [[UIImagePickerController alloc] init];
99-
_imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
100-
_imagePickerController.delegate = self;
10199
_imagePickerController.mediaTypes = @[
102100
(NSString *)kUTTypeMovie, (NSString *)kUTTypeAVIMovie, (NSString *)kUTTypeVideo,
103101
(NSString *)kUTTypeMPEG4
@@ -142,9 +140,7 @@ - (void)showCamera {
142140
[UIImagePickerController isCameraDeviceAvailable:_device]) {
143141
_imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
144142
_imagePickerController.cameraDevice = _device;
145-
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
146-
animated:YES
147-
completion:nil];
143+
[self PresentImagePickerController];
148144
} else {
149145
[[[UIAlertView alloc] initWithTitle:@"Error"
150146
message:@"Camera not available."
@@ -249,20 +245,20 @@ - (void)errorNoPhotoAccess:(PHAuthorizationStatus)status {
249245
- (void)showPhotoLibrary {
250246
// No need to check if SourceType is available. It always is.
251247
_imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
248+
[self PresentImagePickerController];
249+
}
250+
251+
- (void)PresentImagePickerController {
252252
[[self viewControllerWithWindow:nil] presentViewController:_imagePickerController
253253
animated:YES
254254
completion:nil];
255255
}
256256

257-
- (void)imagePickerController:(UIImagePickerController *)picker
258-
didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {
257+
- (void)FinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *_Nonnull)info
258+
completion:(void (^)(void))completion {
259259
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
260-
[_imagePickerController dismissViewControllerAnimated:YES completion:nil];
261-
// The method dismissViewControllerAnimated does not immediately prevent
262-
// further didFinishPickingMediaWithInfo invocations. A nil check is necessary
263-
// to prevent below code to be unwantly executed multiple times and cause a
264-
// crash.
265260
if (!self.result) {
261+
completion();
266262
return;
267263
}
268264
if (videoURL != nil) {
@@ -281,6 +277,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker
281277
message:@"Could not cache the video file."
282278
details:nil]);
283279
self.result = nil;
280+
completion();
284281
return;
285282
}
286283
}
@@ -290,6 +287,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker
290287
self.result(videoURL.path);
291288
self.result = nil;
292289
_arguments = nil;
290+
completion();
293291
} else {
294292
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
295293
if (image == nil) {
@@ -316,6 +314,7 @@ - (void)imagePickerController:(UIImagePickerController *)picker
316314
if (!originalAsset) {
317315
// Image picked without an original asset (e.g. User took a photo directly)
318316
[self saveImageWithPickerInfo:info image:image imageQuality:imageQuality];
317+
completion();
319318
} else {
320319
__weak typeof(self) weakSelf = self;
321320
[[PHImageManager defaultManager]
@@ -329,19 +328,43 @@ - (void)imagePickerController:(UIImagePickerController *)picker
329328
maxWidth:maxWidth
330329
maxHeight:maxHeight
331330
imageQuality:imageQuality];
331+
completion();
332332
}];
333333
}
334334
}
335335
}
336336

337+
- (void)imagePickerController:(UIImagePickerController *)picker
338+
didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info {
339+
[self FinishPickingMediaWithInfo:info
340+
completion:^{
341+
dispatch_async(dispatch_get_main_queue(), ^{
342+
// Dismissing the image picker before cleaning up leads to a race
343+
// condition, where the result is not cleaned before the next image
344+
// picker is brought up. So we dismiss the `_imagePickerController` as
345+
// the last step.
346+
[self->_imagePickerController dismissViewControllerAnimated:YES
347+
completion:nil];
348+
});
349+
}];
350+
}
351+
337352
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
338-
[_imagePickerController dismissViewControllerAnimated:YES completion:nil];
353+
[self handleImagePickerControllerDismissed];
354+
}
355+
356+
- (void)handleImagePickerControllerDismissed {
339357
if (!self.result) {
358+
[_imagePickerController dismissViewControllerAnimated:YES completion:nil];
340359
return;
341360
}
342361
self.result(nil);
343362
self.result = nil;
344363
_arguments = nil;
364+
// Dismissing the image picker before cleaning up leads to a race condition,
365+
// where the result is not cleaned before the next image picker is brought up.
366+
// So we dismiss the `_imagePickerController` as the last step.
367+
[_imagePickerController dismissViewControllerAnimated:YES completion:nil];
345368
}
346369

347370
- (void)saveImageWithOriginalImageData:(NSData *)originalImageData

packages/image_picker/image_picker/ios/image_picker.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Downloaded by pub (not CocoaPods).
1414
s.author = { 'Flutter Dev Team' => '[email protected]' }
1515
s.source = { :http => 'https://github.com/flutter/plugins/tree/master/packages/image_picker' }
1616
s.documentation_url = 'https://pub.dev/packages/image_picker'
17-
s.source_files = 'Classes/**/*'
17+
s.source_files = 'packages/image_picker/image_picker/ios/Classes/**/*'
1818
s.public_header_files = 'Classes/**/*.h'
1919
s.dependency 'Flutter'
2020
s.platform = :ios, '8.0'

0 commit comments

Comments
 (0)