feat(ios): render the map into a flutter texture instead of a platform view - #1143
Open
Nixxx19 wants to merge 2 commits into
Open
feat(ios): render the map into a flutter texture instead of a platform view#1143Nixxx19 wants to merge 2 commits into
Nixxx19 wants to merge 2 commits into
Conversation
|
Successfully scanned changes introduced in a pull request into Internal scan identifier:
See all issues found during this scan in the OX Security Application. Detailed information
1 aggregation
|
Nixxx19
marked this pull request as draft
August 28, 2026 10:58
Nixxx19
force-pushed
the
feat/ios-texture-mode
branch
from
August 28, 2026 11:01
7454b07 to
cfd9176
Compare
Nixxx19
marked this pull request as ready for review
August 28, 2026 11:01
|
awesome |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
closes #1142
on ios the map is a
UiKitView, so uikit composites it and it is not in flutter's scene. nothing can read it back:toImageSyncandRepaintBoundary.toImagereturn a hole where the map is, and a customImageFilter.shaderused as a backdrop samples an empty texture. android avoids this by rendering into aTextureView; ios has no equivalent because its platform views are always uikit composited (flutter/flutter#43902).this adds a texture path for ios. the map is created without a platform view and its frames go to
FlutterTextureRegistry, so the widget tree contains aTextureand nothing else.what it gives you
MapboxMapapi, style, camera, sources, layers, view annotations, and the logo and attribution.before and after
same page, same button, same code, both on an iphone. the panel on the right is the result of
RepaintBoundary.toImageon the page.MapWidget(platform view)MapTextureperformance
same device, same camera path, profile mode, frame timings from
SchedulerBinding.addTimingsCallback. a small widget repaints continuously during the run so flutter produces frames to measure.MapWidget(platform view)MapTextureraster p90 is 27% lower with the texture. ios platform view compositing splits the scene into overlay layers around the view, and a texture is one more layer in a single scene, so the per frame copy costs less than the compositing it replaces. the example app ships the page that produces these numbers, so the result is reproducible rather than quoted.
how it works
HeadlessMapTexturebuilds the ordinaryMapboxMapControllerwith a channel suffix and parks its view offscreen inside the app's own key window, so every pigeon api behaves exactly as it does for the platform view.MapTexturePublishercopies each finished frame into an IOSurface backedCVPixelBufferand hands it to the texture registry. on the dart sideMapTexturesizes the map to its constraints, forwards gestures and disposes the native map when it unmounts.three details worth calling out, because none of them is obvious:
frames are caught at
-[MTLCommandBuffer presentDrawable:].UIView.draw(_:)looks like the hook and never runs, because an MTKView renders through metal rather than core graphics. presentDrawable also lets the copy be encoded onto the same command buffer that presents it, so it is ordered after the render with no waiting.the offscreen map lives in the app's existing key window. a second
UIWindowtakes over the scene. staying composited is what keeps coreanimation recycling drawables.the logo and attribution are rasterised and drawn by flutter. they are uikit views drawn with core graphics, so they are not in the metal output. attribution is preserved.
gestures
pan, pinch, rotate and pitch are forwarded and drive the camera directly, pan through
dragCameraOptionswhich is what the sdk's own recogniser uses.scope
MapWidgetis untouched.MapTextureis additive, ios only and opt in. the 20 lines changed in existing files are an export, apart, aMapboxMap.headlessfactory and a getter onMapboxMapControllerso it can be hosted outside a platform view. nothing existing changes behaviour.tests and verification
test/map_texture_test.dart: creation at the size of its constraints, the texture rendering once the host returns an id, a unique channel suffix per map, style pass through, resize on a constraint change, disposal of the native map when it leaves the tree, gesture forwarding, and nothing forwarded when gestures are offflutter analyzeclean on every touched filefollow ups
happy to take these in this pr or later, whichever you prefer: