Skip to content

Swift 6 strict-concurrency fixes and Dart-owned annotation image pixel ratio - #17

Merged
esenmx merged 2 commits into
masterfrom
feat/dart-owned-image-pixel-ratio
Aug 12, 2026
Merged

Swift 6 strict-concurrency fixes and Dart-owned annotation image pixel ratio#17
esenmx merged 2 commits into
masterfrom
feat/dart-owned-image-pixel-ratio

Conversation

@esenmx

@esenmx esenmx commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Summary

Strict local Xcode 26 (Swift 6 language mode) couldn't build the plugin at all — the first blocker was MainActor-isolated UIScreen.main inside the nonisolated PlatformScreen.scale. Peeling that back surfaced a chain of strict-concurrency errors (delegate conformances, registrar Sendability, MKMapView-touching polyline helpers, pigeon-generated completion captures), and the correct fix for the original blocker turned out to be a real API improvement rather than a workaround: Dart now owns the pixel ratio for annotation images instead of reading it off the platform screen.

Changes

Swift 6 strict-concurrency fixes (minimal, each annotated with a comment stating the main-thread guarantee it encodes):

Symbol Fix
CLLocationManagerDelegate on FlutterMapView @preconcurrency conformance
FlutterPlatformView on MapKitViewHost @preconcurrency conformance
Registrar hand-off in plugin registration (MapKitPlugin.swift) nonisolated(unsafe)
MKPolyline.contains / .meters extension helpers @MainActor

Dart-owned image pixel ratio (the Flutterish replacement for the deprecated UIScreen.main lookup):

  • New optional imagePixelRatio field on the icon wire format (pigeons/messages.dart, messages.g.dart).
  • MKAnnotationIcon.image(png, {imagePixelRatio}) defaults to the implicit view's devicePixelRatio when omitted.
  • MKAnnotationIcon.asset now passes the resolved variant's key.scale as imagePixelRatio — this is a real behavior fix, not just plumbing: a 2x asset selected on a 3x device was previously decoded at the wrong ratio.
  • Snapshot scale reads mapView.traitCollection.displayScale instead of the deleted PlatformScreen.
  • Pigeon bumped 27.1.027.3.0. Regenerating now requires manual re-application of three things to messages.g.swift, documented in the pigeons/messages.dart header: the O(N) deepEquals dictionary-lookup branch (stock pigeon emits O(N·M) and silently reverts the 0.3.4 perf fix), @Sendable on MapKitFlutterApi completions (Xcode 26+ rejects a plain completion captured in the channel reply closure), and copying the result over darwin/mapkit_flutter/'s checked-in copy.
  • While touching the pigeon output, found and fixed real drift: the darwin and ios copies of messages.g.swift had silently diverged since 0.3.4.

Test plan

  • flutter analyze clean (package and example)
  • 144 tests pass
  • Example iOS simulator build green (Xcode 26.6, local)
  • Example macOS build green (Xcode 26.6, local)
  • CI on the older toolchain (expected green, not yet run)

Notes

Marker icons and default-path image icons are unchanged on 1x/2x/3x-matched setups. The only visible behavior change is correct sizing when an asset variant's scale doesn't match the screen's scale, and macOS image sizing now uses the Dart-supplied ratio instead of NSScreen.main.

🤖 Generated with Claude Code

esenmx and others added 2 commits August 12, 2026 16:22
Xcode 26's Swift-6 language mode rejected patterns the older CI
toolchain accepted:
- registrar hand-off into MainActor.assumeIsolated during plugin
  registration, marked nonisolated(unsafe) — registration never
  leaves the main thread, it just isn't Sendable-provable
- FlutterMapView's CLLocationManagerDelegate conformance, now
  @preconcurrency — callbacks arrive on the thread that created the
  manager, which is main
- MKPolyline.contains/meters touching MKMapView geometry from a
  nonisolated extension, now @mainactor since the sole caller
  TouchHandler already is

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces native UIScreen.main/NSScreen.main scale lookup
(PlatformScreen, deleted) with a Dart-supplied imagePixelRatio on the
icon wire format — Flutter owns device pixel ratio, matching how
first-party map plugins pass bitmap scale.

- MKAnnotationIcon.image gains optional imagePixelRatio, defaulting
  to the implicit view's devicePixelRatio
- MKAnnotationIcon.asset passes the resolved asset variant's
  key.scale, so a 2x asset on a 3x device decodes at its true ratio
  (previously always screen scale)
- Snapshot scale now reads the map view's traitCollection.displayScale
  instead of UIScreen.main
- pigeon bumped 27.1.0 -> 27.3.0; regenerated messages.g.swift
  re-applies the O(N) deepEquals dictionary patch and marks FlutterApi
  completions @sendable (both now documented in the schema header)
- darwin copy of messages.g.swift synced with ios (drifted since 0.3.4)
- new unit tests cover serialization, defaulting, equality of the ratio

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@esenmx
esenmx merged commit 938ab04 into master Aug 12, 2026
7 checks passed
@esenmx
esenmx deleted the feat/dart-owned-image-pixel-ratio branch August 12, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant