[image_picker] add requestFullMetadata for iOS (optional permissions) - iOS changes (#5713)
diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md
index c145013..33e2b61 100644
--- a/packages/image_picker/image_picker_ios/CHANGELOG.md
+++ b/packages/image_picker/image_picker_ios/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 0.8.6
+* Adds `requestFullMetadata` option to `pickImage`, so images on iOS can be picked without `Photo Library Usage` permission.
* Updates minimum Flutter version to 2.10.
## 0.8.5+6
diff --git a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
index 04d4911..320582b 100644
--- a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
+++ b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/ImagePickerPluginTests.m
@@ -46,7 +46,7 @@
.andReturn(AVAuthorizationStatusAuthorized);
// Run test
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
@@ -54,6 +54,7 @@
camera:FLTSourceCameraRear]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
+ fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];
@@ -78,7 +79,7 @@
.andReturn(AVAuthorizationStatusAuthorized);
// Run test
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
@@ -86,6 +87,7 @@
camera:FLTSourceCameraFront]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
+ fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];
@@ -110,7 +112,7 @@
.andReturn(AVAuthorizationStatusAuthorized);
// Run test
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
@@ -142,7 +144,7 @@
.andReturn(AVAuthorizationStatusAuthorized);
// Run test
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
@@ -165,11 +167,12 @@
OCMStub(ClassMethod([photoLibrary authorizationStatus]))
.andReturn(PHAuthorizationStatusAuthorized);
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
[plugin setImagePickerControllerOverrides:@[ mockUIImagePicker ]];
[plugin pickMultiImageWithMaxSize:[FLTMaxSize makeWithWidth:@(100) height:@(200)]
quality:@(50)
+ fullMetadata:@(YES)
completion:^(NSArray<NSString *> *_Nullable result,
FlutterError *_Nullable error){
}];
@@ -177,13 +180,48 @@
[mockUIImagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]);
}
+- (void)testPickImageWithoutFullMetadata API_AVAILABLE(ios(11)) {
+ id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
+ id photoLibrary = OCMClassMock([PHPhotoLibrary class]);
+
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ [plugin setImagePickerControllerOverrides:@[ mockUIImagePicker ]];
+
+ [plugin pickImageWithSource:[FLTSourceSpecification makeWithType:FLTSourceTypeGallery
+ camera:FLTSourceCameraFront]
+ maxSize:[[FLTMaxSize alloc] init]
+ quality:nil
+ fullMetadata:@(NO)
+ completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
+ }];
+
+ OCMVerify(times(0), [photoLibrary authorizationStatus]);
+}
+
+- (void)testPickMultiImageWithoutFullMetadata API_AVAILABLE(ios(11)) {
+ id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
+ id photoLibrary = OCMClassMock([PHPhotoLibrary class]);
+
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
+ [plugin setImagePickerControllerOverrides:@[ mockUIImagePicker ]];
+
+ [plugin pickMultiImageWithMaxSize:[[FLTMaxSize alloc] init]
+ quality:nil
+ fullMetadata:@(NO)
+ completion:^(NSArray<NSString *> *_Nullable result,
+ FlutterError *_Nullable error){
+ }];
+
+ OCMVerify(times(0), [photoLibrary authorizationStatus]);
+}
+
#pragma mark - Test camera devices, no op on simulators
- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
return;
}
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
plugin.imagePickerControllerOverrides = @[ controller ];
@@ -191,6 +229,7 @@
camera:FLTSourceCameraRear]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
+ fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];
@@ -202,7 +241,7 @@
#pragma mark - Test video duration
- (void)testPickingVideoWithDuration {
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
UIImagePickerController *controller = [[UIImagePickerController alloc] init];
[plugin setImagePickerControllerOverrides:@[ controller ]];
@@ -223,12 +262,12 @@
UIViewController *vc2 = [UIViewController new];
vc1.mockPresented = vc2;
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
XCTAssertEqual([plugin viewControllerWithWindow:window], vc2);
}
- (void)testPluginMultiImagePathHasNullItem {
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
dispatch_semaphore_t resultSemaphore = dispatch_semaphore_create(0);
__block FlutterError *pickImageResult = nil;
@@ -245,7 +284,7 @@
}
- (void)testPluginMultiImagePathHasItem {
- FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *plugin = [[FLTImagePickerPlugin alloc] init];
NSArray *pathList = @[ @"test" ];
dispatch_semaphore_t resultSemaphore = dispatch_semaphore_create(0);
diff --git a/packages/image_picker/image_picker_ios/example/pubspec.yaml b/packages/image_picker/image_picker_ios/example/pubspec.yaml
index 24b3af0..bca58a5 100755
--- a/packages/image_picker/image_picker_ios/example/pubspec.yaml
+++ b/packages/image_picker/image_picker_ios/example/pubspec.yaml
@@ -16,7 +16,7 @@
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
- image_picker_platform_interface: ^2.3.0
+ image_picker_platform_interface: ^2.6.1
video_player: ^2.1.4
dev_dependencies:
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
index 18d4ad2..fa1bb66 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
+++ b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin.m
@@ -56,7 +56,7 @@
@implementation FLTImagePickerPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
- FLTImagePickerPlugin *instance = [FLTImagePickerPlugin new];
+ FLTImagePickerPlugin *instance = [[FLTImagePickerPlugin alloc] init];
FLTImagePickerApiSetup(registrar.messenger, instance);
}
@@ -119,7 +119,11 @@
_pickerViewController.presentationController.delegate = self;
self.callContext = context;
- [self checkPhotoAuthorizationForAccessLevel];
+ if (context.requestFullMetadata) {
+ [self checkPhotoAuthorizationForAccessLevel];
+ } else {
+ [self showPhotoLibraryWithPHPicker:_pickerViewController];
+ }
}
- (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source
@@ -136,7 +140,16 @@
camera:[self cameraDeviceForSource:source]];
break;
case FLTSourceTypeGallery:
- [self checkPhotoAuthorizationWithImagePicker:imagePickerController];
+ if (@available(iOS 11, *)) {
+ if (context.requestFullMetadata) {
+ [self checkPhotoAuthorizationWithImagePicker:imagePickerController];
+ } else {
+ [self showPhotoLibraryWithImagePicker:imagePickerController];
+ }
+ } else {
+ // Prior to iOS 11, accessing gallery requires authorization
+ [self checkPhotoAuthorizationWithImagePicker:imagePickerController];
+ }
break;
default:
[self sendCallResultWithError:[FlutterError errorWithCode:@"invalid_source"
@@ -151,6 +164,7 @@
- (void)pickImageWithSource:(nonnull FLTSourceSpecification *)source
maxSize:(nonnull FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
+ fullMetadata:(NSNumber *)fullMetadata
completion:
(nonnull void (^)(NSString *_Nullable, FlutterError *_Nullable))completion {
[self cancelInProgressCall];
@@ -166,6 +180,7 @@
context.maxSize = maxSize;
context.imageQuality = imageQuality;
context.maxImageCount = 1;
+ context.requestFullMetadata = [fullMetadata boolValue];
if (source.type == FLTSourceTypeGallery) { // Capture is not possible with PHPicker
if (@available(iOS 14, *)) {
@@ -180,12 +195,14 @@
- (void)pickMultiImageWithMaxSize:(nonnull FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
+ fullMetadata:(NSNumber *)fullMetadata
completion:(nonnull void (^)(NSArray<NSString *> *_Nullable,
FlutterError *_Nullable))completion {
FLTImagePickerMethodCallContext *context =
[[FLTImagePickerMethodCallContext alloc] initWithResult:completion];
context.maxSize = maxSize;
context.imageQuality = imageQuality;
+ context.requestFullMetadata = [fullMetadata boolValue];
if (@available(iOS 14, *)) {
[self launchPHPickerWithContext:context];
@@ -554,7 +571,11 @@
NSNumber *imageQuality = self.callContext.imageQuality;
NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality];
- PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info];
+ PHAsset *originalAsset;
+ if (_callContext.requestFullMetadata) {
+ // Full metadata are available only in PHAsset, which requires gallery permission.
+ originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info];
+ }
if (maxWidth != nil || maxHeight != nil) {
image = [FLTImagePickerImageUtil scaledImage:image
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin_Test.h b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin_Test.h
index 64c2045..d73a54d 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin_Test.h
+++ b/packages/image_picker/image_picker_ios/ios/Classes/FLTImagePickerPlugin_Test.h
@@ -46,6 +46,9 @@
/** Maximum number of images to select. 0 indicates no maximum. */
@property(nonatomic, assign) int maxImageCount;
+/** Whether the image should be picked with full metadata (requires gallery permissions) */
+@property(nonatomic, assign) BOOL requestFullMetadata;
+
@end
#pragma mark -
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
index 310165f..c87bda5 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
+++ b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.h
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Autogenerated from Pigeon (v3.0.2), do not edit directly.
+// Autogenerated from Pigeon (v3.0.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import <Foundation/Foundation.h>
@protocol FlutterBinaryMessenger;
@@ -45,9 +45,11 @@
- (void)pickImageWithSource:(FLTSourceSpecification *)source
maxSize:(FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
+ fullMetadata:(NSNumber *)requestFullMetadata
completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion;
- (void)pickMultiImageWithMaxSize:(FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
+ fullMetadata:(NSNumber *)requestFullMetadata
completion:(void (^)(NSArray<NSString *> *_Nullable,
FlutterError *_Nullable))completion;
- (void)pickVideoWithSource:(FLTSourceSpecification *)source
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
index 6c91c0a..71a5b51 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
+++ b/packages/image_picker/image_picker_ios/ios/Classes/messages.g.m
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Autogenerated from Pigeon (v3.0.2), do not edit directly.
+// Autogenerated from Pigeon (v3.0.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
#import "messages.g.h"
#import <Flutter/Flutter.h>
@@ -144,18 +144,21 @@
binaryMessenger:binaryMessenger
codec:FLTImagePickerApiGetCodec()];
if (api) {
- NSCAssert([api respondsToSelector:@selector(pickImageWithSource:maxSize:quality:completion:)],
+ NSCAssert([api respondsToSelector:@selector
+ (pickImageWithSource:maxSize:quality:fullMetadata:completion:)],
@"FLTImagePickerApi api (%@) doesn't respond to "
- @"@selector(pickImageWithSource:maxSize:quality:completion:)",
+ @"@selector(pickImageWithSource:maxSize:quality:fullMetadata:completion:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
FLTSourceSpecification *arg_source = GetNullableObjectAtIndex(args, 0);
FLTMaxSize *arg_maxSize = GetNullableObjectAtIndex(args, 1);
NSNumber *arg_imageQuality = GetNullableObjectAtIndex(args, 2);
+ NSNumber *arg_requestFullMetadata = GetNullableObjectAtIndex(args, 3);
[api pickImageWithSource:arg_source
maxSize:arg_maxSize
quality:arg_imageQuality
+ fullMetadata:arg_requestFullMetadata
completion:^(NSString *_Nullable output, FlutterError *_Nullable error) {
callback(wrapResult(output, error));
}];
@@ -170,16 +173,19 @@
binaryMessenger:binaryMessenger
codec:FLTImagePickerApiGetCodec()];
if (api) {
- NSCAssert([api respondsToSelector:@selector(pickMultiImageWithMaxSize:quality:completion:)],
+ NSCAssert([api respondsToSelector:@selector
+ (pickMultiImageWithMaxSize:quality:fullMetadata:completion:)],
@"FLTImagePickerApi api (%@) doesn't respond to "
- @"@selector(pickMultiImageWithMaxSize:quality:completion:)",
+ @"@selector(pickMultiImageWithMaxSize:quality:fullMetadata:completion:)",
api);
[channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
NSArray *args = message;
FLTMaxSize *arg_maxSize = GetNullableObjectAtIndex(args, 0);
NSNumber *arg_imageQuality = GetNullableObjectAtIndex(args, 1);
+ NSNumber *arg_requestFullMetadata = GetNullableObjectAtIndex(args, 2);
[api pickMultiImageWithMaxSize:arg_maxSize
quality:arg_imageQuality
+ fullMetadata:arg_requestFullMetadata
completion:^(NSArray<NSString *> *_Nullable output,
FlutterError *_Nullable error) {
callback(wrapResult(output, error));
diff --git a/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart b/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
index 3d1413c..fbc356f 100644
--- a/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
+++ b/packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
@@ -1,7 +1,6 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
import 'dart:async';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
@@ -51,24 +50,42 @@
}) async {
final String? path = await _pickImageAsPath(
source: source,
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: imageQuality,
- preferredCameraDevice: preferredCameraDevice,
+ options: ImagePickerOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: imageQuality,
+ preferredCameraDevice: preferredCameraDevice,
+ ),
);
return path != null ? PickedFile(path) : null;
}
@override
+ Future<XFile?> getImageFromSource({
+ required ImageSource source,
+ ImagePickerOptions options = const ImagePickerOptions(),
+ }) async {
+ final String? path = await _pickImageAsPath(
+ source: source,
+ options: options,
+ );
+ return path != null ? XFile(path) : null;
+ }
+
+ @override
Future<List<PickedFile>?> pickMultiImage({
double? maxWidth,
double? maxHeight,
int? imageQuality,
}) async {
final List<dynamic>? paths = await _pickMultiImageAsPath(
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: imageQuality,
+ options: MultiImagePickerOptions(
+ imageOptions: ImageOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: imageQuality,
+ ),
+ ),
);
if (paths == null) {
return null;
@@ -77,20 +94,33 @@
return paths.map((dynamic path) => PickedFile(path as String)).toList();
}
- Future<List<String>?> _pickMultiImageAsPath({
- double? maxWidth,
- double? maxHeight,
- int? imageQuality,
+ @override
+ Future<List<XFile>> getMultiImageWithOptions({
+ MultiImagePickerOptions options = const MultiImagePickerOptions(),
}) async {
+ final List<String>? paths = await _pickMultiImageAsPath(options: options);
+ if (paths == null) {
+ return <XFile>[];
+ }
+
+ return paths.map((String path) => XFile(path)).toList();
+ }
+
+ Future<List<String>?> _pickMultiImageAsPath({
+ MultiImagePickerOptions options = const MultiImagePickerOptions(),
+ }) async {
+ final int? imageQuality = options.imageOptions.imageQuality;
if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
throw ArgumentError.value(
imageQuality, 'imageQuality', 'must be between 0 and 100');
}
+ final double? maxWidth = options.imageOptions.maxWidth;
if (maxWidth != null && maxWidth < 0) {
throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
}
+ final double? maxHeight = options.imageOptions.maxHeight;
if (maxHeight != null && maxHeight < 0) {
throw ArgumentError.value(maxHeight, 'maxHeight', 'cannot be negative');
}
@@ -98,22 +128,24 @@
// TODO(stuartmorgan): Remove the cast once Pigeon supports non-nullable
// generics, https://github.com/flutter/flutter/issues/97848
return (await _hostApi.pickMultiImage(
- MaxSize(width: maxWidth, height: maxHeight), imageQuality))
+ MaxSize(width: maxWidth, height: maxHeight),
+ imageQuality,
+ options.imageOptions.requestFullMetadata))
?.cast<String>();
}
Future<String?> _pickImageAsPath({
required ImageSource source,
- double? maxWidth,
- double? maxHeight,
- int? imageQuality,
- CameraDevice preferredCameraDevice = CameraDevice.rear,
+ ImagePickerOptions options = const ImagePickerOptions(),
}) {
+ final int? imageQuality = options.imageQuality;
if (imageQuality != null && (imageQuality < 0 || imageQuality > 100)) {
throw ArgumentError.value(
imageQuality, 'imageQuality', 'must be between 0 and 100');
}
+ final double? maxHeight = options.maxHeight;
+ final double? maxWidth = options.maxWidth;
if (maxWidth != null && maxWidth < 0) {
throw ArgumentError.value(maxWidth, 'maxWidth', 'cannot be negative');
}
@@ -124,10 +156,12 @@
return _hostApi.pickImage(
SourceSpecification(
- type: _convertSource(source),
- camera: _convertCamera(preferredCameraDevice)),
+ type: _convertSource(source),
+ camera: _convertCamera(options.preferredCameraDevice),
+ ),
MaxSize(width: maxWidth, height: maxHeight),
imageQuality,
+ options.requestFullMetadata,
);
}
@@ -167,10 +201,12 @@
}) async {
final String? path = await _pickImageAsPath(
source: source,
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: imageQuality,
- preferredCameraDevice: preferredCameraDevice,
+ options: ImagePickerOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: imageQuality,
+ preferredCameraDevice: preferredCameraDevice,
+ ),
);
return path != null ? XFile(path) : null;
}
@@ -182,9 +218,13 @@
int? imageQuality,
}) async {
final List<String>? paths = await _pickMultiImageAsPath(
- maxWidth: maxWidth,
- maxHeight: maxHeight,
- imageQuality: imageQuality,
+ options: MultiImagePickerOptions(
+ imageOptions: ImageOptions(
+ maxWidth: maxWidth,
+ maxHeight: maxHeight,
+ imageQuality: imageQuality,
+ ),
+ ),
);
if (paths == null) {
return null;
diff --git a/packages/image_picker/image_picker_ios/lib/src/messages.g.dart b/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
index 0c5859e..5f8768b 100644
--- a/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
+++ b/packages/image_picker/image_picker_ios/lib/src/messages.g.dart
@@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Autogenerated from Pigeon (v3.0.2), do not edit directly.
+// Autogenerated from Pigeon (v3.0.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name
// @dart = 2.12
@@ -115,13 +115,16 @@
static const MessageCodec<Object?> codec = _ImagePickerApiCodec();
Future<String?> pickImage(SourceSpecification arg_source, MaxSize arg_maxSize,
- int? arg_imageQuality) async {
+ int? arg_imageQuality, bool arg_requestFullMetadata) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ImagePickerApi.pickImage', codec,
binaryMessenger: _binaryMessenger);
- final Map<Object?, Object?>? replyMap =
- await channel.send(<Object?>[arg_source, arg_maxSize, arg_imageQuality])
- as Map<Object?, Object?>?;
+ final Map<Object?, Object?>? replyMap = await channel.send(<Object?>[
+ arg_source,
+ arg_maxSize,
+ arg_imageQuality,
+ arg_requestFullMetadata
+ ]) as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
@@ -140,14 +143,14 @@
}
}
- Future<List<String?>?> pickMultiImage(
- MaxSize arg_maxSize, int? arg_imageQuality) async {
+ Future<List<String?>?> pickMultiImage(MaxSize arg_maxSize,
+ int? arg_imageQuality, bool arg_requestFullMetadata) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.ImagePickerApi.pickMultiImage', codec,
binaryMessenger: _binaryMessenger);
- final Map<Object?, Object?>? replyMap =
- await channel.send(<Object?>[arg_maxSize, arg_imageQuality])
- as Map<Object?, Object?>?;
+ final Map<Object?, Object?>? replyMap = await channel.send(
+ <Object?>[arg_maxSize, arg_imageQuality, arg_requestFullMetadata])
+ as Map<Object?, Object?>?;
if (replyMap == null) {
throw PlatformException(
code: 'channel-error',
diff --git a/packages/image_picker/image_picker_ios/pigeons/messages.dart b/packages/image_picker/image_picker_ios/pigeons/messages.dart
index 94ac034..dd8a0f0 100644
--- a/packages/image_picker/image_picker_ios/pigeons/messages.dart
+++ b/packages/image_picker/image_picker_ios/pigeons/messages.dart
@@ -35,12 +35,13 @@
@HostApi(dartHostTestHandler: 'TestHostImagePickerApi')
abstract class ImagePickerApi {
@async
- @ObjCSelector('pickImageWithSource:maxSize:quality:')
- String? pickImage(
- SourceSpecification source, MaxSize maxSize, int? imageQuality);
+ @ObjCSelector('pickImageWithSource:maxSize:quality:fullMetadata:')
+ String? pickImage(SourceSpecification source, MaxSize maxSize,
+ int? imageQuality, bool requestFullMetadata);
@async
- @ObjCSelector('pickMultiImageWithMaxSize:quality:')
- List<String>? pickMultiImage(MaxSize maxSize, int? imageQuality);
+ @ObjCSelector('pickMultiImageWithMaxSize:quality:fullMetadata:')
+ List<String>? pickMultiImage(
+ MaxSize maxSize, int? imageQuality, bool requestFullMetadata);
@async
@ObjCSelector('pickVideoWithSource:maxDuration:')
String? pickVideo(SourceSpecification source, int? maxDurationSeconds);
diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml
index dc69513..5c30bf9 100755
--- a/packages/image_picker/image_picker_ios/pubspec.yaml
+++ b/packages/image_picker/image_picker_ios/pubspec.yaml
@@ -2,7 +2,7 @@
description: iOS implementation of the image_picker plugin.
repository: https://github.com/flutter/plugins/tree/main/packages/image_picker/image_picker_ios
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.5+6
+version: 0.8.6
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -19,7 +19,7 @@
dependencies:
flutter:
sdk: flutter
- image_picker_platform_interface: ^2.3.0
+ image_picker_platform_interface: ^2.6.1
dev_dependencies:
flutter_test:
diff --git a/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart b/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
index 09517f1..b200257 100644
--- a/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
+++ b/packages/image_picker/image_picker_ios/test/image_picker_ios_test.dart
@@ -39,7 +39,11 @@
@override
Future<String?> pickImage(
- SourceSpecification source, MaxSize maxSize, int? imageQuality) async {
+ SourceSpecification source,
+ MaxSize maxSize,
+ int? imageQuality,
+ bool requestFullMetadata,
+ ) async {
// Flatten arguments for easy comparison.
calls.add(_LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': source.type,
@@ -47,17 +51,22 @@
'maxWidth': maxSize.width,
'maxHeight': maxSize.height,
'imageQuality': imageQuality,
+ 'requestFullMetadata': requestFullMetadata,
}));
return returnValue as String?;
}
@override
Future<List<String?>?> pickMultiImage(
- MaxSize maxSize, int? imageQuality) async {
+ MaxSize maxSize,
+ int? imageQuality,
+ bool requestFullMetadata,
+ ) async {
calls.add(_LoggedMethodCall('pickMultiImage', arguments: <String, dynamic>{
'maxWidth': maxSize.width,
'maxHeight': maxSize.height,
'imageQuality': imageQuality,
+ 'requestFullMetadata': requestFullMetadata,
}));
return returnValue as List<String?>?;
}
@@ -103,14 +112,16 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.gallery,
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -156,49 +167,56 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -257,6 +275,7 @@
'maxHeight': null,
'imageQuality': null,
'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -276,6 +295,7 @@
'maxHeight': null,
'imageQuality': null,
'cameraDevice': SourceCamera.front,
+ 'requestFullMetadata': true,
}),
],
);
@@ -295,6 +315,7 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
],
);
@@ -335,42 +356,49 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
],
);
@@ -524,14 +552,16 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.gallery,
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -577,49 +607,56 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': null,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
'source': SourceType.camera,
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': 70,
- 'cameraDevice': SourceCamera.rear
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -678,6 +715,7 @@
'maxHeight': null,
'imageQuality': null,
'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
}),
],
);
@@ -697,6 +735,7 @@
'maxHeight': null,
'imageQuality': null,
'cameraDevice': SourceCamera.front,
+ 'requestFullMetadata': true,
}),
],
);
@@ -716,6 +755,7 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
],
);
@@ -756,42 +796,49 @@
'maxWidth': null,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': null,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': null,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': null,
'maxHeight': 10.0,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
const _LoggedMethodCall('pickMultiImage',
arguments: <String, dynamic>{
'maxWidth': 10.0,
'maxHeight': 20.0,
'imageQuality': 70,
+ 'requestFullMetadata': true,
}),
],
);
@@ -934,4 +981,478 @@
);
});
});
+
+ group('#getImageFromSource', () {
+ test('passes the image source argument correctly', () async {
+ await picker.getImageFromSource(source: ImageSource.camera);
+ await picker.getImageFromSource(source: ImageSource.gallery);
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.gallery,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('passes the width and height arguments correctly', () async {
+ await picker.getImageFromSource(source: ImageSource.camera);
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(maxWidth: 10.0),
+ );
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(maxHeight: 10.0),
+ );
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ ),
+ );
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(
+ maxWidth: 10.0,
+ imageQuality: 70,
+ ),
+ );
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(
+ maxHeight: 10.0,
+ imageQuality: 70,
+ ),
+ );
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ ),
+ );
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': 70,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': 70,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': 70,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('does not accept a invalid imageQuality argument', () {
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.gallery,
+ options: const ImagePickerOptions(imageQuality: -1),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.gallery,
+ options: const ImagePickerOptions(imageQuality: 101),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(imageQuality: -1),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(imageQuality: 101),
+ ),
+ throwsArgumentError,
+ );
+ });
+
+ test('does not accept a negative width or height argument', () {
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(maxWidth: -1.0),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getImageFromSource(
+ source: ImageSource.camera,
+ options: const ImagePickerOptions(maxHeight: -1.0),
+ ),
+ throwsArgumentError,
+ );
+ });
+
+ test('handles a null image path response gracefully', () async {
+ log.returnValue = null;
+
+ expect(
+ await picker.getImageFromSource(source: ImageSource.gallery), isNull);
+ expect(
+ await picker.getImageFromSource(source: ImageSource.camera), isNull);
+ });
+
+ test('camera position defaults to back', () async {
+ await picker.getImageFromSource(source: ImageSource.camera);
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('camera position can set to front', () async {
+ await picker.getImageFromSource(
+ source: ImageSource.camera,
+ options:
+ const ImagePickerOptions(preferredCameraDevice: CameraDevice.front),
+ );
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.camera,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.front,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('Request full metadata argument defaults to true', () async {
+ await picker.getImageFromSource(source: ImageSource.gallery);
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.gallery,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('passes the request full metadata argument correctly', () async {
+ await picker.getImageFromSource(
+ source: ImageSource.gallery,
+ options: const ImagePickerOptions(requestFullMetadata: false),
+ );
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickImage', arguments: <String, dynamic>{
+ 'source': SourceType.gallery,
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'cameraDevice': SourceCamera.rear,
+ 'requestFullMetadata': false,
+ }),
+ ],
+ );
+ });
+ });
+
+ group('#getMultiImageWithOptions', () {
+ test('calls the method correctly', () async {
+ log.returnValue = <String>['0', '1'];
+ await picker.getMultiImageWithOptions();
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('passes the width and height arguments correctly', () async {
+ log.returnValue = <String>['0', '1'];
+ await picker.getMultiImageWithOptions();
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxWidth: 10.0),
+ ),
+ );
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxHeight: 10.0),
+ ),
+ );
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxWidth: 10.0, maxHeight: 20.0),
+ ),
+ );
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxWidth: 10.0, imageQuality: 70),
+ ),
+ );
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxHeight: 10.0, imageQuality: 70),
+ ),
+ );
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(
+ maxWidth: 10.0,
+ maxHeight: 20.0,
+ imageQuality: 70,
+ ),
+ ),
+ );
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': null,
+ 'imageQuality': 70,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': 10.0,
+ 'imageQuality': 70,
+ 'requestFullMetadata': true,
+ }),
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': 10.0,
+ 'maxHeight': 20.0,
+ 'imageQuality': 70,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('does not accept a negative width or height argument', () {
+ log.returnValue = <String>['0', '1'];
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxWidth: -1.0),
+ ),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(maxHeight: -1.0),
+ ),
+ ),
+ throwsArgumentError,
+ );
+ });
+
+ test('does not accept a invalid imageQuality argument', () {
+ log.returnValue = <String>['0', '1'];
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(imageQuality: -1),
+ ),
+ ),
+ throwsArgumentError,
+ );
+
+ expect(
+ () => picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(imageQuality: 101),
+ ),
+ ),
+ throwsArgumentError,
+ );
+ });
+
+ test('handles a null image path response gracefully', () async {
+ log.returnValue = null;
+
+ expect(await picker.getMultiImageWithOptions(), isEmpty);
+ });
+
+ test('Request full metadata argument defaults to true', () async {
+ log.returnValue = <String>['0', '1'];
+ await picker.getMultiImageWithOptions();
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'requestFullMetadata': true,
+ }),
+ ],
+ );
+ });
+
+ test('Passes the request full metadata argument correctly', () async {
+ log.returnValue = <String>['0', '1'];
+ await picker.getMultiImageWithOptions(
+ options: const MultiImagePickerOptions(
+ imageOptions: ImageOptions(requestFullMetadata: false),
+ ),
+ );
+
+ expect(
+ log.calls,
+ <_LoggedMethodCall>[
+ const _LoggedMethodCall('pickMultiImage',
+ arguments: <String, dynamic>{
+ 'maxWidth': null,
+ 'maxHeight': null,
+ 'imageQuality': null,
+ 'requestFullMetadata': false,
+ }),
+ ],
+ );
+ });
+ });
}
diff --git a/packages/image_picker/image_picker_ios/test/test_api.dart b/packages/image_picker/image_picker_ios/test/test_api.dart
index 8b20f21..1e44f60 100644
--- a/packages/image_picker/image_picker_ios/test/test_api.dart
+++ b/packages/image_picker/image_picker_ios/test/test_api.dart
@@ -1,12 +1,13 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Autogenerated from Pigeon (v3.0.2), do not edit directly.
+// Autogenerated from Pigeon (v3.0.3), do not edit directly.
// See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis
// ignore_for_file: avoid_relative_lib_imports
// @dart = 2.12
import 'dart:typed_data' show Uint8List, Int32List, Int64List, Float64List;
+
// TODO(a14n): remove this import once Flutter 3.1 or later reaches stable (including flutter/flutter#106316)
// ignore: unnecessary_import
import 'package:flutter/foundation.dart' show WriteBuffer, ReadBuffer;
@@ -49,9 +50,10 @@
abstract class TestHostImagePickerApi {
static const MessageCodec<Object?> codec = _TestHostImagePickerApiCodec();
- Future<String?> pickImage(
- SourceSpecification source, MaxSize maxSize, int? imageQuality);
- Future<List<String?>?> pickMultiImage(MaxSize maxSize, int? imageQuality);
+ Future<String?> pickImage(SourceSpecification source, MaxSize maxSize,
+ int? imageQuality, bool requestFullMetadata);
+ Future<List<String?>?> pickMultiImage(
+ MaxSize maxSize, int? imageQuality, bool requestFullMetadata);
Future<String?> pickVideo(
SourceSpecification source, int? maxDurationSeconds);
static void setup(TestHostImagePickerApi? api,
@@ -75,8 +77,11 @@
assert(arg_maxSize != null,
'Argument for dev.flutter.pigeon.ImagePickerApi.pickImage was null, expected non-null MaxSize.');
final int? arg_imageQuality = (args[2] as int?);
- final String? output =
- await api.pickImage(arg_source!, arg_maxSize!, arg_imageQuality);
+ final bool? arg_requestFullMetadata = (args[3] as bool?);
+ assert(arg_requestFullMetadata != null,
+ 'Argument for dev.flutter.pigeon.ImagePickerApi.pickImage was null, expected non-null bool.');
+ final String? output = await api.pickImage(arg_source!, arg_maxSize!,
+ arg_imageQuality, arg_requestFullMetadata!);
return <Object?, Object?>{'result': output};
});
}
@@ -96,8 +101,11 @@
assert(arg_maxSize != null,
'Argument for dev.flutter.pigeon.ImagePickerApi.pickMultiImage was null, expected non-null MaxSize.');
final int? arg_imageQuality = (args[1] as int?);
- final List<String?>? output =
- await api.pickMultiImage(arg_maxSize!, arg_imageQuality);
+ final bool? arg_requestFullMetadata = (args[2] as bool?);
+ assert(arg_requestFullMetadata != null,
+ 'Argument for dev.flutter.pigeon.ImagePickerApi.pickMultiImage was null, expected non-null bool.');
+ final List<String?>? output = await api.pickMultiImage(
+ arg_maxSize!, arg_imageQuality, arg_requestFullMetadata!);
return <Object?, Object?>{'result': output};
});
}