[iOS] SymbolLayer silently dropped from style when textFont is set
还没有人认领这个 Issue。
评估
调研方向
从 _onStyleLoaded 复现和 map.style.addLayer 调用开始,然后将 iOS 对 SymbolLayer.textFont 的处理与所描述的 Android 行为进行比较。运行提供的 flutter run 命令,并验证在标签使用回退字体渲染时,通过立即和延迟的 getLayer 调用都仍能获取该图层。
由索引模型根据 Issue 内容生成。
描述
Summary
On iOS, setting SymbolLayer.textFont causes the entire layer to be silently dropped from the rendered style. The Dart-side addLayer call returns success, but the layer never persists in the style. Visual: the labels never render. Programmatic: subsequent calls to setStyleLayerProperty against that layer id throw PlatformException(0, "Layer ... is not in style").
Android renders the same SymbolLayer correctly with textFont set, on the same mapbox_maps_flutter versions. Android falls back to its default sans-serif when the requested font isn't bundled (I/Mbgl-FontUtils: Couldn't map font family for local ideograph, using sans-serif instead), but the layer renders.
This is the same failure pattern as the lineDasharray LineLayer bug (filed separately) and exhibits the same symptom mutation across versions:
| Version | Symptom |
|---|---|
| 2.12.0 | addLayer returns ok → style.getLayer(id) returns null immediately → labels do not render |
| 2.21.1 | addLayer returns ok → style.getLayer(id) returns the layer at the immediate audit → layer disappears from the style a few milliseconds later → labels do not render |
The pattern of silent failure is identical for both bugs, suggesting a shared underlying defect in the iOS-side layer-add path that's specific to certain layout properties.
Affected versions
mapbox_maps_flutter2.12.0 — confirmed broken (Sep 2024 era)mapbox_maps_flutter2.21.1 — confirmed broken with mutated symptom (current latest at time of filing)
Tested on:
- iPhone 17, iOS 26.3.1, Xcode 26.3
- Compared against: moto g play 2024, Android 14 (API 34) — works correctly on both versions (with sans-serif fallback)
Flutter:
- Original: 3.24.5 / Dart 3.5.4
- Retest: 3.41.6
Minimal reproduction
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';
void main() {
MapboxOptions.setAccessToken(const String.fromEnvironment('MAPBOX_TOKEN'));
runApp(const MaterialApp(home: BugRepro()));
}
class BugRepro extends StatefulWidget {
const BugRepro({super.key});
@override
State<BugRepro> createState() => _BugReproState();
}
class _BugReproState extends State<BugRepro> {
static const _sourceId = 'repro-source';
static const _layerId = 'repro-symbol-layer';
@override
Widget build(BuildContext context) => Scaffold(
body: MapWidget(
styleUri: MapboxStyles.SATELLITE_STREETS,
cameraOptions: CameraOptions(
center: Point(coordinates: Position(-122.4885, 37.6244)),
zoom: 15,
),
onStyleLoadedListener: (_) => _onStyleLoaded(),
onMapCreated: (map) => _map = map,
),
);
MapboxMap? _map;
Future<void> _onStyleLoaded() async {
final map = _map;
if (map == null) return;
// A few Point features with a `label` property to render as text.
final geojson = jsonEncode({
'type': 'FeatureCollection',
'features': [
for (var i = 1; i <= 5; i++)
{
'type': 'Feature',
'properties': {'label': '$i'},
'geometry': {
'type': 'Point',
'coordinates': [-122.4885 + i * 0.0005, 37.6244],
},
},
],
});
await map.style.addSource(GeoJsonSource(id: _sourceId, data: geojson));
// The bug: setting textFont causes the SymbolLayer to silently
// disappear on iOS. Comment out the textFont line below and the
// labels render correctly (in the Mapbox default font).
await map.style.addLayer(SymbolLayer(
id: _layerId,
sourceId: _sourceId,
textFieldExpression: ['get', 'label'],
textSize: 14.0,
textColor: 0xFFFFFFFF,
textHaloColor: 0xFF000000,
textHaloWidth: 1.5,
textAllowOverlap: true,
textFont: const ['DIN Pro Bold', 'Arial Unicode MS Bold'], // ← REMOVE → bug goes away
));
// Diagnostic — same pattern as the lineDasharray bug:
final immediate = await map.style.getLayer(_layerId);
debugPrint('layer present immediately? ${immediate != null}');
await Future<void>.delayed(const Duration(milliseconds: 100));
final delayed = await map.style.getLayer(_layerId);
debugPrint('layer present after 100ms delay? ${delayed != null}');
}
}
Run with:
flutter run -d <ios-device> --dart-define=MAPBOX_TOKEN=pk.xxx
Expected behavior
The SymbolLayer is added to the style, the labels render on the map (in DIN Pro Bold if the glyph set is available, falling back to a default font if not), and subsequent getLayer(id) calls return the layer. This is what happens on Android with the exact same code.
We don't expect Mapbox to ship the DIN Pro Bold font itself — the textFont array is conventionally a fallback chain, and we'd expect either successful resolution to a fallback font OR a clear error at add time. What we get instead is the entire layer silently disappearing with no error and no callback.
Actual behavior
On iOS, with textFont set to ANY value (we tested ['DIN Pro Bold', 'Arial Unicode MS Bold'], ['Arial Unicode MS Bold'], and ['Open Sans Regular'] — all three reproduce):
- The labels never render visually.
- On 2.12.0: the
layer present immediately?debug print outputsfalse. - On 2.21.1: the
layer present immediately?print outputstrue, butlayer present after 100ms delay?printsfalse.
Workaround
Don't set textFont on SymbolLayer cross-platform. The labels will render in the Mapbox default font for the active style — for SATELLITE_STREETS this is a Mapbox-hosted sans-serif which is visually acceptable but does not match the iOS native app's typeface choice.
If matching a specific custom font is a hard requirement: bundle the font as a local glyph PBF set and use style.setStyleGlyphURL(url) instead of the per-layer textFont property. This appears to be the only currently-working path for custom fonts on iOS.
Why the symptom mutation matters
Same as for the related lineDasharray bug filed separately: the audit pattern (getLayer after addLayer) that catches this in user code on 2.12.0 silently passes on 2.21.1, even though the bug is still present. Whatever change was made in the intervening 9 months made the failure asynchronous. Code that defends against the original bug shape no longer detects the new one.
Filing both bugs together (cross-referenced) so a fix can address the underlying cause rather than chasing the surface symptoms one property at a time.
Related
Same set as for the lineDasharray issue:
- #568 — Adding GeoJSON Layer in onMapCreated is unreliable
- #527 —
getLayer("puck") throws "Layer puck is not in style"
Spike report context
This issue was filed during a Flutter migration spike for an existing dual-native (Swift + Kotlin) app, alongside the related LineLayer.lineDasharray issue. Both bugs prevent 1:1 visual parity with the native iOS Mapbox SDK. Full report: https://github.com/oshelot/Caddie-AI/blob/kan-252-flutter-spike/flutter-spike/SPIKE_REPORT.md
Happy to provide additional logs, a smaller repro, or test on additional iOS versions if helpful.
- 主要语言
- Dart
- 星标
- 380
- 派生
- 204
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
mapbox/mapbox-maps-flutter 的其他 Issue
-
难度 4/5 3-5 天 新手友好度 45/100
mapbox/mapbox-maps-flutter#1144 ·
-
iOS: the map cannot be captured or read by flutter, because it is a platform view可能已有人在做 @Nixxx19 于 51 天前认领。 未关闭
难度 5/5 一周以上 新手友好度 25/100
mapbox/mapbox-maps-flutter#1142 ·
-
难度 3/5 1-2 天 新手友好度 58/100
mapbox/mapbox-maps-flutter#1140 ·
-
Normalize ornament positioning relative to safe areas on iOS and Android可能重新可做 @maios 于 95 天前认领,目前没有进行中的 PR。 未关闭
mapbox/mapbox-maps-flutter#1137 · 1 条评论 · 1 个 reaction · 已指派 1 人 ·
-
难度 3/5 1-2 天 新手友好度 48/100
mapbox/mapbox-maps-flutter#1136 · 1 条评论 ·
查看 mapbox/mapbox-maps-flutter 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 67/100
-
bug good first issue
难度 2/5 1-3 小时 新手友好度 82/100
basictech01/uniun#300 ·
维护者通常 1 天内回复
-
Listener that removes itself in its callback causes other listeners to miss updates可能已有人在做 @RaphaelFakhri 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 84/100
RevenueCat/purchases-flutter#1962 ·
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 67/100
维护者通常 5 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 70/100
jhomlala/betterplayer#1609 ·
维护者通常 1 天内回复