Repository navigation
[image_picker_ios] PR 3/5 Split SPM packaging and migrate the plugin class to Swift - #13235
Conversation
There was a problem hiding this comment.
Code Review
This pull request migrates the iOS implementation of the image_picker plugin from Objective-C to Swift and restructures the codebase into mixed-language Swift Package Manager targets. The review feedback focuses on improving the safety and idiomatic quality of the new Swift code. Key recommendations include addressing a potential data race in processPickerItems using NSLock and native Swift arrays, removing redundant Objective-C synchronization blocks, refactoring sendCallResult(withSavedPathList:) to use native Swift arrays instead of NSArray, and removing unnecessary type casts in both the plugin implementation and its unit tests.
| let pathList = NSMutableArray(capacity: results.count) | ||
| var saveError: FlutterError? | ||
|
|
||
| let sendListOperation = BlockOperation { | ||
| if let saveError { | ||
| self.sendCallResult(with: saveError) | ||
| } else { | ||
| self.sendCallResult(withSavedPathList: pathList) | ||
| } | ||
| saveQueue = nil | ||
| } | ||
|
|
||
| for result in results { | ||
| pathList.add(NSNull()) | ||
| let index = pathList.count - 1 | ||
| guard | ||
| let saveOperation = FLTPHPickerSaveImageToPathOperation( | ||
| result: result, | ||
| maxHeight: maxHeight, | ||
| maxWidth: maxWidth, | ||
| desiredImageQuality: desiredImageQuality, | ||
| fullMetadata: requestFullMetadata, | ||
| savedPathBlock: { savedPath, error in | ||
| if let savedPath { | ||
| pathList[index] = savedPath | ||
| } else { | ||
| saveError = error | ||
| } | ||
| }) |
There was a problem hiding this comment.
The current implementation of processPickerItems uses NSMutableArray and NSNull to collect paths from concurrent background operations. Since NSMutableArray is not thread-safe, concurrent writes to it from different background threads in saveQueue can cause data races, crashes, or undefined behavior. Additionally, saveError is written to concurrently without synchronization.
We can resolve this data race and make the code much more idiomatic Swift by:
- Using a native Swift array
[String?]instead ofNSMutableArrayandNSNull. - Protecting concurrent writes to
pathListandsaveErrorusing anNSLock.
var pathList = [String?](repeating: nil, count: results.count)
var saveError: FlutterError?
let lock = NSLock()
let sendListOperation = BlockOperation {
if let saveError {
self.sendCallResult(with: saveError)
} else {
self.sendCallResult(withSavedPathList: pathList)
}
saveQueue = nil
}
for (index, result) in results.enumerated() {
guard
let saveOperation = FLTPHPickerSaveImageToPathOperation(
result: result,
maxHeight: maxHeight,
maxWidth: maxWidth,
desiredImageQuality: desiredImageQuality,
fullMetadata: requestFullMetadata,
savedPathBlock: { savedPath, error in
lock.lock()
defer { lock.unlock() }
if let savedPath {
pathList[index] = savedPath
} else {
saveError = error
}
})There was a problem hiding this comment.
savedPathBlock runs on PHPicker's private queue, and the save queue runs those operations concurrently, so the path-list writes could overlap. pathList is now [String?], and an NSLock covers writes to it and to saveError. The main-queue operation copies both under that lock after the saves finish
| objc_sync_enter(self) | ||
| let beingPresented = imagePickerController.isBeingPresented | ||
| objc_sync_exit(self) | ||
| if beingPresented { | ||
| return | ||
| } |
There was a problem hiding this comment.
The use of objc_sync_enter and objc_sync_exit is unidiomatic in Swift. Since showCamera is always called on the main thread, this synchronization is redundant and can be safely removed.
| objc_sync_enter(self) | |
| let beingPresented = imagePickerController.isBeingPresented | |
| objc_sync_exit(self) | |
| if beingPresented { | |
| return | |
| } | |
| if imagePickerController.isBeingPresented { | |
| return | |
| } |
There was a problem hiding this comment.
This is the port of @synchronized(self) around beingPresented. The authorized path calls showCamera on the caller. Only the not-determined path hops to the main queue first. I kept that critical section
| details: nil)) | ||
| return | ||
| } | ||
| sendCallResult(withSavedPathList: [destination.path] as NSArray) |
There was a problem hiding this comment.
Done. That call uses the [String?]? parameter
| let savedPath = FLTImagePickerPhotoAssetUtil.saveImage( | ||
| withOriginalImageData: originalImageData, image: image ?? UIImage(), | ||
| maxWidth: maxWidth, maxHeight: maxHeight, imageQuality: imageQuality) | ||
| sendCallResult(withSavedPathList: [savedPath] as NSArray) |
There was a problem hiding this comment.
Done. That call uses the [String?]? parameter
| withPickerInfo info: [String: Any]?, image: UIImage, imageQuality: NSNumber? | ||
| ) { | ||
| let savedPath = FLTImagePickerPhotoAssetUtil.saveImage( | ||
| withPickerInfo: info, image: image, imageQuality: imageQuality) |
There was a problem hiding this comment.
Done. That call uses the [String?]? parameter
| func sendCallResult(withSavedPathList pathList: NSArray?) { | ||
| guard let callContext else { | ||
| return | ||
| } | ||
|
|
||
| if let pathList, pathList.contains(NSNull()) { | ||
| callContext.result( | ||
| nil, | ||
| FlutterError( | ||
| code: "create_error", | ||
| message: "pathList's items should not be null", | ||
| details: nil)) | ||
| } else { | ||
| let paths = pathList?.compactMap { $0 as? String } ?? [] | ||
| callContext.result(paths, nil) | ||
| } | ||
| self.callContext = nil | ||
| } |
There was a problem hiding this comment.
To make the API more idiomatic Swift and avoid unnecessary bridging to Objective-C types, we should change sendCallResult(withSavedPathList:) to accept a native Swift array [String?]? instead of NSArray?.
| func sendCallResult(withSavedPathList pathList: NSArray?) { | |
| guard let callContext else { | |
| return | |
| } | |
| if let pathList, pathList.contains(NSNull()) { | |
| callContext.result( | |
| nil, | |
| FlutterError( | |
| code: "create_error", | |
| message: "pathList's items should not be null", | |
| details: nil)) | |
| } else { | |
| let paths = pathList?.compactMap { $0 as? String } ?? [] | |
| callContext.result(paths, nil) | |
| } | |
| self.callContext = nil | |
| } | |
| func sendCallResult(withSavedPathList pathList: [String?]?) { | |
| guard let callContext else { | |
| return | |
| } | |
| if let pathList, pathList.contains(where: { $0 == nil }) { | |
| callContext.result( | |
| nil, | |
| FlutterError( | |
| code: "create_error", | |
| message: "pathList's items should not be null", | |
| details: nil)) | |
| } else { | |
| let paths = pathList?.compactMap { $0 } ?? [] | |
| callContext.result(paths, nil) | |
| } | |
| self.callContext = nil | |
| } |
There was a problem hiding this comment.
sendCallResult(withSavedPathList:) now takes [String?]?. A nil item still returns create_error. The call sites pass Swift arrays directly
| private func captureSendResult( | ||
| _ plugin: FLTImagePickerPlugin, pathList: [Any]? | ||
| _ plugin: ImagePickerPlugin, pathList: [Any]? | ||
| ) -> (result: [String]?, error: FlutterError?) { | ||
| var received: [String]? | ||
| var receivedError: FlutterError? | ||
| plugin.callContext = FLTImagePickerMethodCallContext { result, error in | ||
| plugin.callContext = ImagePickerMethodCallContext { result, error in | ||
| received = result | ||
| receivedError = error | ||
| } | ||
| plugin.sendCallResult(withSavedPathList: pathList) | ||
| plugin.sendCallResult(withSavedPathList: pathList as NSArray?) | ||
| return (received, receivedError) | ||
| } | ||
|
|
||
| @Test func pluginMultiImagePathHasNullItem() { | ||
| let plugin = FLTImagePickerPlugin(viewProvider: StubViewProvider()) | ||
| let plugin = ImagePickerPlugin(viewProvider: StubViewProvider()) | ||
| let (_, error) = captureSendResult(plugin, pathList: [NSNull()]) | ||
| #expect(error?.code == "create_error") | ||
| } |
There was a problem hiding this comment.
Since we updated sendCallResult(withSavedPathList:) to accept a native Swift array [String?]?, we can update captureSendResult and the tests to use native Swift optionals instead of NSArray and NSNull.
| private func captureSendResult( | |
| _ plugin: FLTImagePickerPlugin, pathList: [Any]? | |
| _ plugin: ImagePickerPlugin, pathList: [Any]? | |
| ) -> (result: [String]?, error: FlutterError?) { | |
| var received: [String]? | |
| var receivedError: FlutterError? | |
| plugin.callContext = FLTImagePickerMethodCallContext { result, error in | |
| plugin.callContext = ImagePickerMethodCallContext { result, error in | |
| received = result | |
| receivedError = error | |
| } | |
| plugin.sendCallResult(withSavedPathList: pathList) | |
| plugin.sendCallResult(withSavedPathList: pathList as NSArray?) | |
| return (received, receivedError) | |
| } | |
| @Test func pluginMultiImagePathHasNullItem() { | |
| let plugin = FLTImagePickerPlugin(viewProvider: StubViewProvider()) | |
| let plugin = ImagePickerPlugin(viewProvider: StubViewProvider()) | |
| let (_, error) = captureSendResult(plugin, pathList: [NSNull()]) | |
| #expect(error?.code == "create_error") | |
| } | |
| private func captureSendResult( | |
| _ plugin: ImagePickerPlugin, pathList: [String?]? | |
| ) -> (result: [String]?, error: FlutterError?) { | |
| var received: [String]? | |
| var receivedError: FlutterError? | |
| plugin.callContext = ImagePickerMethodCallContext { result, error in | |
| received = result | |
| receivedError = error | |
| } | |
| plugin.sendCallResult(withSavedPathList: pathList) | |
| return (received, receivedError) | |
| } | |
| @Test func pluginMultiImagePathHasNullItem() { | |
| let plugin = ImagePickerPlugin(viewProvider: StubViewProvider()) | |
| let (_, error) = captureSendResult(plugin, pathList: [nil]) | |
| #expect(error?.code == "create_error") | |
| } |
There was a problem hiding this comment.
Done. captureSendResult takes [String?]?, and the null-item test passes [nil].
| confirmed() | ||
| } | ||
| plugin.sendCallResult(withSavedPathList: ["a", "b"]) | ||
| plugin.sendCallResult(withSavedPathList: ["a", "b"] as NSArray) |
There was a problem hiding this comment.
Done. That call uses the [String?]? parameter
| confirmed() | ||
| } | ||
| plugin.sendCallResult(withSavedPathList: ["a", "b"]) | ||
| plugin.sendCallResult(withSavedPathList: ["a", "b"] as NSArray) |
There was a problem hiding this comment.
Done. That call uses the [String?]? parameter
…kUTType code paths (#13224) With Xcode 27 the `xcode analyze` step of `Mac_arm64 ios_platform_tests` fails on image_picker_ios: ``` FLTImagePickerImageUtil.m:132:37: error: 'kUTTypeGIF' is deprecated: first deprecated in iOS 15.0 - Use UTTypeGIF or UTType.gif (swift) instead. [-Werror,-Wdeprecated-declarations] 132 | gifTypeIdentifier = (NSString *)kUTTypeGIF; ``` Staging run on Xcode 27 (27A266a): https://ci.chromium.org/b/8668491298933206513 `kUTTypeGIF` is only referenced in the `else` branch of an `if (@available(iOS 14.0, *))` check (added in #10848), so it never runs on iOS 14+. The compiler still has to compile that branch though, and Xcode 27 only supports deployment targets of iOS 15 and up, so the plugin is now always built with `-target …-ios15.0` and the reference trips `-Wdeprecated-declarations`, which `xcode analyze` treats as an error. The build stops at the first failing file; `FLTImagePickerPhotoAssetUtil.m` has the same pattern, and `FLTImagePickerPlugin.m` uses `kUTTypeImage` / `kUTTypeMovie` unconditionally. Flutter 3.47 dropped iOS 13 and 14, so rather than keep those code paths alive this raises the package minimum to Flutter 3.47 / Dart 3.13 and iOS 15 (podspec and `Package.swift`), and deletes the iOS 13 branches: `UTTypeGIF`, `UTTypeImage` and `UTTypeMovie` are used directly. Clients on older Flutter stay on the previous version through `pub`, so this is a patch bump, same as #10231 did for iOS 13. The remaining `@available(iOS 13/14, *)` checks in `FLTImagePickerPlugin.m` are now dead too; I left them alone since that file is being rewritten in Swift in #13235 and they can go there. Also updates the app-facing `image_picker` README's support table to iOS 15 (with a `## NEXT` entry, no version bump), the same way #10470 did for iOS 13. Verified on Xcode 27 (with the earlier, fallback-preserving version of this change): `xcode analyze`, `xcode analyze deprecation` and the native tests pass for image_picker_ios — https://ci.chromium.org/b/8668086845504323249 (shard 3 of a staging replay; the remaining `native test` failure in that build is in_app_purchase_storekit, flutter/flutter#194285). Part of flutter/flutter#194019 ## Pre-Review Checklist Test exemption: native-only change with no behaviour change; the existing GIF tests in `RunnerTests/ImageUtilTests.swift` and `RunnerTests/PhotoAssetUtilTests.swift` already exercise both call sites. [^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.
| imagePickerController.delegate = self | ||
| var mediaTypes: [String] = [] | ||
| if context.includeImages { | ||
| mediaTypes.append(kUTTypeImage as String) |
There was a problem hiding this comment.
There was a problem hiding this comment.
launchUIImagePicker now uses UTType.image.identifier and UTType.movie.identifier, matching what landed in #13224. Rebased onto that. 0.8.13+12 is the published iOS 15 bump, so this PR is 0.8.13+13
7b356b6 to
5a4cee4
Compare
| } | ||
|
|
||
| /// Production implementation that forwards to UIImagePickerController. | ||
| struct DefaultCameraAvailability: CameraAvailabilityChecking { |
There was a problem hiding this comment.
nit: rename struct to DefaultCameraAvailabilityChecking or rename protocol to CameraAvailability
There was a problem hiding this comment.
Renamed the struct to DefaultCameraAvailabilityChecker. That matches DefaultCameraPermissionChecker and DefaultPhotoLibraryPermissionChecker. The protocol stays CameraAvailabilityChecking
| var imageQuality: NSNumber? | ||
|
|
||
| /// Maximum number of items to select. 0 indicates no maximum. | ||
| var maxItemCount: Int = 0 |
There was a problem hiding this comment.
Done. var maxItemCount = 0
| } | ||
| } | ||
|
|
||
| @available(iOS 14, *) |
There was a problem hiding this comment.
i think our minimum is already 15 so you can remove this
There was a problem hiding this comment.
Removed @available(iOS 14, *) from launchPHPicker. The deployment target is iOS 15, so that method can still call the PHPicker helpers
|
|
||
| public func pickImage( | ||
| withSource source: FLTSourceSpecification, maxSize: FLTMaxSize, quality imageQuality: NSNumber?, | ||
| fullMetadata: Bool, completion: @escaping (String?, FlutterError?) -> Void |
There was a problem hiding this comment.
nit: separate lines for these params
There was a problem hiding this comment.
Done. pickImage, pickMultiImage, and pickVideo each take one parameter per line, and swift-format lint --strict keeps that wrapping
| if (paths?.count ?? 0) > 1 { | ||
| completion( | ||
| nil, | ||
| FlutterError( |
There was a problem hiding this comment.
the indentation has been insane. does completion(nil, FlutterError( pass the linter?
There was a problem hiding this comment.
Yes. swift-format lint --strict accepts completion(nil, FlutterError(. That indent is the formatter’s wrap, so I left it
There was a problem hiding this comment.
Can you reduce the indentation given that it passes the check?
There was a problem hiding this comment.
Done. The FlutterError is built first, and the call is completion(nil, invalidResult). swift-format lint --strict still passes
|
|
||
| func checkCameraAuthorization( | ||
| with imagePickerController: UIImagePickerController, | ||
| camera device: UIImagePickerController.CameraDevice |
There was a problem hiding this comment.
Done. The parameter is cameraDevice
| cameraPermissionChecker.requestAccess(for: .video) { granted in | ||
| DispatchQueue.main.async { | ||
| if granted { | ||
| self.showCamera(device, with: imagePickerController) |
There was a problem hiding this comment.
you will need to put it in outer closure (requestAccess) rather than the inner one (async)
There was a problem hiding this comment.
Done. [weak self] is on the requestAccess closure, and the main-queue hop uses self?
| photoLibraryPermissionChecker.requestAuthorization { status in | ||
| DispatchQueue.main.async { | ||
| if status == .authorized { | ||
| self.showPhotoLibrary(with: imagePickerController) |
There was a problem hiding this comment.
Done. [weak self] is on requestAuthorization as well
| switch status { | ||
| case .restricted: | ||
| sendCallResult( | ||
| with: FlutterError( |
There was a problem hiding this comment.
does sendCallResult(with: FlutterError( pass linter?
There was a problem hiding this comment.
Yes. swift-format lint --strict accepts sendCallResult(with: FlutterError(. Same formatter wrap as the completion call
| let lock = NSLock() | ||
|
|
||
| let sendListOperation = BlockOperation { | ||
| lock.lock() |
There was a problem hiding this comment.
why is lock required? Is saveError and pathList accessed in multiple queues?
There was a problem hiding this comment.
Yes. savedPathBlock runs on PHPicker’s private queue, and those save operations run concurrently, so pathList and saveError are written from more than one thread. The main queue operation copies both under the same lock before it calls sendCallResult
There was a problem hiding this comment.
Can you leave a comment there?
There was a problem hiding this comment.
i assume it's also in objc code?
There was a problem hiding this comment.
Left a comment at the lock. The Objective-C implementation wrote pathList and saveError from savedPathBlock with no lock. The completions still run concurrently on PHPicker's private queue, and the main-queue operation reads both values, so the Swift port locks those writes
…instead of NSArray. Refactor tests to handle optional strings and ensure compatibility with new type definitions.
…tional headers for Swift compatibility. This change ensures that the necessary Objective-C headers are accessible for the Swift plugin, facilitating the use of the Pigeon API and related helpers.
…d Swift compatibility. This change replaces the excluded header file in Package.swift and updates the umbrella header in ImagePickerPlugin.modulemap to ensure proper integration with Swift.
…ethod signatures for clarity. Renamed `DefaultCameraAvailability` to `DefaultCameraAvailabilityChecker` and adjusted related references. Enhanced `FlutterResultAdapter` typealias for better readability and updated method parameters in `ImagePickerPlugin` for consistency.
5a4cee4 to
d9c7b29
Compare
…ed paths correctly. Calls single-item completions once when multiple paths are returned, ensuring proper error handling. Refactor tests to reflect this change.
main migrated the image_picker_ios plugin class to Swift (flutter#13235). Moves the recent media implementation into ImagePickerPlugin.swift, adds the RecentAssetsFetching and ThumbnailRequesting seams as Swift protocols, and adds the access-level methods to PhotoLibraryPermissionChecking.
flutter/packages@93baed9...108dad0 2026-10-22 [email protected] [material_ui] Migrate M3 IconButton template to use new gen_defaults (flutter/packages#12922) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationBar template to use new gen_defaults (flutter/packages#13067) 2026-10-22 [email protected] [material_ui] Remove obsolete `SurfaceTint` defaults template (flutter/packages#13276) 2026-10-22 [email protected] [material_ui] Migrate M3 Radio template to use new gen_defaults (flutter/packages#13210) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationDrawer template to use new gen_defaults (flutter/packages#13068) 2026-10-22 [email protected] [image_picker_ios] PR 3/5 Split SPM packaging and migrate the plugin class to Swift (flutter/packages#13235) 2026-10-22 [email protected] [ci] Increase check-discovery timeout in release workflows (flutter/packages#13392) 2026-10-22 [email protected] [material_ui] Migrate M3 `Switch` template to use new gen_defaults (flutter/packages#13274) 2026-10-22 [email protected] [material_ui] Migrate M3 PopupMenu template to use new gen_defaults (flutter/packages#13209) 2026-10-22 [email protected] [material_ui] Add day and weekday builders to CalendarDatePicker and showDatePicker (flutter/packages#12587) 2026-10-22 [email protected] [material_ui] Migrate M3 `SearchView` template to use new gen_defaults (flutter/packages#13272) 2026-10-22 [email protected] [material_ui] Migrate M3 `TextField` template to use new gen_defaults (flutter/packages#13275) 2026-10-22 [email protected] [material_ui] Migrate M3 RangeSlider template to use new gen_defaults (flutter/packages#13215) 2026-10-22 [email protected] [go_router] Keep web autocomplete focused in shell routes (flutter/packages#13348) 2026-10-22 [email protected] [shared_preferences_android] Fix web compilation of apps that import the package (flutter/packages#13380) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationRail template to use new gen_defaults (flutter/packages#13069) 2026-10-22 [email protected] [material_ui] Migrate M3 SearchBar template to use new gen_defaults (flutter/packages#13216) 2026-10-22 [email protected] [material_ui] Fix for time picker error in locales that do not use Latin digits (flutter/packages#13035) 2026-10-22 [email protected] [material_ui] Fix MenuAnchor scrollbar safe-area padding (flutter/packages#12470) 2026-10-22 [email protected] [material_ui] Document Material 3 fallback for Divider.color and VerticalDivider.color (flutter/packages#12967) 2026-10-22 [email protected] [material_ui] Migrate M3 tabs template to use new gen_defaults (flutter/packages#13139) 2026-10-22 [email protected] [material_ui] Migrate M3 progress indicator defaults to new gen_defaults (flutter/packages#13026) 2026-10-22 [email protected] [google_sign_in] Convert the iOS example app and UI tests to Swift (flutter/packages#13271) 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
Resolves conflicts with flutter#13235, which moved the Objective-C sources to the image_picker_ios_objc target and migrated the plugin class to Swift: - Moves this change to 0.8.13+14, above main's 0.8.13+13 entry. - Ports the two UIImagePickerController save guards from the deleted FLTImagePickerPlugin.m to ImagePickerPlugin.swift, sending the same `invalid_image` error instead of a path list when saving fails. - Updates this change's two plugin tests to the Swift plugin class names.
flutter/packages@93baed9...108dad0 2026-10-22 [email protected] [material_ui] Migrate M3 IconButton template to use new gen_defaults (flutter/packages#12922) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationBar template to use new gen_defaults (flutter/packages#13067) 2026-10-22 [email protected] [material_ui] Remove obsolete `SurfaceTint` defaults template (flutter/packages#13276) 2026-10-22 [email protected] [material_ui] Migrate M3 Radio template to use new gen_defaults (flutter/packages#13210) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationDrawer template to use new gen_defaults (flutter/packages#13068) 2026-10-22 [email protected] [image_picker_ios] PR 3/5 Split SPM packaging and migrate the plugin class to Swift (flutter/packages#13235) 2026-10-22 [email protected] [ci] Increase check-discovery timeout in release workflows (flutter/packages#13392) 2026-10-22 [email protected] [material_ui] Migrate M3 `Switch` template to use new gen_defaults (flutter/packages#13274) 2026-10-22 [email protected] [material_ui] Migrate M3 PopupMenu template to use new gen_defaults (flutter/packages#13209) 2026-10-22 [email protected] [material_ui] Add day and weekday builders to CalendarDatePicker and showDatePicker (flutter/packages#12587) 2026-10-22 [email protected] [material_ui] Migrate M3 `SearchView` template to use new gen_defaults (flutter/packages#13272) 2026-10-22 [email protected] [material_ui] Migrate M3 `TextField` template to use new gen_defaults (flutter/packages#13275) 2026-10-22 [email protected] [material_ui] Migrate M3 RangeSlider template to use new gen_defaults (flutter/packages#13215) 2026-10-22 [email protected] [go_router] Keep web autocomplete focused in shell routes (flutter/packages#13348) 2026-10-22 [email protected] [shared_preferences_android] Fix web compilation of apps that import the package (flutter/packages#13380) 2026-10-22 [email protected] [material_ui] Migrate M3 NavigationRail template to use new gen_defaults (flutter/packages#13069) 2026-10-22 [email protected] [material_ui] Migrate M3 SearchBar template to use new gen_defaults (flutter/packages#13216) 2026-10-22 [email protected] [material_ui] Fix for time picker error in locales that do not use Latin digits (flutter/packages#13035) 2026-10-22 [email protected] [material_ui] Fix MenuAnchor scrollbar safe-area padding (flutter/packages#12470) 2026-10-22 [email protected] [material_ui] Document Material 3 fallback for Divider.color and VerticalDivider.color (flutter/packages#12967) 2026-10-22 [email protected] [material_ui] Migrate M3 tabs template to use new gen_defaults (flutter/packages#13139) 2026-10-22 [email protected] [material_ui] Migrate M3 progress indicator defaults to new gen_defaults (flutter/packages#13026) 2026-10-22 [email protected] [google_sign_in] Convert the iOS example app and UI tests to Swift (flutter/packages#13271) 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
…eration, and image utilities to Swift (#13394) Migrates the Objective-C helpers that `ImagePickerPlugin` calls into the Swift target: * `FIPViewProvider` becomes `ViewProvider` / `DefaultViewProvider`. * `FLTPHPickerSaveImageToPathOperation` becomes `PHPickerSaveImageToPathOperation`. * `FLTImagePickerImageUtil`, `FLTImagePickerMetaDataUtil`, and `FLTImagePickerPhotoAssetUtil` become `ImagePickerImageUtil`, `ImagePickerMetaDataUtil`, and `ImagePickerPhotoAssetUtil`. * The `PHImageManager` seam becomes `ImageDataRequesting`. * `PHPickerResult` conforms to `PickerItem`, replacing the `BridgedPickerItem` wrapper. Deletes the custom module map and `image_picker_ios.h` umbrella header. The `image_picker_ios_objc` target remains for the Pigeon messages until the next PR. CocoaPods no longer sets `s.module_map`. Bumps image_picker_ios to **0.8.13+14**. PR 4/5 of the Obj-C → Swift migration, stacked on #13235. 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.
Splits the Swift package into a Swift target and an
image_picker_ios_objctarget. The Swift target depends on the Objective-C target, which still holds the view provider, image utilities, PHPicker save operation, and Pigeon messages. MigratesFLTImagePickerPlugintoImagePickerPluginand moves the camera, photo library, and PHPicker seams into that Swift target.pluginClassis nowImagePickerPlugin.Plugin behavior is unchanged. Bumps
image_picker_iosto 0.8.13+13.PR 3/5 of the Obj-C → Swift migration. 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