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

Commit 024cc35

Browse files
committed
[image_picker] add forceFullMetadata for iOS
1 parent 9b614ea commit 024cc35

File tree

7 files changed

+153
-74
lines changed

7 files changed

+153
-74
lines changed

packages/image_picker/image_picker/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.8.4
2+
3+
* Add `forceFullMetadata` option to `pickImage`.
4+
* To keep this non-breaking `forceFullMetadata` defaults to `true`, so the plugin tries
5+
to get the full image metadata which may require extra permission requests on certain platforms.
6+
* If `forceFullMetadata` is set to `false`, the plugin fetches the image in a way that reduces
7+
permission requests from the platform (e.g on iOS the plugin won’t ask for the `NSPhotoLibraryUsageDescription` permission).
8+
19
## 0.8.3+3
210

311
* Fix pickImage not returning a value on iOS when dismissing PHPicker sheet by swiping.

packages/image_picker/image_picker/example/lib/main.dart

Lines changed: 65 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ class _MyHomePageState extends State<MyHomePage> {
8888
source: source, maxDuration: const Duration(seconds: 10));
8989
await _playVideo(file);
9090
} else if (isMultiImage) {
91-
await _displayPickImageDialog(context!,
92-
(double? maxWidth, double? maxHeight, int? quality) async {
91+
await _displayPickImageDialog(context!, (double? maxWidth,
92+
double? maxHeight, int? quality, bool forceFullMetadata) async {
9393
try {
9494
final pickedFileList = await _picker.pickMultiImage(
9595
maxWidth: maxWidth,
@@ -106,14 +106,15 @@ class _MyHomePageState extends State<MyHomePage> {
106106
}
107107
});
108108
} else {
109-
await _displayPickImageDialog(context!,
110-
(double? maxWidth, double? maxHeight, int? quality) async {
109+
await _displayPickImageDialog(context!, (double? maxWidth,
110+
double? maxHeight, int? quality, bool forceFullMetadata) async {
111111
try {
112112
final pickedFile = await _picker.pickImage(
113113
source: source,
114114
maxWidth: maxWidth,
115115
maxHeight: maxHeight,
116116
imageQuality: quality,
117+
forceFullMetadata: forceFullMetadata,
117118
);
118119
setState(() {
119120
_imageFile = pickedFile;
@@ -358,60 +359,74 @@ class _MyHomePageState extends State<MyHomePage> {
358359
return showDialog(
359360
context: context,
360361
builder: (context) {
361-
return AlertDialog(
362-
title: Text('Add optional parameters'),
363-
content: Column(
364-
children: <Widget>[
365-
TextField(
366-
controller: maxWidthController,
367-
keyboardType: TextInputType.numberWithOptions(decimal: true),
368-
decoration:
369-
InputDecoration(hintText: "Enter maxWidth if desired"),
370-
),
371-
TextField(
372-
controller: maxHeightController,
373-
keyboardType: TextInputType.numberWithOptions(decimal: true),
374-
decoration:
375-
InputDecoration(hintText: "Enter maxHeight if desired"),
376-
),
377-
TextField(
378-
controller: qualityController,
379-
keyboardType: TextInputType.number,
380-
decoration:
381-
InputDecoration(hintText: "Enter quality if desired"),
382-
),
383-
],
384-
),
385-
actions: <Widget>[
386-
TextButton(
387-
child: const Text('CANCEL'),
388-
onPressed: () {
389-
Navigator.of(context).pop();
390-
},
362+
bool forceFullMetadata = true;
363+
return StatefulBuilder(builder: (context, setState) {
364+
return AlertDialog(
365+
title: Text('Add optional parameters'),
366+
content: Column(
367+
children: <Widget>[
368+
TextField(
369+
controller: maxWidthController,
370+
keyboardType:
371+
TextInputType.numberWithOptions(decimal: true),
372+
decoration:
373+
InputDecoration(hintText: "Enter maxWidth if desired"),
374+
),
375+
TextField(
376+
controller: maxHeightController,
377+
keyboardType:
378+
TextInputType.numberWithOptions(decimal: true),
379+
decoration:
380+
InputDecoration(hintText: "Enter maxHeight if desired"),
381+
),
382+
TextField(
383+
controller: qualityController,
384+
keyboardType: TextInputType.number,
385+
decoration:
386+
InputDecoration(hintText: "Enter quality if desired"),
387+
),
388+
CheckboxListTile(
389+
value: forceFullMetadata,
390+
onChanged: (bool? value) {
391+
setState(() {
392+
forceFullMetadata = value ?? false;
393+
});
394+
},
395+
title: Text("Force full metadata"),
396+
)
397+
],
391398
),
392-
TextButton(
393-
child: const Text('PICK'),
399+
actions: <Widget>[
400+
TextButton(
401+
child: const Text('CANCEL'),
394402
onPressed: () {
395-
double? width = maxWidthController.text.isNotEmpty
396-
? double.parse(maxWidthController.text)
397-
: null;
398-
double? height = maxHeightController.text.isNotEmpty
399-
? double.parse(maxHeightController.text)
400-
: null;
401-
int? quality = qualityController.text.isNotEmpty
402-
? int.parse(qualityController.text)
403-
: null;
404-
onPick(width, height, quality);
405403
Navigator.of(context).pop();
406-
}),
407-
],
408-
);
404+
},
405+
),
406+
TextButton(
407+
child: const Text('PICK'),
408+
onPressed: () {
409+
double? width = maxWidthController.text.isNotEmpty
410+
? double.parse(maxWidthController.text)
411+
: null;
412+
double? height = maxHeightController.text.isNotEmpty
413+
? double.parse(maxHeightController.text)
414+
: null;
415+
int? quality = qualityController.text.isNotEmpty
416+
? int.parse(qualityController.text)
417+
: null;
418+
onPick(width, height, quality, forceFullMetadata);
419+
Navigator.of(context).pop();
420+
}),
421+
],
422+
);
423+
});
409424
});
410425
}
411426
}
412427

413428
typedef void OnPickImageCallback(
414-
double? maxWidth, double? maxHeight, int? quality);
429+
double? maxWidth, double? maxHeight, int? quality, bool forceFullMetadata);
415430

416431
class AspectRatioVideo extends StatefulWidget {
417432
AspectRatioVideo(this.controller);

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

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ - (void)pickImageWithPHPicker:(int)maxImagesAllowed API_AVAILABLE(ios(14)) {
9797

9898
self.maxImagesAllowed = maxImagesAllowed;
9999

100-
[self checkPhotoAuthorizationForAccessLevel];
100+
BOOL usePhaAsset = [[_arguments objectForKey:@"forceFullMetadata"] boolValue];
101+
if (usePhaAsset) {
102+
[self checkPhotoAuthorizationForAccessLevel];
103+
return;
104+
}
105+
[self showPhotoLibrary:PHPickerClassType];
101106
}
102107

103108
- (void)pickImageWithUIImagePicker {
@@ -107,6 +112,7 @@ - (void)pickImageWithUIImagePicker {
107112
_imagePickerController.mediaTypes = @[ (NSString *)kUTTypeImage ];
108113

109114
int imageSource = [[_arguments objectForKey:@"source"] intValue];
115+
BOOL usePhaAsset = [[_arguments objectForKey:@"forceFullMetadata"] boolValue];
110116

111117
self.maxImagesAllowed = 1;
112118

@@ -115,7 +121,11 @@ - (void)pickImageWithUIImagePicker {
115121
[self checkCameraAuthorization];
116122
break;
117123
case SOURCE_GALLERY:
118-
[self checkPhotoAuthorization];
124+
if (usePhaAsset) {
125+
[self checkPhotoAuthorization];
126+
break;
127+
}
128+
[self showPhotoLibrary:UIImagePickerClassType];
119129
break;
120130
default:
121131
self.result([FlutterError errorWithCode:@"invalid_source"
@@ -132,13 +142,14 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
132142
details:nil]);
133143
self.result = nil;
134144
}
145+
BOOL usePhaAsset = [[_arguments objectForKey:@"forceFullMetadata"] boolValue];
135146

136147
if ([@"pickImage" isEqualToString:call.method]) {
137148
self.result = result;
138149
_arguments = call.arguments;
139150
int imageSource = [[_arguments objectForKey:@"source"] intValue];
140151

141-
if (imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker
152+
if (usePhaAsset && imageSource == SOURCE_GALLERY) { // Capture is not possible with PHPicker
142153
if (@available(iOS 14, *)) {
143154
// PHPicker is used
144155
[self pickImageWithPHPicker:1];
@@ -171,6 +182,7 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
171182
_arguments = call.arguments;
172183

173184
int imageSource = [[_arguments objectForKey:@"source"] intValue];
185+
BOOL usePhaAsset = [[_arguments objectForKey:@"forceFullMetadata"] boolValue];
174186
if ([[_arguments objectForKey:@"maxDuration"] isKindOfClass:[NSNumber class]]) {
175187
NSTimeInterval max = [[_arguments objectForKey:@"maxDuration"] doubleValue];
176188
_imagePickerController.videoMaximumDuration = max;
@@ -181,7 +193,11 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
181193
[self checkCameraAuthorization];
182194
break;
183195
case SOURCE_GALLERY:
184-
[self checkPhotoAuthorization];
196+
if (usePhaAsset) {
197+
[self checkPhotoAuthorization];
198+
break;
199+
}
200+
[self showPhotoLibrary:UIImagePickerClassType];
185201
break;
186202
default:
187203
result([FlutterError errorWithCode:@"invalid_source"
@@ -484,8 +500,12 @@ - (void)imagePickerController:(UIImagePickerController *)picker
484500
NSNumber *maxHeight = [_arguments objectForKey:@"maxHeight"];
485501
NSNumber *imageQuality = [_arguments objectForKey:@"imageQuality"];
486502
NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality];
503+
BOOL usePhaAsset = [[_arguments objectForKey:@"forceFullMetadata"] boolValue];
487504

488-
PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info];
505+
PHAsset *originalAsset;
506+
if (usePhaAsset) {
507+
originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromImagePickerInfo:info];
508+
}
489509

490510
if (maxWidth != (id)[NSNull null] || maxHeight != (id)[NSNull null]) {
491511
image = [FLTImagePickerImageUtil scaledImage:image

packages/image_picker/image_picker/lib/image_picker.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ class ImagePicker {
4444
/// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked,
4545
/// a warning message will be logged.
4646
///
47+
/// `forceFullMetadata` defaults to `true`, so the plugin tries to get the full image metadata which may require
48+
/// extra permission requests on certain platforms.
49+
/// If `forceFullMetadata` is set to `false`, the plugin fetches the image in a way that reduces permission requests
50+
/// from the platform (e.g on iOS the plugin won’t ask for the `NSPhotoLibraryUsageDescription` permission).
51+
///
4752
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
4853
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
4954
/// Defaults to [CameraDevice.rear]. Note that Android has no documented parameter for an intent to specify if
@@ -65,13 +70,15 @@ class ImagePicker {
6570
double? maxWidth,
6671
double? maxHeight,
6772
int? imageQuality,
73+
bool forceFullMetadata = true,
6874
CameraDevice preferredCameraDevice = CameraDevice.rear,
6975
}) {
7076
return platform.pickImage(
7177
source: source,
7278
maxWidth: maxWidth,
7379
maxHeight: maxHeight,
7480
imageQuality: imageQuality,
81+
forceFullMetadata: forceFullMetadata,
7582
preferredCameraDevice: preferredCameraDevice,
7683
);
7784
}
@@ -185,6 +192,11 @@ class ImagePicker {
185192
/// image types such as JPEG and on Android PNG and WebP, too. If compression is not supported for the image that is picked,
186193
/// a warning message will be logged.
187194
///
195+
/// `forceFullMetadata` defaults to `true`, so the plugin tries to get the full image metadata which may require
196+
/// extra permission requests on certain platforms.
197+
/// If `forceFullMetadata` is set to `false`, the plugin fetches the image in a way that reduces permission requests
198+
/// from the platform (e.g on iOS the plugin won’t ask for the `NSPhotoLibraryUsageDescription` permission).
199+
///
188200
/// Use `preferredCameraDevice` to specify the camera to use when the `source` is [ImageSource.camera].
189201
/// The `preferredCameraDevice` is ignored when `source` is [ImageSource.gallery]. It is also ignored if the chosen camera is not supported on the device.
190202
/// Defaults to [CameraDevice.rear]. Note that Android has no documented parameter for an intent to specify if
@@ -205,13 +217,15 @@ class ImagePicker {
205217
double? maxWidth,
206218
double? maxHeight,
207219
int? imageQuality,
220+
bool forceFullMetadata = true,
208221
CameraDevice preferredCameraDevice = CameraDevice.rear,
209222
}) {
210223
return platform.getImage(
211224
source: source,
212225
maxWidth: maxWidth,
213226
maxHeight: maxHeight,
214227
imageQuality: imageQuality,
228+
forceFullMetadata: forceFullMetadata,
215229
preferredCameraDevice: preferredCameraDevice,
216230
);
217231
}

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.3+3
6+
version: 0.8.4
77

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

0 commit comments

Comments
 (0)