Sitelet https://github.com/flutter/packages/pull/12713
Skip to content

[google_maps_flutter] Convert heatmap controller to Swift - #12713

Merged
auto-submit[bot] merged 18 commits into
flutter:mainfrom
stuartmorgan-g:maps-swift-heatmaps-and-utils
Sep 4, 2026
Merged

auto-submit[bot] merged 18 commits into
flutter:mainfrom
stuartmorgan-g:maps-swift-heatmaps-and-utils

Conversation

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator

This converts HeatmapController and the remaining utility functions to Swift in the _sdk* packages.

The final remaining Obj-C code will be migrated in a follow-up PRs.

The conversion process was:

  • Initial conversion via Gemini, with explicit instruction to keep the structure the same.
  • Side-by-side manual review of the old and new versions of the files.
  • Manual fixes and improvements.

The conversion code utils have much more change than previous PRs, since the direct conversion code felt very non-idiomatic in Swift. Almost all of the free functions for Pigeon<->Maps SDK type conversions were converted to extensions on the Pigeon types:

  • To avoid the fragile pattern of putting extension methods on types we don't control (which can lead to collisions), all the extensions are on the Pigeon types, and so the APIs aren't symmetrical:
    • Maps -> Pigeon is done via a convenience constructor (generally called make(from:)
    • Pigeon -> Maps is done via a toMapsSDKClassName() method on the Pigeon type (I'm not sold on that naming pattern; alternate suggestions welcome)
  • Conversions functions that were array-based have been changed to single-element conversions following the pattern above, and then the call sites changed to just map that conversion function, since map is a simple and idiomatic pattern in Swift, unlike the loop-and-add construction that had been required in Obj-C.
    • This in turn caused some tests to be simplified, since we didn't need to test things like the number of list items converted, and can instead just test the individual conversion.

The test bridging header is removed since there are no longer any _Test headers.

Part of flutter/flutter#119108

Pre-Review Checklist

Footnotes

  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. ↩ ↩2

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request converts the heatmap controller and data conversion logic from Objective-C to Swift across the iOS packages (sdk9, sdk10, and shared_code), removing several Objective-C files in favor of Swift implementations. The review feedback highlights critical safety issues, pointing out potential runtime crashes from unsafely unwrapping optional values like heatmap.gradient and heatmap.weightedData. Additionally, the reviewer suggests performance optimizations, such as avoiding unnecessary CLLocation heap allocations by passing CLLocationCoordinate2D directly to path-creation helpers, and refactoring redundant image loading logic in ImageUtils.swift.

Comment on lines +89 to +97
var gmsMapViewType: GMSMapViewType {
switch self {
case .none: return .none
case .normal: return .normal
case .satellite: return .satellite
case .terrain: return .terrain
case .hybrid: return .hybrid
@unknown default: return .normal
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

With this being a var, is it set once and then never changed? Is it possible for the map type to change?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's just a var because that's the syntax for a computed property; because there's no set defined for it, it's not actually assignable. FGMPlatformMapType is an enum, so an individual instance of it can't change value.

self.heatmapTileLayer = tileLayer
self.mapView = mapView
super.init()
HeatmapController.update(tileLayer, from: heatmap, mapView: mapView)

Copy link
Copy Markdown
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 to pass self.tileLayer?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

self.heatmapTypeLayer and tileLayer are the same at this point, so it doesn't actually matter which is passed.


var image: UIImage?

switch bitmap {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add back comment

Suggested change
switch bitmap {
// See comment in messages.dart for why this is so loosely typed. See also
// https://github.com/flutter/flutter/issues/117819.
switch bitmap {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. I caught that in the conversion utils, but missed it here.

(Also, good news: this problem is fixed in the next PR, since Swift Pigeon supports a limited form of class hierarchy for this use case.)

case let bitmap as FGMPlatformBitmapBytes:
// Deprecated: This message handling for 'fromBytes' has been replaced by 'bytes'.
// Refer to the flutter google_maps_flutter_platform_interface package for details.
image = UIImage(data: bitmap.byteData.data, scale: screenScale)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the try catch not necessary here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

You can't catch NSExceptions in Swift, so if UIImage's constructor can leak NSExceptions in current versions of iOS, Apple has done something very wrong 🙂

A Swift do/catch would catch Swift errors, but this constructor can't throw those because it's not marked as throws.

}
case let bitmap as FGMPlatformBitmapBytesMap:
let bytes = bitmap.byteData
image = UIImage(data: bytes.data, scale: screenScale)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Try catch not required?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same.

@vashworth

Copy link
Copy Markdown
Contributor

Some tests are failing

00:13 +33 ~5: GroundOverlay set ground overlays correctly
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following _TypeError was thrown running a test:
type 'int' is not a subtype of type 'double?' in type cast

When the exception was thrown, this was the stack:
#0      PlatformBitmapDefaultMarker.decode (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2375:55)
#1      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2997:44)
#2      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#3      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#4      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#5      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#6      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2995:38)
#7      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#8      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#9      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#10     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#11     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2979:45)
#12     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#13     StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#14     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#15     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#16     StandardMessageCodec.decodeMessage (package:flutter/src/services/message_codecs.dart:342:28)
#17     BasicMessageChannel.send (package:flutter/src/services/platform_channel.dart:241:18)
<asynchronous suspension>
#18     MapsInspectorApi.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:4216:33)
<asynchronous suspension>
#19     GoogleMapsInspectorIOS.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/google_map_inspector_ios.dart:107:54)
<asynchronous suspension>
#20     main.<anonymous closure>.<anonymous closure> (file:///Volumes/Work/s/w/ir/x/w/packages/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart:1602:57)
<asynchronous suspension>
#21     testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:192:15)
<asynchronous suspension>
#22     TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1980:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

The test description was:
  set ground overlays correctly
════════════════════════════════════════════════════════════════════════════════════════════════════
00:16 +33 ~5 -1: GroundOverlay set ground overlays correctly [E]
  Test failed. See exception logs above.
  The test description was: set ground overlays correctly
  
00:16 +33 ~5 -1: GroundOverlay update ground overlays correctly
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following _TypeError was thrown running a test:
type 'int' is not a subtype of type 'double?' in type cast

When the exception was thrown, this was the stack:
#0      PlatformBitmapDefaultMarker.decode (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2375:55)
#1      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2997:44)
#2      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#3      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#4      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#5      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#6      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2995:38)
#7      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#8      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#9      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#10     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#11     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2979:45)
#12     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#13     StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#14     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#15     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#16     StandardMessageCodec.decodeMessage (package:flutter/src/services/message_codecs.dart:342:28)
#17     BasicMessageChannel.send (package:flutter/src/services/platform_channel.dart:241:18)
<asynchronous suspension>
#18     MapsInspectorApi.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:4216:33)
<asynchronous suspension>
#19     GoogleMapsInspectorIOS.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/google_map_inspector_ios.dart:107:54)
<asynchronous suspension>
#20     main.<anonymous closure>.<anonymous closure> (file:///Volumes/Work/s/w/ir/x/w/packages/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart:1675:57)
<asynchronous suspension>
#21     testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:192:15)
<asynchronous suspension>
#22     TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1980:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

The test description was:
  update ground overlays correctly
════════════════════════════════════════════════════════════════════════════════════════════════════
00:19 +33 ~5 -2: GroundOverlay update ground overlays correctly [E]
  Test failed. See exception logs above.
  The test description was: update ground overlays correctly
  

@stuartmorgan-g stuartmorgan-g left a comment •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Some tests are failing

Ha. This is a fun little reminder of why we should be moving to Swift, where we have strong uniform typing 🙂

FGMPlatformBitmap *placeholderImage =
    [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]];
let placeholderImage = FGMPlatformBitmap.make(
  withBitmap: FGMPlatformBitmapDefaultMarker.make(withHue: 0))

Looks the same, right? Only, because hue is a nullable double in the Pigeon definition, the Obj-C FGMPlatformBitmap has to declare it as an NSNumber*, not a double. So in the Obj-C, 0 was actually a misspelling of nil... which didn't matter, because they are both just integers.

But in Swift, 0 is an integer in an NSNumber context, so is equivalent to the Obj-C @(0), and since the 0 is an int, it gets encoded with the wrong type, and so explodes on the Dart side.

Fixed by correcting the spelling of nil. (The potential for this kind of problem is eliminated in the next PR, when all of these data classes become Swift.)

Comment on lines +89 to +97
var gmsMapViewType: GMSMapViewType {
switch self {
case .none: return .none
case .normal: return .normal
case .satellite: return .satellite
case .terrain: return .terrain
case .hybrid: return .hybrid
@unknown default: return .normal
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's just a var because that's the syntax for a computed property; because there's no set defined for it, it's not actually assignable. FGMPlatformMapType is an enum, so an individual instance of it can't change value.

self.heatmapTileLayer = tileLayer
self.mapView = mapView
super.init()
HeatmapController.update(tileLayer, from: heatmap, mapView: mapView)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

self.heatmapTypeLayer and tileLayer are the same at this point, so it doesn't actually matter which is passed.


var image: UIImage?

switch bitmap {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. I caught that in the conversion utils, but missed it here.

(Also, good news: this problem is fixed in the next PR, since Swift Pigeon supports a limited form of class hierarchy for this use case.)

case let bitmap as FGMPlatformBitmapBytes:
// Deprecated: This message handling for 'fromBytes' has been replaced by 'bytes'.
// Refer to the flutter google_maps_flutter_platform_interface package for details.
image = UIImage(data: bitmap.byteData.data, scale: screenScale)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

You can't catch NSExceptions in Swift, so if UIImage's constructor can leak NSExceptions in current versions of iOS, Apple has done something very wrong 🙂

A Swift do/catch would catch Swift errors, but this constructor can't throw those because it's not marked as throws.

}
case let bitmap as FGMPlatformBitmapBytesMap:
let bytes = bitmap.byteData
image = UIImage(data: bytes.data, scale: screenScale)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Same.

@vashworth

Copy link
Copy Markdown
Contributor

Tests still failing:

The following _TypeError was thrown running a test:
type 'int' is not a subtype of type 'double?' in type cast

When the exception was thrown, this was the stack:
#0      PlatformBitmapDefaultMarker.decode (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2375:55)
#1      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2997:44)
#2      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#3      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#4      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#5      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#6      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2995:38)
#7      StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#8      StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#9      _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#10     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#11     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:2979:45)
#12     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#13     StandardMessageCodec.readValueOfType (package:flutter/src/services/message_codecs.dart:525:23)
#14     _PigeonCodec.readValueOfType (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:3011:22)
#15     StandardMessageCodec.readValue (package:flutter/src/services/message_codecs.dart:480:12)
#16     StandardMessageCodec.decodeMessage (package:flutter/src/services/message_codecs.dart:342:28)
#17     BasicMessageChannel.send (package:flutter/src/services/platform_channel.dart:241:18)
<asynchronous suspension>
#18     MapsInspectorApi.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/messages.g.dart:4216:33)
<asynchronous suspension>
#19     GoogleMapsInspectorIOS.getGroundOverlayInfo (package:google_maps_flutter_ios_sdk10/src/google_map_inspector_ios.dart:107:54)
<asynchronous suspension>
#20     main.<anonymous closure>.<anonymous closure> (file:///Volumes/Work/s/w/ir/x/w/packages/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart:1602:57)
<asynchronous suspension>
#21     testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:192:15)
<asynchronous suspension>
#22     TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1980:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

The test description was:
  set ground overlays correctly

@stuartmorgan-g

Copy link
Copy Markdown
Collaborator Author

I forgot to sync the last changes to the other copies.

(Who came up with this crazy multi-copy system? 🙃)

@vashworth vashworth added the autosubmit Merge PR when tree becomes green via auto submit App label Sep 3, 2026
@auto-submit
auto-submit Bot merged commit 0ad8af3 into flutter:main Sep 4, 2026
13 checks passed
pull Bot pushed a commit to Mattlk13/flutter that referenced this pull request Sep 9, 2026
…er#192485)

flutter/packages@9af9c60...36e088a

2026-09-09 daniel.leon@cloudsufi.com [quick_actions] Adopt code-excerpts
for README (flutter/packages#12643)
2026-09-08 65155920+0xharkirat@users.noreply.github.com [camera_web] Fix
TypeError when reading the torch capability (flutter/packages#12647)
2026-09-08 gibbonsj97@gmail.com [google_maps_flutter_web] Avoid
replacing advanced marker content on move (flutter/packages#11952)
2026-09-08 mit@google.com [material_ui][cupertino_ui] Change issue
tracker label in pubspec.yaml (flutter/packages#12792)
2026-09-08 saurabhmirajkar000@gmail.com [material_ui] Fix FilledButton
Material 3 default style docs (flutter/packages#12620)
2026-09-08 21270878+elliette@users.noreply.github.com [infra] Use a
modified no-response workflow in flutter/packages
(flutter/packages#12745)
2026-09-08 21270878+elliette@users.noreply.github.com [material_ui]
Migrate M3 Banner template to use new gen_defaults
(flutter/packages#12734)
2026-09-08 engine-flutter-autoroll@skia.org Roll Flutter from
63170e9 to b444e78 (13 revisions) (flutter/packages#12791)
2026-09-08 fluttergithubbot@gmail.com Sync release-go_router-18.0.1 to
main (flutter/packages#12725)
2026-09-08 fluttergithubbot@gmail.com Sync release-material_ui-1.1.1 to
main (flutter/packages#12726)
2026-09-08 stuartmorgan@google.com [tool] Adopt `platform` 3.2.0
(flutter/packages#12789)
2026-09-07 50643541+Mairramer@users.noreply.github.com [material_ui] Fix
SliverGeometry maxPaintExtent assertion in CarouselView.weighted
(flutter/packages#12563)
2026-09-05 engine-flutter-autoroll@skia.org Roll Flutter from
5a6cfa7 to 63170e9 (15 revisions) (flutter/packages#12767)
2026-09-04 engine-flutter-autoroll@skia.org Manual roll Flutter from
70797e1 to 5a6cfa7 (52 revisions) (flutter/packages#12760)
2026-09-04 brackenavaron@gmail.com [material_ui] port drawer tests over
from flutter/widgets (flutter/packages#12711)
2026-09-04 tarrinneal@gmail.com add cooldown (flutter/packages#12708)
2026-09-04 joeldumasbg@gmail.com [in_app_purchase] Support StoreKit 2
introductory offer eligibility JWS (flutter/packages#12584)
2026-09-04 21270878+elliette@users.noreply.github.com [material_ui]
Migrate M3 Badge template to use new gen_defaults
(flutter/packages#12733)
2026-09-04 stuartmorgan@google.com [google_maps_flutter] Convert heatmap
controller to Swift (flutter/packages#12713)
2026-09-04 97480502+b-luk@users.noreply.github.com [material_ui] Remove
unused `maintainState` constructor parameter in `scaffold_test.dart`
(flutter/packages#12754)
2026-09-04 a1rwulf@users.noreply.github.com [video_player_avfoundation]
Route video over AirPlay (flutter/packages#12490)
2026-09-04 jerome.dellamaria@proton.me [google_fonts] Add
google_fonts_lite file to allow tree-shaking of the other huge files
(flutter/packages#11433)
2026-09-04 engine-flutter-autoroll@skia.org Roll Flutter from
0cbd1a4 to 70797e1 (27 revisions) (flutter/packages#12727)
2026-09-04 stuartmorgan@google.com Update Chrome for stable tests
(flutter/packages#12747)

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 flutter-ecosystem@google.com 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
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
)

This converts HeatmapController and the remaining utility functions to Swift in the `_sdk*` packages.

The final remaining Obj-C code will be migrated in a follow-up PRs.

The conversion process was:
- Initial conversion via Gemini, with explicit instruction to keep the structure the same.
- Side-by-side manual review of the old and new versions of the files.
- Manual fixes and improvements.

The conversion code utils have much more change than previous PRs, since the direct conversion code felt very non-idiomatic in Swift. Almost all of the free functions for Pigeon<->Maps SDK type conversions were converted to extensions on the Pigeon types:
- To avoid the fragile pattern of putting extension methods on types we don't control (which can lead to collisions), all the extensions are on the Pigeon types, and so the APIs aren't symmetrical:
  - Maps -> Pigeon is done via a convenience constructor (generally called `make(from:)`
  - Pigeon -> Maps is done via a `toMapsSDKClassName()` method on the Pigeon type (I'm not sold on that naming pattern; alternate suggestions welcome)
- Conversions functions that were array-based have been changed to single-element conversions following the pattern above, and then the call sites changed to just `map` that conversion function, since `map` is a simple and idiomatic pattern in Swift, unlike the loop-and-add construction that had been required in Obj-C.
  - This in turn caused some tests to be simplified, since we didn't need to test things like the number of list items converted, and can instead just test the individual conversion.

The test bridging header is removed since there are no longer any `_Test` headers.

Part of flutter/flutter#119108

## Pre-Review Checklist

[^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.
victorsanni pushed a commit to victorsanni/packages that referenced this pull request Sep 9, 2026
)

This converts HeatmapController and the remaining utility functions to Swift in the `_sdk*` packages.

The final remaining Obj-C code will be migrated in a follow-up PRs.

The conversion process was:
- Initial conversion via Gemini, with explicit instruction to keep the structure the same.
- Side-by-side manual review of the old and new versions of the files.
- Manual fixes and improvements.

The conversion code utils have much more change than previous PRs, since the direct conversion code felt very non-idiomatic in Swift. Almost all of the free functions for Pigeon<->Maps SDK type conversions were converted to extensions on the Pigeon types:
- To avoid the fragile pattern of putting extension methods on types we don't control (which can lead to collisions), all the extensions are on the Pigeon types, and so the APIs aren't symmetrical:
  - Maps -> Pigeon is done via a convenience constructor (generally called `make(from:)`
  - Pigeon -> Maps is done via a `toMapsSDKClassName()` method on the Pigeon type (I'm not sold on that naming pattern; alternate suggestions welcome)
- Conversions functions that were array-based have been changed to single-element conversions following the pattern above, and then the call sites changed to just `map` that conversion function, since `map` is a simple and idiomatic pattern in Swift, unlike the loop-and-add construction that had been required in Obj-C.
  - This in turn caused some tests to be simplified, since we didn't need to test things like the number of list items converted, and can instead just test the individual conversion.

The test bridging header is removed since there are no longer any `_Test` headers.

Part of flutter/flutter#119108

## Pre-Review Checklist

[^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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App CICD Run CI/CD p: google_maps_flutter platform-ios

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants