From a7f3d15b5535b54b79e1fe7cde2737965f4c9fbd Mon Sep 17 00:00:00 2001 From: TeddyYeung <78269113+TeddyYeung@users.noreply.github.com> Date: Wed, 22 Jul 2026 10:17:50 +0900 Subject: [PATCH] [image_picker_ios] Return an error for undecodable image data PHPicker can provide image-conforming data that UIImage cannot decode. Complete the save operation with invalid_image instead of passing a nil image to the save path. --- .../image_picker_ios/CHANGELOG.md | 4 ++ .../PickerSaveImageToPathOperationTests.m | 38 +++++++++++++++++++ .../FLTPHPickerSaveImageToPathOperation.m | 7 ++++ .../image_picker_ios/pubspec.yaml | 2 +- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md index 58dae8e1b635..b461eb001ffd 100644 --- a/packages/image_picker/image_picker_ios/CHANGELOG.md +++ b/packages/image_picker/image_picker_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.13+7 + +* Returns an error when selected image data cannot be decoded. + ## 0.8.13+6 * Replaces deprecated `kUTTypeGIF` with `UTTypeGIF` to fix iOS 15+ deprecation warnings. diff --git a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index a136c35c637a..2065f429b06a 100644 --- a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -229,6 +229,44 @@ - (void)testFailingImageLoad API_AVAILABLE(ios(14)) { [self waitForExpectationsWithTimeout:30 handler:nil]; } +- (void)testUndecodableImageDataReturnsErrorAndFinishes API_AVAILABLE(ios(14)) { + NSData *undecodableImageData = [@"not an image" dataUsingEncoding:NSUTF8StringEncoding]; + + id mockItemProvider = OCMClassMock([NSItemProvider class]); + OCMStub([mockItemProvider hasItemConformingToTypeIdentifier:UTTypeImage.identifier]) + .andReturn(YES); + [[mockItemProvider stub] + loadDataRepresentationForTypeIdentifier:UTTypeImage.identifier + completionHandler:[OCMArg invokeBlockWithArgs:undecodableImageData, + [NSNull null], nil]]; + + id pickerResult = OCMClassMock([PHPickerResult class]); + OCMStub([pickerResult itemProvider]).andReturn(mockItemProvider); + + XCTestExpectation *errorExpectation = [self expectationWithDescription:@"invalid image error"]; + XCTestExpectation *operationExpectation = + [self expectationWithDescription:@"Operation completed"]; + + FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] + initWithResult:pickerResult + maxHeight:@100 + maxWidth:@100 + desiredImageQuality:@100 + fullMetadata:YES + savedPathBlock:^(NSString *savedPath, FlutterError *error) { + XCTAssertNil(savedPath); + XCTAssertEqualObjects(error.code, @"invalid_image"); + [errorExpectation fulfill]; + }]; + operation.completionBlock = ^{ + [operationExpectation fulfill]; + }; + + [operation start]; + [self waitForExpectationsWithTimeout:30 handler:nil]; + XCTAssertTrue(operation.isFinished); +} + - (void)testSavePNGImageWithoutFullMetadata API_AVAILABLE(ios(14)) { id photoAssetUtil = OCMClassMock([PHAsset class]); diff --git a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTPHPickerSaveImageToPathOperation.m index caee6a4fb30f..e5f4f7c6e5cf 100644 --- a/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker_ios/ios/image_picker_ios/Sources/image_picker_ios/FLTPHPickerSaveImageToPathOperation.m @@ -127,6 +127,13 @@ - (void)start { /// Processes the image. - (void)processImage:(NSData *)pickerImageData API_AVAILABLE(ios(14)) { UIImage *localImage = [[UIImage alloc] initWithData:pickerImageData]; + if (localImage == nil) { + FlutterError *flutterError = [FlutterError errorWithCode:@"invalid_image" + message:@"Could not decode image data." + details:nil]; + [self completeOperationWithPath:nil error:flutterError]; + return; + } if (self.maxWidth != nil || self.maxHeight != nil) { localImage = [FLTImagePickerImageUtil scaledImage:localImage diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml index 076169304097..11d0cd04e4f9 100755 --- a/packages/image_picker/image_picker_ios/pubspec.yaml +++ b/packages/image_picker/image_picker_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: image_picker_ios description: iOS implementation of the image_picker plugin. repository: https://github.com/flutter/packages/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.13+6 +version: 0.8.13+7 environment: sdk: ^3.10.0