mapbox / mapbox/mapbox-maps-ios
MapView never renders in CarPlay dashboard/instrument-cluster scenes — parentScene resolves nil for non-CPWindow CarPlay windows
Nobody has claimed this yet.
- Dominant language
- Swift
- Stars
- 601
- Forks
- 196
- PR merge metrics
- No merged PRs in 30d
Description
**Environment**
- MapboxMaps 11.18.3 (also present in current `main`)
- iOS 18.x, CarPlay navigation app (`com.apple.developer.carplay-maps`), real head unit
**Summary**
A `MapView` placed in the CarPlay **dashboard** scene (`CPTemplateApplicationDashboardScene`, iOS ≥ 13.4) or **instrument-cluster** scene never draws a single frame — the Metal view stays transparent/black while sibling UIKit views in the same window render normally. The head-unit (`CPTemplateApplicationScene`) map is unaffected.
**Root cause (traced in SDK source)**
`MapView` only runs its display link while `shouldRunDisplayLink(for: window?.parentScene)` is true, and `updateFromDisplayLink` re-pauses on every frame when it is false (`Sources/MapboxMaps/Foundation/MapView.swift`).
`UIWindow.parentScene` (`Sources/MapboxMaps/Foundation/Extensions/UIWindow+ParentScene.swift`) resolves:
```swift
switch self {
case let carPlayWindow as CPWindow:
return carPlayWindow.templateApplicationScene // head unit — works
default:
return windowScene // typed UIWindowScene?
}
```
The dashboard window handed to `CPTemplateApplicationDashboardSceneDelegate.templateApplicationDashboardScene(_:didConnect:to:)` is a **plain `UIWindow`** (not a `CPWindow`) attached to a scene that is **not a `UIWindowScene`**, so `windowScene` is nil → `parentScene` is nil → `shouldRunDisplayLink(nil)` returns false → the display link never starts, and the scene-activation notification path can't rescue it because the per-frame check re-pauses immediately.
Notably, the `UIScene.allWindows` helper **in the same file** already knows about both scene types:
```swift
if let carPlayDashboardScene = self as? CPTemplateApplicationDashboardScene {
return [carPlayDashboardScene.dashboardWindow]
}
```
— only `parentScene` misses the reverse mapping.
**Suggested fix**
In the `default:` branch, fall back to scanning connected scenes with the existing helper when `windowScene` is nil:
```swift
default:
if let scene = windowScene { return scene }
return UIApplication.shared.connectedScenes.first { $0.allWindows.contains(self) }
```
We are running exactly this as a local pod patch and the dashboard map renders correctly with it. (If per-frame cost is a concern, the result could be cached per window — the per-frame `updateFromDisplayLink` check calls `parentScene` on every tick.)
**Repro sketch**
1. CarPlay nav app with a dashboard scene declared (`CPSupportsDashboardNavigationScene`).
2. In the dashboard scene delegate, add any `MapView` to the provided window's root view controller.
3. Attach a dashboard-capable head unit (the simulator cannot display the dashboard scene; a real car or the standalone CarPlay Simulator app is required).
4. Result: UIKit siblings render; the map never paints. Breakpoint in `updateFromDisplayLink` confirms `window?.parentScene == nil` → immediate pause.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Sources/MapboxMaps/Foundation/Extensions/UIWindow+ParentScene.swift and inspect the existing UIScene.allWindows helper, then trace its use from Sources/MapboxMaps/Foundation/MapView.swift in updateFromDisplayLink. Reproduce with a real dashboard or instrument-cluster CarPlay scene and verify that MapView renders there while the head-unit scene remains unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ios, swift
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100