expo-gaode-map 2.2.43-next.0 → 2.2.44-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- #Wed Jul 15 10:15:05 CST 2026
1
+ #Thu Jul 16 13:17:48 CST 2026
2
2
  gradle.version=8.9
@@ -13,6 +13,12 @@ import UIKit
13
13
  * - 支持自定义 children 视图
14
14
  */
15
15
  class MarkerView: ExpoView {
16
+ private struct ChildrenSnapshotRequest {
17
+ let size: CGSize
18
+ let signature: String
19
+ let cacheKey: String
20
+ }
21
+
16
22
  // MARK: - 事件派发器(专属事件名避免冲突)
17
23
  var onMarkerPress = EventDispatcher()
18
24
  var onMarkerDragStart = EventDispatcher()
@@ -84,6 +90,8 @@ class MarkerView: ExpoView {
84
90
  private var pendingDetachCheckTask: DispatchWorkItem?
85
91
  /// 最近一次应用到 annotationView 的 children 结构签名
86
92
  private var lastRenderedChildrenSignature: String?
93
+ /// 最近一次应用到 annotationView 的 children 快照缓存 key
94
+ private var lastRenderedChildrenCacheKey: String?
87
95
  /// 最近一次成功渲染的 children 图片,用于缓存未命中时避免闪烁
88
96
  private var lastRenderedChildrenImage: UIImage?
89
97
  /// 上次设置的地图引用(防止重复调用)
@@ -124,7 +132,7 @@ class MarkerView: ExpoView {
124
132
  return
125
133
  }
126
134
 
127
- scheduleChildrenImageRefresh(invalidateChildrenCache: true)
135
+ scheduleChildrenImageRefresh(invalidateChildrenCache: !hasExplicitChildrenCacheKey)
128
136
  }
129
137
 
130
138
  /**
@@ -178,7 +186,7 @@ class MarkerView: ExpoView {
178
186
  guard cacheKey != key else { return }
179
187
  self.cacheKey = key
180
188
  if !subviews.isEmpty {
181
- scheduleChildrenImageRefresh(invalidateChildrenCache: true)
189
+ scheduleChildrenImageRefresh(invalidateChildrenCache: !hasExplicitChildrenCacheKey)
182
190
  } else {
183
191
  refreshAnnotationAppearance()
184
192
  }
@@ -255,11 +263,14 @@ class MarkerView: ExpoView {
255
263
 
256
264
  // 1. 如果有 children,使用自定义视图
257
265
  if self.subviews.count > 0 {
258
- let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
259
- let key = childrenCacheKey(for: size)
260
- if let cached = IconBitmapCache.shared.image(forKey: key) {
266
+ let request = makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 60))
267
+ if request.cacheKey == lastRenderedChildrenCacheKey, annotationView?.image != nil {
268
+ return annotationView
269
+ }
270
+
271
+ if let cached = IconBitmapCache.shared.image(forKey: request.cacheKey) {
261
272
  if let annotationView = annotationView {
262
- applyChildrenImage(cached, to: annotationView, signature: childrenRenderSignature())
273
+ applyChildrenImage(cached, to: annotationView, request: request)
263
274
  }
264
275
  return annotationView
265
276
  }
@@ -268,8 +279,14 @@ class MarkerView: ExpoView {
268
279
  DispatchQueue.main.async { [weak self, weak annotationView] in
269
280
  guard let self = self, let annotationView = annotationView else { return }
270
281
  guard self.isAnnotationView(annotationView, boundTo: annotation) else { return }
271
- if let generated = self.createImageFromSubviews(size: size) {
272
- self.applyChildrenImage(generated, to: annotationView, signature: self.childrenRenderSignature())
282
+ let request = self.makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 60))
283
+ if request.cacheKey == self.lastRenderedChildrenCacheKey, annotationView.image != nil {
284
+ return
285
+ }
286
+ if let cached = IconBitmapCache.shared.image(forKey: request.cacheKey) {
287
+ self.applyChildrenImage(cached, to: annotationView, request: request)
288
+ } else if let generated = self.createImageFromSubviews(request: request) {
289
+ self.applyChildrenImage(generated, to: annotationView, request: request)
273
290
  }
274
291
  }
275
292
  return annotationView
@@ -349,23 +366,24 @@ class MarkerView: ExpoView {
349
366
  annotationView?.isDraggable = draggable
350
367
  self.annotationView = annotationView
351
368
 
352
- // 生成 cacheKey fallback identifier
353
- let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
354
- let key = childrenCacheKey(for: size)
355
- let signature = childrenRenderSignature()
369
+ let request = makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 40))
370
+
371
+ if request.cacheKey == lastRenderedChildrenCacheKey, annotationView?.image != nil {
372
+ return annotationView
373
+ }
356
374
 
357
375
  // 1) 如果缓存命中,直接同步返回图像(fast path)
358
- if let cached = IconBitmapCache.shared.image(forKey: key) {
376
+ if let cached = IconBitmapCache.shared.image(forKey: request.cacheKey) {
359
377
  if let annotationView = annotationView {
360
- applyChildrenImage(cached, to: annotationView, signature: signature)
378
+ applyChildrenImage(cached, to: annotationView, request: request)
361
379
  }
362
380
  return annotationView
363
381
  }
364
382
 
365
383
  // 2) 缓存未命中:先尝试同步渲染,失败时保留旧图,避免点击切态闪烁。
366
- if let generated = createImageFromSubviews(size: size) {
384
+ if let generated = createImageFromSubviews(request: request) {
367
385
  if let annotationView = annotationView {
368
- applyChildrenImage(generated, to: annotationView, signature: signature)
386
+ applyChildrenImage(generated, to: annotationView, request: request)
369
387
  }
370
388
  return annotationView
371
389
  }
@@ -381,15 +399,19 @@ class MarkerView: ExpoView {
381
399
  DispatchQueue.main.async { [weak self, weak annotationView] in
382
400
  guard let self = self, let annotationView = annotationView else { return }
383
401
  guard self.isAnnotationView(annotationView, boundTo: annotation) else { return }
402
+ let request = self.makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 40))
403
+ if request.cacheKey == self.lastRenderedChildrenCacheKey, annotationView.image != nil {
404
+ return
405
+ }
384
406
  // 再次检查缓存(避免重复渲染)
385
- if let cached = IconBitmapCache.shared.image(forKey: key) {
386
- self.applyChildrenImage(cached, to: annotationView, signature: signature)
407
+ if let cached = IconBitmapCache.shared.image(forKey: request.cacheKey) {
408
+ self.applyChildrenImage(cached, to: annotationView, request: request)
387
409
  return
388
410
  }
389
411
 
390
412
  // 调用你的原生渲染逻辑(保留空白检测、多次 layout)
391
- if let generated = self.createImageFromSubviews(size: size) {
392
- self.applyChildrenImage(generated, to: annotationView, signature: signature)
413
+ if let generated = self.createImageFromSubviews(request: request) {
414
+ self.applyChildrenImage(generated, to: annotationView, request: request)
393
415
  } else if self.hasPendingImageContent() {
394
416
  self.scheduleSubviewRefresh(allowFallbackToDefault: false)
395
417
  }
@@ -527,11 +549,8 @@ class MarkerView: ExpoView {
527
549
  /**
528
550
  * 将子视图转换为图片
529
551
  */
530
- private func createImageFromSubviews(size explicitSize: CGSize? = nil, cacheImage: Bool = true) -> UIImage? {
531
- let size = explicitSize ?? resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
532
- let key = childrenCacheKey(for: size)
533
-
534
- if cacheImage, let cachedImage = IconBitmapCache.shared.image(forKey: key) {
552
+ private func createImageFromSubviews(request: ChildrenSnapshotRequest, cacheImage: Bool = true) -> UIImage? {
553
+ if cacheImage, let cachedImage = IconBitmapCache.shared.image(forKey: request.cacheKey) {
535
554
  return cachedImage
536
555
  }
537
556
 
@@ -539,12 +558,12 @@ class MarkerView: ExpoView {
539
558
  return nil
540
559
  }
541
560
 
542
- guard size.width > 0, size.height > 0 else {
561
+ guard request.size.width > 0, request.size.height > 0 else {
543
562
  return nil
544
563
  }
545
564
 
546
565
  // 强制子视图使用指定尺寸布局
547
- firstSubview.frame = CGRect(origin: .zero, size: size)
566
+ firstSubview.frame = CGRect(origin: .zero, size: request.size)
548
567
 
549
568
  // 在 React Native 完成当前挂载批次后执行一次确定性布局。
550
569
  // 后续布局变化会再次合并触发快照,不需要阻塞主 RunLoop 猜测内容何时就绪。
@@ -554,7 +573,7 @@ class MarkerView: ExpoView {
554
573
  return nil
555
574
  }
556
575
 
557
- UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
576
+ UIGraphicsBeginImageContextWithOptions(request.size, false, 0.0)
558
577
  defer { UIGraphicsEndImageContext() }
559
578
 
560
579
  guard let _ = UIGraphicsGetCurrentContext() else {
@@ -562,7 +581,7 @@ class MarkerView: ExpoView {
562
581
  }
563
582
 
564
583
  // 使用 drawHierarchy 而不是 layer.render,这样能正确渲染 Text
565
- firstSubview.drawHierarchy(in: CGRect(origin: .zero, size: size), afterScreenUpdates: true)
584
+ firstSubview.drawHierarchy(in: CGRect(origin: .zero, size: request.size), afterScreenUpdates: true)
566
585
 
567
586
  guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
568
587
  return nil
@@ -571,13 +590,17 @@ class MarkerView: ExpoView {
571
590
 
572
591
 
573
592
  if cacheImage {
574
- IconBitmapCache.shared.setImage(image, forKey: key)
593
+ IconBitmapCache.shared.setImage(image, forKey: request.cacheKey)
575
594
  }
576
595
 
577
596
  return image
578
597
  }
579
598
 
580
- private func applyChildrenImage(_ image: UIImage, to annotationView: MAAnnotationView, signature: String? = nil) {
599
+ private func applyChildrenImage(
600
+ _ image: UIImage,
601
+ to annotationView: MAAnnotationView,
602
+ request: ChildrenSnapshotRequest
603
+ ) {
581
604
  CATransaction.begin()
582
605
  CATransaction.setDisableActions(true)
583
606
  UIView.performWithoutAnimation {
@@ -589,9 +612,8 @@ class MarkerView: ExpoView {
589
612
  }
590
613
  CATransaction.commit()
591
614
  lastRenderedChildrenImage = image
592
- if let resolvedSignature = signature {
593
- lastRenderedChildrenSignature = resolvedSignature
594
- }
615
+ lastRenderedChildrenSignature = request.signature
616
+ lastRenderedChildrenCacheKey = request.cacheKey
595
617
  }
596
618
 
597
619
  private func currentChildrenAnnotationView() -> MAAnnotationView? {
@@ -632,8 +654,10 @@ class MarkerView: ExpoView {
632
654
  return
633
655
  }
634
656
 
635
- if invalidateChildrenCache {
657
+ let shouldInvalidateCache = invalidateChildrenCache && !self.hasExplicitChildrenCacheKey
658
+ if shouldInvalidateCache {
636
659
  self.lastRenderedChildrenSignature = nil
660
+ self.lastRenderedChildrenCacheKey = nil
637
661
  self.invalidateCurrentChildrenCache()
638
662
  }
639
663
 
@@ -642,25 +666,27 @@ class MarkerView: ExpoView {
642
666
  return
643
667
  }
644
668
 
645
- let size = self.resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
646
- let key = self.childrenCacheKey(for: size)
647
- let signature = self.childrenRenderSignature()
669
+ let request = self.makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 40))
670
+
671
+ if request.cacheKey == self.lastRenderedChildrenCacheKey, targetView.image != nil {
672
+ return
673
+ }
648
674
 
649
- if cacheImage, let cached = IconBitmapCache.shared.image(forKey: key) {
675
+ if cacheImage, let cached = IconBitmapCache.shared.image(forKey: request.cacheKey) {
650
676
  if let expectedGeneration,
651
677
  self.childrenRefreshGeneration != expectedGeneration {
652
678
  return
653
679
  }
654
- self.applyChildrenImage(cached, to: targetView, signature: signature)
680
+ self.applyChildrenImage(cached, to: targetView, request: request)
655
681
  return
656
682
  }
657
683
 
658
- if let generated = self.createImageFromSubviews(size: size, cacheImage: cacheImage) {
684
+ if let generated = self.createImageFromSubviews(request: request, cacheImage: cacheImage) {
659
685
  if let expectedGeneration,
660
686
  self.childrenRefreshGeneration != expectedGeneration {
661
687
  return
662
688
  }
663
- self.applyChildrenImage(generated, to: targetView, signature: signature)
689
+ self.applyChildrenImage(generated, to: targetView, request: request)
664
690
  return
665
691
  }
666
692
 
@@ -711,6 +737,11 @@ class MarkerView: ExpoView {
711
737
  return "\(baseKey)|\(Int(iconWidth.rounded()))x\(Int(iconHeight.rounded()))"
712
738
  }
713
739
 
740
+ private var hasExplicitChildrenCacheKey: Bool {
741
+ guard let cacheKey else { return false }
742
+ return !cacheKey.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
743
+ }
744
+
714
745
  private func applyCenterOffset(to annotationView: MAAnnotationView, defaultOffset: CGPoint) {
715
746
  annotationView.centerOffset = resolvedCenterOffset(defaultOffset: defaultOffset)
716
747
  }
@@ -789,13 +820,22 @@ class MarkerView: ExpoView {
789
820
  return fallback
790
821
  }
791
822
 
792
- private func childrenCacheKey(for size: CGSize) -> String {
793
- let signature = childrenRenderSignature()
794
- let baseKey = cacheKey.map { "\($0)|\(signature)" }
823
+ private func makeChildrenSnapshotRequest(
824
+ size explicitSize: CGSize? = nil,
825
+ defaultSize: CGSize
826
+ ) -> ChildrenSnapshotRequest {
827
+ let size = explicitSize ?? resolvedContentSubviewSize(defaultSize: defaultSize)
828
+ let explicitCacheKey = hasExplicitChildrenCacheKey ? cacheKey : nil
829
+ let signature = explicitCacheKey ?? childrenRenderSignature()
830
+ let baseKey = explicitCacheKey
795
831
  ?? "children_\(ObjectIdentifier(self).hashValue)|\(signature)"
796
832
  let roundedWidth = Int(ceil(size.width))
797
833
  let roundedHeight = Int(ceil(size.height))
798
- return "\(baseKey)|\(roundedWidth)x\(roundedHeight)"
834
+ return ChildrenSnapshotRequest(
835
+ size: size,
836
+ signature: signature,
837
+ cacheKey: "\(baseKey)|\(roundedWidth)x\(roundedHeight)"
838
+ )
799
839
  }
800
840
 
801
841
  private func childrenRenderSignature() -> String {
@@ -945,6 +985,7 @@ class MarkerView: ExpoView {
945
985
  animatedAnnotationView = nil
946
986
  lastRenderedChildrenImage = nil
947
987
  lastRenderedChildrenSignature = nil
988
+ lastRenderedChildrenCacheKey = nil
948
989
  isAnimating = false
949
990
  lastSetMapView = nil
950
991
  self.mapView = nil
@@ -1006,6 +1047,7 @@ class MarkerView: ExpoView {
1006
1047
  if subviews.isEmpty {
1007
1048
  if allowFallbackToDefault {
1008
1049
  lastRenderedChildrenSignature = nil
1050
+ lastRenderedChildrenCacheKey = nil
1009
1051
  annotationView = nil
1010
1052
  mapView.removeAnnotation(annotation)
1011
1053
  mapView.addAnnotation(annotation)
@@ -1013,8 +1055,8 @@ class MarkerView: ExpoView {
1013
1055
  return
1014
1056
  }
1015
1057
 
1016
- let signature = childrenRenderSignature()
1017
- if signature == lastRenderedChildrenSignature, annotationView?.image != nil {
1058
+ let request = makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 40))
1059
+ if request.cacheKey == lastRenderedChildrenCacheKey, annotationView?.image != nil {
1018
1060
  return
1019
1061
  }
1020
1062
 
@@ -1033,20 +1075,21 @@ class MarkerView: ExpoView {
1033
1075
  return
1034
1076
  }
1035
1077
 
1036
- let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
1037
- if let image = createImageFromSubviews(size: size) {
1038
- applyChildrenImage(image, to: annotationView, signature: signature)
1078
+ if let image = createImageFromSubviews(request: request) {
1079
+ applyChildrenImage(image, to: annotationView, request: request)
1039
1080
  }
1040
1081
  }
1041
1082
 
1042
1083
  private func invalidateCurrentChildrenCache() {
1043
- let sizes = [
1044
- resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40)),
1045
- resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
1084
+ guard !hasExplicitChildrenCacheKey else { return }
1085
+
1086
+ let requests = [
1087
+ makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 40)),
1088
+ makeChildrenSnapshotRequest(defaultSize: CGSize(width: 200, height: 60))
1046
1089
  ]
1047
1090
 
1048
- for size in sizes {
1049
- IconBitmapCache.shared.removeImage(forKey: childrenCacheKey(for: size))
1091
+ for request in requests {
1092
+ IconBitmapCache.shared.removeImage(forKey: request.cacheKey)
1050
1093
  }
1051
1094
  }
1052
1095
 
@@ -1058,8 +1101,10 @@ class MarkerView: ExpoView {
1058
1101
 
1059
1102
  self.cancelPendingSubviewRefresh()
1060
1103
 
1061
- if invalidateChildrenCache {
1104
+ let shouldInvalidateCache = invalidateChildrenCache && !self.hasExplicitChildrenCacheKey
1105
+ if shouldInvalidateCache {
1062
1106
  self.lastRenderedChildrenSignature = nil
1107
+ self.lastRenderedChildrenCacheKey = nil
1063
1108
  if !self.subviews.isEmpty {
1064
1109
  self.invalidateCurrentChildrenCache()
1065
1110
  }
@@ -1202,7 +1247,7 @@ class MarkerView: ExpoView {
1202
1247
  guard contentWidth != width else { return }
1203
1248
  contentWidth = width
1204
1249
  if !subviews.isEmpty {
1205
- scheduleChildrenImageRefresh(invalidateChildrenCache: true)
1250
+ scheduleChildrenImageRefresh(invalidateChildrenCache: !hasExplicitChildrenCacheKey)
1206
1251
  }
1207
1252
  }
1208
1253
 
@@ -1210,7 +1255,7 @@ class MarkerView: ExpoView {
1210
1255
  guard contentHeight != height else { return }
1211
1256
  contentHeight = height
1212
1257
  if !subviews.isEmpty {
1213
- scheduleChildrenImageRefresh(invalidateChildrenCache: true)
1258
+ scheduleChildrenImageRefresh(invalidateChildrenCache: !hasExplicitChildrenCacheKey)
1214
1259
  }
1215
1260
  }
1216
1261
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "2.2.43-next.0",
3
+ "version": "2.2.44-next.0",
4
4
  "description": "Expo Modules AMap (Gaode Map) stack for Expo/React Native: Config Plugin, New Architecture support, maps, location, search, offline maps, and react-native-amap3d migration guidance.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",