Repository navigation
[image_picker_ios] PR 5/5 Switch Pigeon to Swift and finish the Objective-C to Swift migration. - #13493
Conversation
There was a problem hiding this comment.
Code Review
This pull request migrates the iOS image picker plugin's Pigeon integration from Objective-C to Swift, removing the Objective-C dependency and updating the plugin and its tests to use the new Swift-native types and PigeonError. Feedback on the changes suggests renaming a test helper method to match a renamed production method, and utilizing Swift's implicit bridging to cast optional Double values directly to NSNumber? instead of using .map.
| /// Saves run on a background queue and the result is delivered later on the | ||
| /// main queue, so `confirmation` would return before the callback runs. | ||
| /// `#expect` on that queue is not recorded on this test. | ||
| private func processPickerItems( |
There was a problem hiding this comment.
The helper method processPickerItems should be renamed to processPickerResults to remain consistent with the renamed production method processPickerResults in ImagePickerPlugin and the updated doc comment above.\n\nNote: If you apply this suggestion, please make sure to also rename any other call sites of this helper method within this test file to avoid compilation errors.
| private func processPickerItems( | |
| private func processPickerResults( |
There was a problem hiding this comment.
Renamed the helper to processPickerResults, including its three call sites, so it matches ImagePickerPlugin.processPickerResults
| let maxWidth = currentCallContext?.maxSize?.width.map { NSNumber(value: $0) } | ||
| let maxHeight = currentCallContext?.maxSize?.height.map { NSNumber(value: $0) } |
There was a problem hiding this comment.
Instead of using .map { NSNumber(value: $0) }, you can leverage Swift's implicit bridging to NSNumber by casting the optional Double directly using as NSNumber?. This is more concise and idiomatic.
let maxWidth = currentCallContext?.maxSize?.width as NSNumber?\n let maxHeight = currentCallContext?.maxSize?.height as NSNumber?There was a problem hiding this comment.
Done. width and height are now cast with as NSNumber? here
| let maxWidth = callContext?.maxSize?.width.map { NSNumber(value: $0) } | ||
| let maxHeight = callContext?.maxSize?.height.map { NSNumber(value: $0) } |
There was a problem hiding this comment.
Instead of using .map { NSNumber(value: $0) }, you can leverage Swift's implicit bridging to NSNumber by casting the optional Double directly using as NSNumber?. This is more concise and idiomatic.
let maxWidth = callContext?.maxSize?.width as NSNumber?\n let maxHeight = callContext?.maxSize?.height as NSNumber?There was a problem hiding this comment.
Done. The camera path uses the same as NSNumber? cast
stuartmorgan
left a comment
There was a problem hiding this comment.
This should have a full iOS team review still, but some drive-by comments as someone familiar with Swift Pigeon conversions.
| return | ||
| } | ||
| completion(paths?.first, error) | ||
| if let error { |
There was a problem hiding this comment.
Is it safe to use the abbreviated syntax now? The podspec is still listing the Swift version as 5.0, and this is 5.7+ syntax. Maybe it's moot under the current Xcode version requirements though?
There was a problem hiding this comment.
Yes. s.swift_version = '5.0' selects the Swift 5 language mode. if let error is Swift 5.7, and this package requires Flutter 3.47, whose iOS toolchain is well past that
There was a problem hiding this comment.
I double checked https://xcodereleases.com/ - Swift 5.7 is in Xcode 14 so we are safe
There was a problem hiding this comment.
None of these entries are doing anything any more; they should be replaced with @SwiftFunction annotations where needed, and remove where no longer useful.
There was a problem hiding this comment.
Removed all five @ObjCSelectors. The generated Swift names already match the plugin (pickImage(source:maxSize:imageQuality:requestFullMetadata:completion:) and the other four), so none of them need an @SwiftFunction. Regenerating Pigeon did not change the generated Dart or Swift
| } | ||
|
|
||
| func desiredImageQuality(_ imageQuality: NSNumber?) -> NSNumber { | ||
| func desiredImageQuality(_ imageQuality: Int64?) -> NSNumber { |
There was a problem hiding this comment.
Isn't all of the usage of NSNumber that still exists in this file (and the internal utilities they call to) a legacy of the Pigeon APIs using NSNumbers to express nullability? I would expect that everything in the entire plugin could stop using NSNumber as part of this PR.
There was a problem hiding this comment.
Done for the plugin's own values. desiredImageQuality now returns Double, and max width, max height, and quality are Double? through the save operation and the image utilities. The remaining NSNumbers are ImageIO dictionary values (GIF delay, GIF loop count, and EXIF), not the old Pigeon nullability wrappers
There was a problem hiding this comment.
The remaining
NSNumbers are ImageIO dictionary values (GIF delay, GIF loop count, and EXIF), not the old Pigeon nullability wrappers
Option since it's not entirely in scope, but doesn't reading the dictionary values with as? Double? or as? Int? trigged the auto-bridging and avoid the need to manually call doubleValue/intValue later (and the need to reference NSNumber directly in Swift code at all)?
There was a problem hiding this comment.
Done. as? Double and as? Int bridge the ImageIO NSNumbers, so the GIF delay, loop count, and EXIF dimension no longer go through NSNumber, doubleValue, or intValue. I used as? Double and as? Int rather than as? Double?
| maxDurationSeconds: nil | ||
| ) { result in | ||
| guard case .failure(let error as PigeonError) = result else { | ||
| Issue.record("Expected invalid_result") |
There was a problem hiding this comment.
These message could be useful when tests fail. Can you make them more verbose?
There was a problem hiding this comment.
Done! Each Issue.record in this file now includes the actual result
| return | ||
| } | ||
| completion(paths?.first, error) | ||
| if let error { |
There was a problem hiding this comment.
I double checked https://xcodereleases.com/ - Swift 5.7 is in Xcode 14 so we are safe
…to Swift migration.
…for clarity in test cases and update related references.
…e size and quality. Swift Pigeon ignores the old selectors, and NSNumber was only wrapping nullable width, height, and quality.
…IF and GIF properties. Additionally, modifies ImagePickerImageUtil to handle GIF delay times as Double.
… include result details for better debugging.
9fb26b6 to
403e59a
Compare
flutter/packages@0478162...63881f9 2026-11-06 [email protected] [material_ui] Paint Dialog.fullscreen background color behind the keyboard (flutter/packages#13244) 2026-11-05 [email protected] [material_ui] Add tabBar/tab roles and expanded state semantics (flutter/packages#13176) 2026-11-05 [email protected] [material_ui] Disable the DropdownButtonFormField decoration when the field is disabled (flutter/packages#13473) 2026-11-05 [email protected] [material_ui] Fix Switch throwing when first painted mid-animation (flutter/packages#13496) 2026-11-05 [email protected] [various] Add engineIdentifier to fake plugin registrars (flutter/packages#13574) 2026-11-05 [email protected] [google_sign_in] Allow GoogleSignIn-iOS 10 (flutter/packages#13306) 2026-11-05 [email protected] [material_ui] Hit test the floating label of InputDecorator at its painted position (flutter/packages#13326) 2026-11-05 [email protected] [material_ui] Fix InputDecorator intrinsic height when isDense or isC… (flutter/packages#13522) 2026-11-05 [email protected] [material_ui] Paint Scaffold persistent bottom sheet background color behind the keyboard (flutter/packages#13242) 2026-11-05 [email protected] [image_picker_ios] PR 5/5 Switch Pigeon to Swift and finish the Objective-C to Swift migration. (flutter/packages#13493) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
…13570) Converts the `image_picker_ios` iOS example app and UI tests from Objective-C to Swift: * `AppDelegate` is now Swift. `@main` replaces `main.m`, and `AppDelegate.h` becomes `Runner-Bridging-Header.h`. * `ImagePickerFromGalleryUITests` and `ImagePickerFromLimitedGalleryUITests` are now Swift. * The example still seeds the photo library from `jpgImageTall.jpg`, and logs when that fixture is missing. * Drops the `@available(iOS 14, *)` checks in the UI tests. The example already requires iOS 15. The plugin implementation is unchanged from #13493. Bumps image_picker_ios to **0.8.13+16**. Follow-up to the Obj-C → Swift migration, following #13493. Part of flutter/flutter#119107 ## Pre-Review Checklist **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
Switches
image_picker_iosPigeon output from Objective-C to Swift and removes the remaining Objective-C packaging:pigeons/messages.dartnow generatesmessages.g.swiftinstead ofmessages.g.handmessages.g.m.ImagePickerPluginand the PHPicker save operation use the generated Swift API, includingPigeonErrorinstead ofFlutterError.image_picker_ios_objcSwift Package Manager target, theimage_picker_ios.humbrella header, and the custom module map.s.module_map.The iOS example app and UI tests stay Objective-C until the next PR.
Bumps image_picker_ios to 0.8.13+15.
PR 5/5 of the Obj-C → Swift migration, following #13394. Part of flutter/flutter#119107
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2