expo-gaode-map 2.2.38 → 2.2.39-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.
- package/android/build.gradle +6 -31
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapView.kt +35 -12
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapViewModule.kt +2 -0
- package/android/src/main/java/expo/modules/gaodemap/managers/UIManager.kt +8 -0
- package/android/src/main/java/expo/modules/gaodemap/overlays/MarkerView.kt +13 -5
- package/build/ExpoGaodeMapOfflineModule.js +1 -1
- package/build/ExpoGaodeMapOfflineModule.js.map +1 -1
- package/build/ExpoGaodeMapView.js +2 -8
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/AreaMaskOverlay.d.ts +1 -2
- package/build/components/AreaMaskOverlay.d.ts.map +1 -1
- package/build/components/AreaMaskOverlay.js +2 -1
- package/build/components/AreaMaskOverlay.js.map +1 -1
- package/build/components/FoldableMapView.d.ts +3 -2
- package/build/components/FoldableMapView.d.ts.map +1 -1
- package/build/components/FoldableMapView.js +2 -1
- package/build/components/FoldableMapView.js.map +1 -1
- package/build/components/MapUI.js +2 -1
- package/build/components/MapUI.js.map +1 -1
- package/build/components/RouteOverlay.d.ts +1 -2
- package/build/components/RouteOverlay.d.ts.map +1 -1
- package/build/components/RouteOverlay.js +5 -5
- package/build/components/RouteOverlay.js.map +1 -1
- package/build/components/overlays/Circle.d.ts +1 -1
- package/build/components/overlays/Circle.d.ts.map +1 -1
- package/build/components/overlays/Circle.js +2 -1
- package/build/components/overlays/Circle.js.map +1 -1
- package/build/components/overlays/Cluster.d.ts +1 -1
- package/build/components/overlays/Cluster.d.ts.map +1 -1
- package/build/components/overlays/Cluster.js +2 -1
- package/build/components/overlays/Cluster.js.map +1 -1
- package/build/components/overlays/HeatMap.d.ts +1 -1
- package/build/components/overlays/HeatMap.d.ts.map +1 -1
- package/build/components/overlays/HeatMap.js +2 -1
- package/build/components/overlays/HeatMap.js.map +1 -1
- package/build/components/overlays/Marker.d.ts +1 -1
- package/build/components/overlays/Marker.d.ts.map +1 -1
- package/build/components/overlays/Marker.js +8 -7
- package/build/components/overlays/Marker.js.map +1 -1
- package/build/components/overlays/MultiPoint.d.ts +1 -2
- package/build/components/overlays/MultiPoint.d.ts.map +1 -1
- package/build/components/overlays/MultiPoint.js +2 -1
- package/build/components/overlays/MultiPoint.js.map +1 -1
- package/build/components/overlays/Polygon.d.ts +1 -1
- package/build/components/overlays/Polygon.d.ts.map +1 -1
- package/build/components/overlays/Polygon.js +2 -1
- package/build/components/overlays/Polygon.js.map +1 -1
- package/build/components/overlays/Polyline.d.ts +1 -1
- package/build/components/overlays/Polyline.d.ts.map +1 -1
- package/build/components/overlays/Polyline.js +2 -1
- package/build/components/overlays/Polyline.js.map +1 -1
- package/build/module/geometry.d.ts.map +1 -1
- package/build/module/geometry.js +2 -1
- package/build/module/geometry.js.map +1 -1
- package/build/search/ExpoGaodeMapSearchModule.d.ts +1 -1
- package/build/search/ExpoGaodeMapSearchModule.d.ts.map +1 -1
- package/build/search/ExpoGaodeMapSearchModule.js.map +1 -1
- package/build/types/common.types.d.ts +1 -1
- package/build/types/common.types.d.ts.map +1 -1
- package/build/types/common.types.js.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/index.js.map +1 -1
- package/build/types/map-view.types.d.ts +11 -0
- package/build/types/map-view.types.d.ts.map +1 -1
- package/build/types/map-view.types.js.map +1 -1
- package/build/utils/GeoUtils.d.ts +2 -2
- package/build/utils/GeoUtils.d.ts.map +1 -1
- package/build/utils/GeoUtils.js +3 -3
- package/build/utils/GeoUtils.js.map +1 -1
- package/build/utils/RouteUtils.d.ts.map +1 -1
- package/build/utils/RouteUtils.js +5 -2
- package/build/utils/RouteUtils.js.map +1 -1
- package/ios/ExpoGaodeMapView.swift +106 -10
- package/ios/ExpoGaodeMapViewModule.swift +5 -0
- package/ios/overlays/MarkerView.swift +104 -32
- package/package.json +9 -7
- package/plugin/build/withGaodeMap.js +3 -2
|
@@ -77,6 +77,8 @@ class MarkerView: ExpoView {
|
|
|
77
77
|
private var pendingSubviewRefreshTask: DispatchWorkItem?
|
|
78
78
|
/// 最近一次应用到 annotationView 的 children 结构签名
|
|
79
79
|
private var lastRenderedChildrenSignature: String?
|
|
80
|
+
/// 最近一次成功渲染的 children 图片,用于缓存未命中时避免闪烁
|
|
81
|
+
private var lastRenderedChildrenImage: UIImage?
|
|
80
82
|
/// 上次设置的地图引用(防止重复调用)
|
|
81
83
|
private weak var lastSetMapView: MAMapView?
|
|
82
84
|
|
|
@@ -156,7 +158,11 @@ class MarkerView: ExpoView {
|
|
|
156
158
|
func setCacheKey(_ key: String?) {
|
|
157
159
|
guard cacheKey != key else { return }
|
|
158
160
|
self.cacheKey = key
|
|
159
|
-
|
|
161
|
+
if !subviews.isEmpty {
|
|
162
|
+
scheduleChildrenImageRefresh()
|
|
163
|
+
} else {
|
|
164
|
+
refreshAnnotationAppearance()
|
|
165
|
+
}
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
/**
|
|
@@ -233,9 +239,8 @@ class MarkerView: ExpoView {
|
|
|
233
239
|
let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
|
|
234
240
|
let key = childrenCacheKey(for: size)
|
|
235
241
|
if let cached = IconBitmapCache.shared.image(forKey: key) {
|
|
236
|
-
annotationView?.image = cached
|
|
237
242
|
if let annotationView = annotationView {
|
|
238
|
-
|
|
243
|
+
applyChildrenImage(cached, to: annotationView, signature: childrenRenderSignature())
|
|
239
244
|
}
|
|
240
245
|
return annotationView
|
|
241
246
|
}
|
|
@@ -244,9 +249,8 @@ class MarkerView: ExpoView {
|
|
|
244
249
|
DispatchQueue.main.async { [weak self, weak annotationView] in
|
|
245
250
|
guard let self = self, let annotationView = annotationView else { return }
|
|
246
251
|
guard self.isAnnotationView(annotationView, boundTo: annotation) else { return }
|
|
247
|
-
if let generated = self.createImageFromSubviews() {
|
|
248
|
-
|
|
249
|
-
self.applyCenterOffset(to: annotationView, defaultOffset: .zero)
|
|
252
|
+
if let generated = self.createImageFromSubviews(size: size) {
|
|
253
|
+
self.applyChildrenImage(generated, to: annotationView, signature: self.childrenRenderSignature())
|
|
250
254
|
}
|
|
251
255
|
}
|
|
252
256
|
return annotationView
|
|
@@ -307,9 +311,7 @@ class MarkerView: ExpoView {
|
|
|
307
311
|
|
|
308
312
|
// 🔑 如果有 children,使用自定义视图
|
|
309
313
|
if self.subviews.count > 0 {
|
|
310
|
-
let
|
|
311
|
-
?? String(ObjectIdentifier(self).hashValue)
|
|
312
|
-
let reuseId = "custom_marker_children_\(reuseToken)" + (growAnimation ? "_grow" : "")
|
|
314
|
+
let reuseId = "custom_marker_children_\(ObjectIdentifier(self).hashValue)" + (growAnimation ? "_grow" : "")
|
|
313
315
|
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
|
|
314
316
|
if annotationView == nil {
|
|
315
317
|
if growAnimation {
|
|
@@ -331,37 +333,44 @@ class MarkerView: ExpoView {
|
|
|
331
333
|
// 生成 cacheKey 或 fallback 到 identifier
|
|
332
334
|
let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
|
|
333
335
|
let key = childrenCacheKey(for: size)
|
|
336
|
+
let signature = childrenRenderSignature()
|
|
334
337
|
|
|
335
338
|
// 1) 如果缓存命中,直接同步返回图像(fast path)
|
|
336
339
|
if let cached = IconBitmapCache.shared.image(forKey: key) {
|
|
337
|
-
annotationView?.image = cached
|
|
338
340
|
if let annotationView = annotationView {
|
|
339
|
-
|
|
341
|
+
applyChildrenImage(cached, to: annotationView, signature: signature)
|
|
340
342
|
}
|
|
341
343
|
return annotationView
|
|
342
344
|
}
|
|
343
345
|
|
|
344
|
-
// 2)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
346
|
+
// 2) 缓存未命中:先尝试同步渲染,失败时保留旧图,避免点击切态闪烁。
|
|
347
|
+
if let generated = createImageFromSubviews(size: size) {
|
|
348
|
+
if let annotationView = annotationView {
|
|
349
|
+
applyChildrenImage(generated, to: annotationView, signature: signature)
|
|
350
|
+
}
|
|
351
|
+
return annotationView
|
|
352
|
+
}
|
|
349
353
|
|
|
350
|
-
|
|
354
|
+
if annotationView?.image == nil, let previousImage = lastRenderedChildrenImage {
|
|
355
|
+
annotationView?.image = previousImage
|
|
356
|
+
if let annotationView = annotationView {
|
|
357
|
+
applyCenterOffset(to: annotationView, defaultOffset: .zero)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 图片内容可能尚未就绪,保留旧图并延迟重试,避免透明闪烁。
|
|
351
362
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self, weak annotationView] in
|
|
352
363
|
guard let self = self, let annotationView = annotationView else { return }
|
|
353
364
|
guard self.isAnnotationView(annotationView, boundTo: annotation) else { return }
|
|
354
365
|
// 再次检查缓存(避免重复渲染)
|
|
355
366
|
if let cached = IconBitmapCache.shared.image(forKey: key) {
|
|
356
|
-
|
|
357
|
-
self.applyCenterOffset(to: annotationView, defaultOffset: .zero)
|
|
367
|
+
self.applyChildrenImage(cached, to: annotationView, signature: signature)
|
|
358
368
|
return
|
|
359
369
|
}
|
|
360
370
|
|
|
361
371
|
// 调用你的原生渲染逻辑(保留空白检测、多次 layout)
|
|
362
|
-
if let generated = self.createImageFromSubviews() {
|
|
363
|
-
|
|
364
|
-
self.applyCenterOffset(to: annotationView, defaultOffset: .zero)
|
|
372
|
+
if let generated = self.createImageFromSubviews(size: size) {
|
|
373
|
+
self.applyChildrenImage(generated, to: annotationView, signature: signature)
|
|
365
374
|
} else if self.hasPendingImageContent() {
|
|
366
375
|
self.scheduleSubviewRefresh(allowFallbackToDefault: false)
|
|
367
376
|
}
|
|
@@ -499,8 +508,8 @@ class MarkerView: ExpoView {
|
|
|
499
508
|
/**
|
|
500
509
|
* 将子视图转换为图片
|
|
501
510
|
*/
|
|
502
|
-
private func createImageFromSubviews() -> UIImage? {
|
|
503
|
-
let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
|
|
511
|
+
private func createImageFromSubviews(size explicitSize: CGSize? = nil) -> UIImage? {
|
|
512
|
+
let size = explicitSize ?? resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 60))
|
|
504
513
|
let key = childrenCacheKey(for: size)
|
|
505
514
|
|
|
506
515
|
if let cachedImage = IconBitmapCache.shared.image(forKey: key) {
|
|
@@ -549,6 +558,70 @@ class MarkerView: ExpoView {
|
|
|
549
558
|
return image
|
|
550
559
|
}
|
|
551
560
|
|
|
561
|
+
private func applyChildrenImage(_ image: UIImage, to annotationView: MAAnnotationView, signature: String? = nil) {
|
|
562
|
+
annotationView.image = image
|
|
563
|
+
applyCenterOffset(to: annotationView, defaultOffset: .zero)
|
|
564
|
+
annotationView.canShowCallout = false
|
|
565
|
+
annotationView.isDraggable = draggable
|
|
566
|
+
lastRenderedChildrenImage = image
|
|
567
|
+
if let resolvedSignature = signature {
|
|
568
|
+
lastRenderedChildrenSignature = resolvedSignature
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
private func refreshChildrenImageInPlace(invalidateChildrenCache: Bool = false) {
|
|
573
|
+
guard !isRemoving else { return }
|
|
574
|
+
|
|
575
|
+
let refresh = { [weak self] in
|
|
576
|
+
guard let self = self, !self.isRemoving, !self.subviews.isEmpty else { return }
|
|
577
|
+
|
|
578
|
+
if invalidateChildrenCache {
|
|
579
|
+
self.lastRenderedChildrenSignature = nil
|
|
580
|
+
self.invalidateCurrentChildrenCache()
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
guard let targetView = self.annotationView ?? self.animatedAnnotationView else {
|
|
584
|
+
self.refreshAnnotationAppearance(invalidateChildrenCache: invalidateChildrenCache)
|
|
585
|
+
return
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
let size = self.resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
|
|
589
|
+
let key = self.childrenCacheKey(for: size)
|
|
590
|
+
let signature = self.childrenRenderSignature()
|
|
591
|
+
|
|
592
|
+
if let cached = IconBitmapCache.shared.image(forKey: key) {
|
|
593
|
+
self.applyChildrenImage(cached, to: targetView, signature: signature)
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if let generated = self.createImageFromSubviews(size: size) {
|
|
598
|
+
self.applyChildrenImage(generated, to: targetView, signature: signature)
|
|
599
|
+
return
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if self.hasPendingImageContent() {
|
|
603
|
+
self.scheduleSubviewRefresh(allowFallbackToDefault: false)
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if Thread.isMainThread {
|
|
608
|
+
refresh()
|
|
609
|
+
} else {
|
|
610
|
+
DispatchQueue.main.async(execute: refresh)
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
private func scheduleChildrenImageRefresh(invalidateChildrenCache: Bool = false) {
|
|
615
|
+
pendingSubviewRefreshTask?.cancel()
|
|
616
|
+
|
|
617
|
+
let task = DispatchWorkItem { [weak self] in
|
|
618
|
+
self?.refreshChildrenImageInPlace(invalidateChildrenCache: invalidateChildrenCache)
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
pendingSubviewRefreshTask = task
|
|
622
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.02, execute: task)
|
|
623
|
+
}
|
|
624
|
+
|
|
552
625
|
private func iconCacheKey(for iconUri: String) -> String {
|
|
553
626
|
let baseKey = cacheKey ?? "icon|\(iconUri)"
|
|
554
627
|
return "\(baseKey)|\(Int(iconWidth.rounded()))x\(Int(iconHeight.rounded()))"
|
|
@@ -769,6 +842,8 @@ class MarkerView: ExpoView {
|
|
|
769
842
|
animatedAnnotationView?.annotation = nil
|
|
770
843
|
annotationView = nil
|
|
771
844
|
animatedAnnotationView = nil
|
|
845
|
+
lastRenderedChildrenImage = nil
|
|
846
|
+
lastRenderedChildrenSignature = nil
|
|
772
847
|
isAnimating = false
|
|
773
848
|
lastSetMapView = nil
|
|
774
849
|
self.mapView = nil
|
|
@@ -850,12 +925,9 @@ class MarkerView: ExpoView {
|
|
|
850
925
|
return
|
|
851
926
|
}
|
|
852
927
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
annotationView.canShowCallout = false
|
|
857
|
-
annotationView.isDraggable = draggable
|
|
858
|
-
lastRenderedChildrenSignature = signature
|
|
928
|
+
let size = resolvedContentSubviewSize(defaultSize: CGSize(width: 200, height: 40))
|
|
929
|
+
if let image = createImageFromSubviews(size: size) {
|
|
930
|
+
applyChildrenImage(image, to: annotationView, signature: signature)
|
|
859
931
|
}
|
|
860
932
|
}
|
|
861
933
|
|
|
@@ -1023,7 +1095,7 @@ class MarkerView: ExpoView {
|
|
|
1023
1095
|
guard contentWidth != width else { return }
|
|
1024
1096
|
contentWidth = width
|
|
1025
1097
|
if !subviews.isEmpty {
|
|
1026
|
-
|
|
1098
|
+
scheduleChildrenImageRefresh(invalidateChildrenCache: true)
|
|
1027
1099
|
}
|
|
1028
1100
|
}
|
|
1029
1101
|
|
|
@@ -1031,7 +1103,7 @@ class MarkerView: ExpoView {
|
|
|
1031
1103
|
guard contentHeight != height else { return }
|
|
1032
1104
|
contentHeight = height
|
|
1033
1105
|
if !subviews.isEmpty {
|
|
1034
|
-
|
|
1106
|
+
scheduleChildrenImageRefresh(invalidateChildrenCache: true)
|
|
1035
1107
|
}
|
|
1036
1108
|
}
|
|
1037
1109
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-gaode-map",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.39-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",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"build": "expo-module build && yarn build:plugin",
|
|
19
19
|
"build:plugin": "tsc --project plugin/tsconfig.json",
|
|
20
20
|
"clean": "expo-module clean && rm -rf plugin/build",
|
|
21
|
-
"lint": "
|
|
21
|
+
"lint": "eslint \"src/**/*.{ts,tsx}\"",
|
|
22
22
|
"test": "npx jest --no-watchman --config jest.config.js --runInBand",
|
|
23
23
|
"prepare": "expo-module prepare && yarn build:plugin",
|
|
24
24
|
"postinstall": "node scripts/check-expo-modules.js",
|
|
@@ -75,13 +75,15 @@
|
|
|
75
75
|
"@babel/runtime": "^7.25.7",
|
|
76
76
|
"@testing-library/react-native": "^13.3.3",
|
|
77
77
|
"@types/jest": "^29.5.14",
|
|
78
|
+
"@types/node": "^22.18.0",
|
|
78
79
|
"@types/react": "~19.2.10",
|
|
79
|
-
"
|
|
80
|
-
"expo
|
|
80
|
+
"eslint": "^9.25.1",
|
|
81
|
+
"expo": "^57.0.1",
|
|
82
|
+
"expo-module-scripts": "^56.0.3",
|
|
81
83
|
"jest": "~29.7.0",
|
|
82
|
-
"jest-expo": "~
|
|
83
|
-
"react-native": "0.
|
|
84
|
-
"typescript": "^
|
|
84
|
+
"jest-expo": "~57.0.0",
|
|
85
|
+
"react-native": "0.86.0",
|
|
86
|
+
"typescript": "^6.0.3"
|
|
85
87
|
},
|
|
86
88
|
"peerDependencies": {
|
|
87
89
|
"expo": "*",
|
|
@@ -146,8 +146,9 @@ const withGaodeMapAndroidManifest = (config, props) => {
|
|
|
146
146
|
else {
|
|
147
147
|
// 更新现有的 API Key
|
|
148
148
|
const apiKeyIndex = mainApplication['meta-data'].findIndex((item) => item.$?.['android:name'] === 'com.amap.api.v2.apikey');
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
const apiKeyMetaData = mainApplication['meta-data'][apiKeyIndex];
|
|
150
|
+
if (apiKeyMetaData) {
|
|
151
|
+
apiKeyMetaData.$ = {
|
|
151
152
|
'android:name': 'com.amap.api.v2.apikey',
|
|
152
153
|
'android:value': props.androidKey,
|
|
153
154
|
};
|