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

[image_picker] add requestFullMetadata for iOS (optional permissions) - iOS changes #5713

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
c705774
Moved iOS specific changes to a separate branch
PiotrMitkowski May 13, 2022
bf73c73
Fixed line formatting
PiotrMitkowski May 13, 2022
d48e642
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski May 25, 2022
3b3435f
PR remarks
PiotrMitkowski May 25, 2022
420a4c4
PR remarks
PiotrMitkowski May 25, 2022
ca15f9e
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski Jul 26, 2022
dff7042
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski Jul 29, 2022
b9c4cef
Updated iOS package with new interface method implementation
PiotrMitkowski Jul 29, 2022
b3d81e3
Implemented native part of picking multi images without full metadata
PiotrMitkowski Jul 29, 2022
d95b117
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski Aug 3, 2022
4a41df1
Updated versions of the platform interface in iOS implementation
PiotrMitkowski Aug 3, 2022
932ae7c
Fixed import for generated messages file
PiotrMitkowski Aug 3, 2022
2424828
Restored accidentally removed comments from generated test API file
PiotrMitkowski Aug 3, 2022
5685468
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski Aug 5, 2022
2464c13
PR remarks
PiotrMitkowski Aug 5, 2022
9252583
Merge branch 'main' of github.com:flutter/plugins into ios-optional-p…
PiotrMitkowski Aug 25, 2022
09a264a
PR remarks
PiotrMitkowski Aug 25, 2022
6aaa4b0
Merge branch 'main' into ios-optional-permissions-ios-changes
stuartmorgan Aug 31, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/image_picker/image_picker_ios/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.8.6

* Adds `requestFullMetadata` option to `pickImage`, so images on iOS can be picked without `Photo Library Usage` permission.

## 0.8.5+5

* Adds non-deprecated codepaths for iOS 13+.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ - (void)testPluginPickImageDeviceBack {
camera:FLTSourceCameraRear]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];

Expand Down Expand Up @@ -86,6 +87,7 @@ - (void)testPluginPickImageDeviceFront {
camera:FLTSourceCameraFront]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];

Expand Down Expand Up @@ -177,6 +179,24 @@ - (void)testPickMultiImageShouldUseUIImagePickerControllerOnPreiOS14 {
[mockUIImagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary]);
}

- (void)testPickImageWithoutFullMetadata API_AVAILABLE(ios(11)) {
id mockUIImagePicker = OCMClassMock([UIImagePickerController class]);
id photoLibrary = OCMClassMock([PHPhotoLibrary class]);

FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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]);
}

#pragma mark - Test camera devices, no op on simulators

- (void)testPluginPickImageDeviceCancelClickMultipleTimes {
Expand All @@ -191,6 +211,7 @@ - (void)testPluginPickImageDeviceCancelClickMultipleTimes {
camera:FLTSourceCameraRear]
maxSize:[[FLTMaxSize alloc] init]
quality:nil
fullMetadata:@(YES)
completion:^(NSString *_Nullable result, FlutterError *_Nullable error){
}];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies:
# 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.5.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.4.0?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2.4.0 was the broken version that I reverted in 2.4.1

video_player: ^2.1.4

dev_dependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,11 @@ - (void)launchPHPickerWithContext:(nonnull FLTImagePickerMethodCallContext *)con
_pickerViewController.presentationController.delegate = self;
self.callContext = context;

[self checkPhotoAuthorizationForAccessLevel];
if (context.requestFullMetadata) {
[self checkPhotoAuthorizationForAccessLevel];
} else {
[self showPhotoLibraryWithPHPicker:_pickerViewController];
}
}

- (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source
Expand All @@ -136,7 +140,16 @@ - (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source
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"
Expand All @@ -151,6 +164,7 @@ - (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source
- (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];
Expand All @@ -166,6 +180,7 @@ - (void)pickImageWithSource:(nonnull FLTSourceSpecification *)source
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, *)) {
Expand Down Expand Up @@ -234,7 +249,11 @@ - (void)pickVideoWithSource:(nonnull FLTSourceSpecification *)source
camera:[self cameraDeviceForSource:source]];
break;
case FLTSourceTypeGallery:
[self checkPhotoAuthorizationWithImagePicker:imagePickerController];
if (context.requestFullMetadata) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this need the same @available check and fallback?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized that this change for picking a video can't be used with the current platform interface. It doesn't allow passing requestFullMetadata for both multi-image and videos. I can either improve the interface or remove this change for video picking (depending on what you think is better).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any reason we wouldn't want support for this in the multi-image case, so updating that interface makes sense.

Looking at the result callback, is this change even relevant for video? It looks like the parameter is only used in a non-video codepath.

Copy link
Contributor Author

@PiotrMitkowski PiotrMitkowski Jun 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll update the interface and create a PR soon. I'll also remove usage of requestFullMetadata for the video path, since it it isn't used, as you've noticed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is still missing the iOS 11 @available check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed usage of requestFullMetadata from here since it isn't supported in the video picking.

[self checkPhotoAuthorizationWithImagePicker:imagePickerController];
} else {
[self showPhotoLibraryWithImagePicker:imagePickerController];
}
break;
default:
[self sendCallResultWithError:[FlutterError errorWithCode:@"invalid_source"
Expand Down Expand Up @@ -554,7 +573,11 @@ - (void)imagePickerController:(UIImagePickerController *)picker
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ typedef void (^FlutterResultAdapter)(NSArray<NSString *> *_Nullable, FlutterErro
/** 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 -
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -45,6 +45,7 @@ NSObject<FlutterMessageCodec> *FLTImagePickerApiGetCodec(void);
- (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
Expand Down
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -144,18 +144,21 @@ void FLTImagePickerApiSetup(id<FlutterBinaryMessenger> binaryMessenger,
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));
}];
Expand Down
46 changes: 32 additions & 14 deletions packages/image_picker/image_picker_ios/lib/image_picker_ios.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,28 @@ class ImagePickerIOS extends ImagePickerPlatform {
}) 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,
Expand Down Expand Up @@ -104,16 +118,16 @@ class ImagePickerIOS extends ImagePickerPlatform {

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');
}
Expand All @@ -124,10 +138,12 @@ class ImagePickerIOS extends ImagePickerPlatform {

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,
);
}

Expand Down Expand Up @@ -167,10 +183,12 @@ class ImagePickerIOS extends ImagePickerPlatform {
}) 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;
}
Expand Down
13 changes: 8 additions & 5 deletions packages/image_picker/image_picker_ios/lib/src/messages.g.dart
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -115,13 +115,16 @@ class ImagePickerApi {
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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ class SourceSpecification {
@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);
Expand Down
4 changes: 2 additions & 2 deletions packages/image_picker/image_picker_ios/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: image_picker_ios
description: iOS implementation of the video_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+5
version: 0.8.6

environment:
sdk: ">=2.14.0 <3.0.0"
Expand All @@ -19,7 +19,7 @@ flutter:
dependencies:
flutter:
sdk: flutter
image_picker_platform_interface: ^2.3.0
image_picker_platform_interface: ^2.5.0

dev_dependencies:
flutter_test:
Expand Down
Loading