Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
cf18209
Added pickMultiImage to image_picker_platform_interface
danielroek Mar 10, 2021
41af3db
initial implementation Android
danielroek Mar 12, 2021
7b934b0
Added some Android unit tests
danielroek Mar 12, 2021
82385a5
Fixed failing tests
danielroek Mar 12, 2021
74c9fad
Added tests
danielroek Mar 17, 2021
f027e9a
fixed platform_interface tests
danielroek Mar 17, 2021
31eae2d
WIP: iOS implementation
Mar 24, 2021
bbb094b
Finished iOS implementation; Formatted code
Mar 31, 2021
e8cf955
Reverted changes in example
Mar 31, 2021
a543675
Added image compression to iOS implementation; Removed some NSLogs; A…
Apr 2, 2021
0844445
Updated docs, bumped version to 0.7.3
Apr 2, 2021
745fb1e
Merge remote-tracking branch 'flutter/master' into image_picker_multi…
danielroek Apr 14, 2021
17cb3d8
Merge branch 'master' into image_picker_multi_image_android
danielroek Apr 14, 2021
3fd1a01
Updated version
danielroek Apr 14, 2021
75b34be
Fixed formatting
danielroek Apr 14, 2021
ea075ad
Merge remote-tracking branch 'origin/image_picker_multi_image_android…
danielroek Apr 14, 2021
2619cf4
Fixed formatting
Apr 14, 2021
4362c6e
Improved iOS implementation
Apr 22, 2021
9b1171f
Improved iOS implementation
Apr 22, 2021
e693266
Changed test to second image, because first sample image is HEIC
Apr 22, 2021
4563f90
Merge remote-tracking branch 'origin/master' into image_picker_multi_…
danielroek Apr 22, 2021
c09e604
Updated documentation
danielroek Apr 22, 2021
8cb0114
Merge branch 'master' into image_picker_multi_image_android
ydag May 21, 2021
d3315c8
Refactor handleChooseMultiImageResult method
ydag May 25, 2021
85d605c
Refactor picker to implement multi image option
ydag May 25, 2021
aaf5fd8
Add handleMultiSavedPaths method to return images
ydag May 25, 2021
7cf9338
Add handlePath to reuse the code
ydag May 25, 2021
7d9b7a5
Add unit tests for multi image on Flutter
ydag May 26, 2021
bba9609
Change to group unit tests better way
ydag May 26, 2021
2382d9e
Add additional parameters to handlePath method
ydag May 27, 2021
0e910ac
Fix the comment
ydag May 27, 2021
ca3be77
Refactor picker to use semaphore
ydag May 31, 2021
b69234a
Add declaration comment for handlePath method
ydag May 31, 2021
d2be72d
Add declaration comment for handleMultiSavedPaths
ydag May 31, 2021
9c96f25
Add testPluginMultiImagePathIsNull unit test
ydag May 31, 2021
3a0cb11
Add testPluginMultiImagePathHasZeroItem unit test
ydag May 31, 2021
d39e39c
Add testPluginMultiImagePathHasItem unit test
ydag May 31, 2021
527491d
Update CHANGELOG file and version
ydag May 31, 2021
1bae4e2
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 1, 2021
572e04b
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 2, 2021
dc40ea3
Update code format
ydag Jun 2, 2021
ba34e22
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 2, 2021
ae3f811
Remove the unnecessary test
ydag Jun 3, 2021
3b07dc2
Update the comments
ydag Jun 3, 2021
6b657f7
Add buildMethodCall that has only method parameter
ydag Jun 3, 2021
5595392
Refactor the test
ydag Jun 3, 2021
6c82b13
Fix the test name
ydag Jun 3, 2021
6c6ca76
Update the docs
ydag Jun 4, 2021
aeac535
Update the handleChooseMultiImageResult method
ydag Jun 4, 2021
02a1d07
Update the method name
ydag Jun 4, 2021
7f147dc
Update the parameter name
ydag Jun 4, 2021
a1ec45a
Update the property name and type
ydag Jun 4, 2021
9ad4a9a
Update the method comment
ydag Jun 4, 2021
a598d78
Update the method comments
ydag Jun 4, 2021
4af8c30
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 4, 2021
e996554
Fix picker to use semaphore better
ydag Jun 7, 2021
3b8c1dd
Make sure the order of pathList is the same as the order of results
renefloor Jun 7, 2021
7c09ae6
Separate creation of array in function
renefloor Jun 8, 2021
b5de177
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 8, 2021
ed7ef7e
Fix unit tests
ydag Jun 8, 2021
a2621e6
Update method comment
ydag Jun 8, 2021
60b5238
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 8, 2021
25d9a46
Fix format
ydag Jun 9, 2021
6f4e7c7
Update CHANGELOG.md
ydag Jun 14, 2021
33b74a0
Fix to correct variable type
ydag Jun 14, 2021
8c0c5ca
Refactor to return List from all the places
ydag Jun 14, 2021
152bd33
Remove unnecessary test
ydag Jun 14, 2021
f3d2441
Fix the if statement for maxImagesAllowed
ydag Jun 14, 2021
44c06f1
Update the method comment and name
ydag Jun 14, 2021
3a0aca4
Revert the if statement changes
ydag Jun 14, 2021
9d0b257
Add new classes to subclass NSOperation
ydag Jun 16, 2021
d9d8525
Refactor picker method to use NSOperation
ydag Jun 16, 2021
5deab57
Update naming
ydag Jun 16, 2021
3182612
Add block to get saved path
ydag Jun 17, 2021
d7a5e70
Update naming
ydag Jun 17, 2021
6c514b7
Update CHANGELOG
ydag Jun 17, 2021
32cefbc
Update README
ydag Jun 17, 2021
60b2e06
Refactor to clean code
ydag Jun 17, 2021
7f3791b
Refactor if statement and error message
ydag Jun 17, 2021
193566a
Add class documentation
ydag Jun 17, 2021
b41e3f4
Fix error message
ydag Jun 18, 2021
3712c95
Update naming
ydag Jun 18, 2021
59f3501
Refactor if statement to check pathList items
ydag Jun 18, 2021
080a211
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 18, 2021
b3c8518
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 21, 2021
e20b966
Fix format
ydag Jun 21, 2021
42b2db1
Refactor if statement
ydag Jun 21, 2021
e8a6c95
Fix unit test
ydag Jun 21, 2021
27e0790
Merge branch 'master' into image_picker_multi_image_android
ydag Jun 22, 2021
c39bf66
Update packages/image_picker/image_picker/README.md
ydag Jun 22, 2021
44ab497
Update packages/image_picker/image_picker/CHANGELOG.md
ydag Jun 22, 2021
b858317
Merge branch 'image_picker_multi_image_android' of github.com:Baseflo…
ydag Jun 22, 2021
43473da
Add else block for lower iOS versions
ydag Jun 22, 2021
c50b694
Update the CHANGELOG
ydag Jun 22, 2021
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
11 changes: 9 additions & 2 deletions packages/image_picker/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.8.1

* Add a new method `getMultiImage` to allow picking multiple images on iOS 14 or higher
and Android 4.3 or higher. Returns only 1 image for lower versions of iOS and Android.
* Known issue: On Android, `getLostData` will only get the last picked image when picking multiple images,
see: [#84634](https://github.com/flutter/flutter/issues/84634).

## 0.8.0+4

* Cleaned up the README example
Expand Down Expand Up @@ -49,15 +56,15 @@ is not included selected photos and image is scaled.

## 0.7.3

* Endorse image_picker_for_web
* Endorse image_picker_for_web.
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!


## 0.7.2+1

* Android: fixes an issue where videos could be wrongly picked with `.jpg` extension.

## 0.7.2

* Run CocoaPods iOS tests in RunnerUITests target
* Run CocoaPods iOS tests in RunnerUITests target.

## 0.7.1

Expand Down
7 changes: 7 additions & 0 deletions packages/image_picker/image_picker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ First, add `image_picker` as a [dependency in your pubspec.yaml file](https://fl

### iOS

Starting with version **0.8.1** the iOS implementation uses PHPicker to pick (multiple) images on iOS 14 or higher.
As a result of implementing PHPicker it becomes impossible to pick HEIC images on the iOS simulator in iOS 14+. This is a known issue. Please test this on a real device, or test with non-HEIC images until Apple solves this issue.[63426347 - Apple known issue](https://www.google.com/search?q=63426347+apple&sxsrf=ALeKk01YnTMid5S0PYvhL8GbgXJ40ZS[…]t=gws-wiz&ved=0ahUKEwjKh8XH_5HwAhWL_rsIHUmHDN8Q4dUDCA8&uact=5)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a Google Search URL, is there a direct link to the Apple issue tracker? I can only find forum threads like this: https://developer.apple.com/forums/thread/658135

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, there is not an issue tracker. Not one publicly available. It seems those issues can contain private data which is why they are private.

Copy link
Contributor

Choose a reason for hiding this comment

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


Add the following keys to your _Info.plist_ file, located in `<project root>/ios/Runner/Info.plist`:

* `NSPhotoLibraryUsageDescription` - describe why your app needs permission for the photo library. This is called _Privacy - Photo Library Usage Description_ in the visual editor.
Expand All @@ -19,6 +22,8 @@ Add the following keys to your _Info.plist_ file, located in `<project root>/ios

### Android

Starting with version **0.8.1** the Android implementation support to pick (multiple) images on Android 4.3 or higher.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's also mention the android knowns issue for get lost data in the Handling MainActivity destruction on Android in README

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.


No configuration required - the plugin should work out of the box.

It is no longer required to add `android:requestLegacyExternalStorage="true"` as an attribute to the `<application>` tag in AndroidManifest.xml, as `image_picker` has been updated to make use of scoped storage.
Expand Down Expand Up @@ -63,6 +68,8 @@ Future<void> retrieveLostData() async {

There's no way to detect when this happens, so calling this method at the right place is essential. We recommend to wire this into some kind of start up check. Please refer to the example app to see how we used it.

On Android, `getLostData` will only get the last picked image when picking multiple images, see: [#84634](https://github.com/flutter/flutter/issues/84634).

## Deprecation warnings in `pickImage`, `pickVideo` and `LostDataResponse`

Starting with version **0.6.7** of the image_picker plugin, the API of the plugin changed slightly to allow for web implementations to exist.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.flutter.plugin.common.PluginRegistry;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
Expand Down Expand Up @@ -75,6 +76,7 @@ public class ImagePickerDelegate
@VisibleForTesting static final int REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY = 2342;
@VisibleForTesting static final int REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA = 2343;
@VisibleForTesting static final int REQUEST_CAMERA_IMAGE_PERMISSION = 2345;
@VisibleForTesting static final int REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY = 2346;
@VisibleForTesting static final int REQUEST_CODE_CHOOSE_VIDEO_FROM_GALLERY = 2352;
@VisibleForTesting static final int REQUEST_CODE_TAKE_VIDEO_WITH_CAMERA = 2353;
@VisibleForTesting static final int REQUEST_CAMERA_VIDEO_PERMISSION = 2355;
Expand Down Expand Up @@ -315,13 +317,32 @@ public void chooseImageFromGallery(MethodCall methodCall, MethodChannel.Result r
launchPickImageFromGalleryIntent();
}

public void chooseMultiImageFromGallery(MethodCall methodCall, MethodChannel.Result result) {
if (!setPendingMethodCallAndResult(methodCall, result)) {
finishWithAlreadyActiveError(result);
return;
}

launchMultiPickImageFromGalleryIntent();
}

private void launchPickImageFromGalleryIntent() {
Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT);
pickImageIntent.setType("image/*");

activity.startActivityForResult(pickImageIntent, REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY);
}

private void launchMultiPickImageFromGalleryIntent() {
Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
Copy link
Contributor

Choose a reason for hiding this comment

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

So lower android version won't allow multiple images right? We need to mention it in the CHANGELOG and other docs as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done.

pickImageIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
pickImageIntent.setType("image/*");

activity.startActivityForResult(pickImageIntent, REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY);
}

public void takeImageWithCamera(MethodCall methodCall, MethodChannel.Result result) {
if (!setPendingMethodCallAndResult(methodCall, result)) {
finishWithAlreadyActiveError(result);
Expand Down Expand Up @@ -440,6 +461,9 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
case REQUEST_CODE_CHOOSE_IMAGE_FROM_GALLERY:
handleChooseImageResult(resultCode, data);
break;
case REQUEST_CODE_CHOOSE_MULTI_IMAGE_FROM_GALLERY:
handleChooseMultiImageResult(resultCode, data);
break;
case REQUEST_CODE_TAKE_IMAGE_WITH_CAMERA:
handleCaptureImageResult(resultCode);
break;
Expand Down Expand Up @@ -467,6 +491,24 @@ private void handleChooseImageResult(int resultCode, Intent data) {
finishWithSuccess(null);
}

private void handleChooseMultiImageResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_OK && intent != null) {
ArrayList<String> paths = new ArrayList<>();
if (intent.getClipData() != null) {
for (int i = 0; i < intent.getClipData().getItemCount(); i++) {
paths.add(fileUtils.getPathFromUri(activity, intent.getClipData().getItemAt(i).getUri()));
}
} else {
paths.add(fileUtils.getPathFromUri(activity, intent.getData()));
}
handleMultiImageResult(paths, false);
return;
}

// User cancelled choosing a picture.
finishWithSuccess(null);
}

private void handleChooseVideoResult(int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && data != null) {
String path = fileUtils.getPathFromUri(activity, data.getData());
Expand Down Expand Up @@ -516,26 +558,45 @@ public void onPathReady(String path) {
finishWithSuccess(null);
}

private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) {
private void handleMultiImageResult(
ArrayList<String> paths, boolean shouldDeleteOriginalIfScaled) {
if (methodCall != null) {
Double maxWidth = methodCall.argument("maxWidth");
Double maxHeight = methodCall.argument("maxHeight");
Integer imageQuality = methodCall.argument("imageQuality");

String finalImagePath =
imageResizer.resizeImageIfNeeded(path, maxWidth, maxHeight, imageQuality);

finishWithSuccess(finalImagePath);
for (int i = 0; i < paths.size(); i++) {
String finalImagePath = getResizedImagePath(paths.get(i));

//delete original file if scaled
if (finalImagePath != null
&& !finalImagePath.equals(paths.get(i))
&& shouldDeleteOriginalIfScaled) {
new File(paths.get(i)).delete();
}
paths.set(i, finalImagePath);
}
finishWithListSuccess(paths);
}
}

private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) {
if (methodCall != null) {
String finalImagePath = getResizedImagePath(path);
//delete original file if scaled
if (finalImagePath != null && !finalImagePath.equals(path) && shouldDeleteOriginalIfScaled) {
new File(path).delete();
}
finishWithSuccess(finalImagePath);
} else {
finishWithSuccess(path);
}
}

private String getResizedImagePath(String path) {
Double maxWidth = methodCall.argument("maxWidth");
Double maxHeight = methodCall.argument("maxHeight");
Integer imageQuality = methodCall.argument("imageQuality");

return imageResizer.resizeImageIfNeeded(path, maxWidth, maxHeight, imageQuality);
}

private void handleVideoResult(String path) {
finishWithSuccess(path);
}
Expand Down Expand Up @@ -564,6 +625,17 @@ private void finishWithSuccess(String imagePath) {
clearMethodCallAndResult();
}

private void finishWithListSuccess(ArrayList<String> imagePaths) {
if (pendingResult == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we also call clearMethodCallAndResult(); in this case?

for (String imagePath : imagePaths) {
cache.saveResult(imagePath, null, null);
Copy link
Contributor

Choose a reason for hiding this comment

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

only one image can be saved in the "cache", so only the last one saved is in the cache, it is not what we want right?
We might need a different cache for list Images, or we can deprecate the old cache, and the new cache always have a list of images (when there is only one image, the list length is 1)

Copy link
Contributor

@ydag ydag Jun 4, 2021

Choose a reason for hiding this comment

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

We can save only one image path and it is the last one in this case. Maybe we can create another PR to update the cache. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, please create an issue and link a TODO to it. We also need to mentioned this "known issue" in the CHANGELOG, which also can be linked to the same issue.

}
return;
}
pendingResult.success(imagePaths);
clearMethodCallAndResult();
}

private void finishWithAlreadyActiveError(MethodChannel.Result result) {
result.error("already_active", "Image picker is already active", null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public void onActivityStopped(Activity activity) {
}

static final String METHOD_CALL_IMAGE = "pickImage";
static final String METHOD_CALL_MULTI_IMAGE = "pickMultiImage";
static final String METHOD_CALL_VIDEO = "pickVideo";
private static final String METHOD_CALL_RETRIEVE = "retrieve";
private static final int CAMERA_DEVICE_FRONT = 1;
Expand Down Expand Up @@ -302,6 +303,9 @@ public void onMethodCall(MethodCall call, MethodChannel.Result rawResult) {
throw new IllegalArgumentException("Invalid image source: " + imageSource);
}
break;
case METHOD_CALL_MULTI_IMAGE:
delegate.chooseMultiImageFromGallery(call, result);
break;
case METHOD_CALL_VIDEO:
imageSource = call.argument("source");
switch (imageSource) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ public void chooseImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyAc
}

@Test
public void chooseMultiImageFromGallery_WhenPendingResultExists_FinishesWithAlreadyActiveError() {
ImagePickerDelegate delegate = createDelegateWithPendingResultAndMethodCall();

delegate.chooseMultiImageFromGallery(mockMethodCall, mockResult);

verifyFinishedWithAlreadyActiveError();
verifyNoMoreInteractions(mockResult);
}

public void
chooseImageFromGallery_WhenHasExternalStoragePermission_LaunchesChooseFromGalleryIntent() {
when(mockPermissionManager.isPermissionGranted(Manifest.permission.READ_EXTERNAL_STORAGE))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class ImagePickerPluginTest {
private static final int SOURCE_CAMERA = 0;
private static final int SOURCE_GALLERY = 1;
private static final String PICK_IMAGE = "pickImage";
private static final String PICK_MULTI_IMAGE = "pickMultiImage";
private static final String PICK_VIDEO = "pickVideo";

@Rule public ExpectedException exception = ExpectedException.none();
Expand Down Expand Up @@ -92,6 +93,14 @@ public void onMethodCall_WhenSourceIsGallery_InvokesChooseImageFromGallery() {
verifyZeroInteractions(mockResult);
}

@Test
public void onMethodCall_InvokesChooseMultiImageFromGallery() {
MethodCall call = buildMethodCall(PICK_MULTI_IMAGE);
plugin.onMethodCall(call, mockResult);
verify(mockImagePickerDelegate).chooseMultiImageFromGallery(eq(call), any());
verifyZeroInteractions(mockResult);
}

@Test
public void onMethodCall_WhenSourceIsCamera_InvokesTakeImageWithCamera() {
MethodCall call = buildMethodCall(PICK_IMAGE, SOURCE_CAMERA);
Expand Down Expand Up @@ -173,4 +182,8 @@ private MethodCall buildMethodCall(String method, final int source) {

return new MethodCall(method, arguments);
}

private MethodCall buildMethodCall(String method) {
return new MethodCall(method, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ - (UIViewController *)presentedViewController {

@interface FLTImagePickerPlugin (Test)
@property(copy, nonatomic) FlutterResult result;
- (void)handleSavedPath:(NSString *)path;
- (void)handleSavedPathList:(NSMutableArray *)pathList;
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;
@end

Expand Down Expand Up @@ -122,21 +122,6 @@ - (void)testPickingVideoWithDuration {
XCTAssertEqual([plugin getImagePickerController].videoMaximumDuration, 95);
}

- (void)testPluginPickImageSelectMultipleTimes {
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
FlutterMethodCall *call =
[FlutterMethodCall methodCallWithMethodName:@"pickImage"
arguments:@{@"source" : @(0), @"cameraDevice" : @(0)}];
[plugin handleMethodCall:call
result:^(id _Nullable r){
}];
plugin.result = ^(id result) {

};
[plugin handleSavedPath:@"test"];
[plugin handleSavedPath:@"test"];
}

- (void)testViewController {
UIWindow *window = [UIWindow new];
MockViewController *vc1 = [MockViewController new];
Expand All @@ -149,4 +134,62 @@ - (void)testViewController {
XCTAssertEqual([plugin viewControllerWithWindow:window], vc2);
}

- (void)testPluginMultiImagePathIsNil {
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];

dispatch_semaphore_t resultSemaphore = dispatch_semaphore_create(0);
__block FlutterError *pickImageResult = nil;

plugin.result = ^(id _Nullable r) {
pickImageResult = r;
dispatch_semaphore_signal(resultSemaphore);
};
[plugin handleSavedPathList:nil];

dispatch_semaphore_wait(resultSemaphore, DISPATCH_TIME_FOREVER);

XCTAssertEqualObjects(pickImageResult.code, @"create_error");
}

- (void)testPluginMultiImagePathHasNullItem {
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
NSMutableArray *pathList = [NSMutableArray new];

[pathList addObject:[NSNull null]];

dispatch_semaphore_t resultSemaphore = dispatch_semaphore_create(0);
__block FlutterError *pickImageResult = nil;

plugin.result = ^(id _Nullable r) {
pickImageResult = r;
dispatch_semaphore_signal(resultSemaphore);
};
[plugin handleSavedPathList:pathList];

dispatch_semaphore_wait(resultSemaphore, DISPATCH_TIME_FOREVER);

XCTAssertEqualObjects(pickImageResult.code, @"create_error");
}

- (void)testPluginMultiImagePathHasItem {
FLTImagePickerPlugin *plugin = [FLTImagePickerPlugin new];
NSString *savedPath = @"test";
NSMutableArray *pathList = [NSMutableArray new];

[pathList addObject:savedPath];

dispatch_semaphore_t resultSemaphore = dispatch_semaphore_create(0);
__block id pickImageResult = nil;

plugin.result = ^(id _Nullable r) {
pickImageResult = r;
dispatch_semaphore_signal(resultSemaphore);
};
[plugin handleSavedPathList:pathList];

dispatch_semaphore_wait(resultSemaphore, DISPATCH_TIME_FOREVER);

XCTAssertEqual(pickImageResult, pathList);
}

@end
Loading