expo-gaode-map-navigation 1.1.5-next.1 → 1.1.5-next.3

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.
Files changed (136) hide show
  1. package/android/build.gradle +10 -0
  2. package/android/src/main/cpp/CMakeLists.txt +24 -0
  3. package/android/src/main/cpp/cluster_jni.cpp +848 -0
  4. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
  5. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
  6. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
  7. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
  8. package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
  9. package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
  10. package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
  11. package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
  12. package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
  13. package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
  14. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
  15. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
  16. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
  17. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
  18. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
  19. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
  20. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
  21. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
  22. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
  23. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
  24. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
  25. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
  26. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
  27. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
  28. package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
  29. package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
  30. package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
  31. package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
  32. package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
  33. package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
  34. package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
  35. package/build/ExpoGaodeMapNaviView.d.ts +7 -7
  36. package/build/ExpoGaodeMapNaviView.js +8 -8
  37. package/build/ExpoGaodeMapNavigationModule.d.ts +2 -1
  38. package/build/index.d.ts +35 -33
  39. package/build/index.js +70 -106
  40. package/build/map/ExpoGaodeMapModule.d.ts +2 -201
  41. package/build/map/ExpoGaodeMapModule.js +584 -14
  42. package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
  43. package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
  44. package/build/map/ExpoGaodeMapView.js +66 -58
  45. package/build/map/components/FoldableMapView.d.ts +38 -0
  46. package/build/map/components/FoldableMapView.js +209 -0
  47. package/build/map/components/MapContext.d.ts +12 -0
  48. package/build/map/components/MapContext.js +54 -0
  49. package/build/map/components/MapUI.d.ts +18 -0
  50. package/build/map/components/MapUI.js +29 -0
  51. package/build/map/components/overlays/Circle.js +34 -3
  52. package/build/map/components/overlays/Cluster.d.ts +3 -1
  53. package/build/map/components/overlays/Cluster.js +31 -2
  54. package/build/map/components/overlays/HeatMap.d.ts +3 -1
  55. package/build/map/components/overlays/HeatMap.js +33 -3
  56. package/build/map/components/overlays/Marker.d.ts +1 -1
  57. package/build/map/components/overlays/Marker.js +37 -32
  58. package/build/map/components/overlays/MultiPoint.js +1 -1
  59. package/build/map/components/overlays/Polygon.js +30 -3
  60. package/build/map/components/overlays/Polyline.js +36 -3
  61. package/build/map/index.d.ts +25 -5
  62. package/build/map/index.js +59 -18
  63. package/build/map/types/common.types.d.ts +40 -0
  64. package/build/map/types/common.types.js +0 -4
  65. package/build/map/types/index.d.ts +3 -2
  66. package/build/map/types/map-view.types.d.ts +108 -3
  67. package/build/map/types/native-module.types.d.ts +363 -0
  68. package/build/map/types/native-module.types.js +5 -0
  69. package/build/map/types/offline.types.d.ts +132 -0
  70. package/build/map/types/offline.types.js +5 -0
  71. package/build/map/types/overlays.types.d.ts +137 -24
  72. package/build/map/utils/ErrorHandler.d.ts +110 -0
  73. package/build/map/utils/ErrorHandler.js +421 -0
  74. package/build/map/utils/GeoUtils.d.ts +20 -0
  75. package/build/map/utils/GeoUtils.js +76 -0
  76. package/build/map/utils/OfflineMapManager.d.ts +148 -0
  77. package/build/map/utils/OfflineMapManager.js +217 -0
  78. package/build/map/utils/PermissionUtils.d.ts +91 -0
  79. package/build/map/utils/PermissionUtils.js +255 -0
  80. package/build/map/utils/PlatformDetector.d.ts +102 -0
  81. package/build/map/utils/PlatformDetector.js +186 -0
  82. package/build/types/index.d.ts +1 -0
  83. package/build/types/index.js +1 -0
  84. package/build/types/native-module.types.d.ts +69 -0
  85. package/build/types/native-module.types.js +2 -0
  86. package/build/types/naviview.types.d.ts +1 -1
  87. package/expo-module.config.json +12 -10
  88. package/ios/ExpoGaodeMapNavigation.podspec +9 -0
  89. package/ios/map/ExpoGaodeMapModule.swift +485 -75
  90. package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
  91. package/ios/map/ExpoGaodeMapView.swift +611 -62
  92. package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
  93. package/ios/map/MapPreloadManager.swift +348 -0
  94. package/ios/map/cpp/ClusterEngine.cpp +110 -0
  95. package/ios/map/cpp/ClusterEngine.hpp +20 -0
  96. package/ios/map/cpp/ColorParser.cpp +135 -0
  97. package/ios/map/cpp/ColorParser.hpp +14 -0
  98. package/ios/map/cpp/GeometryEngine.cpp +574 -0
  99. package/ios/map/cpp/GeometryEngine.hpp +159 -0
  100. package/ios/map/cpp/QuadTree.cpp +92 -0
  101. package/ios/map/cpp/QuadTree.hpp +42 -0
  102. package/ios/map/cpp/README.md +55 -0
  103. package/ios/map/cpp/tests/benchmark_js.js +41 -0
  104. package/ios/map/cpp/tests/run.sh +17 -0
  105. package/ios/map/cpp/tests/test_main.cpp +276 -0
  106. package/ios/map/managers/UIManager.swift +72 -1
  107. package/ios/map/modules/LocationManager.swift +114 -165
  108. package/ios/map/overlays/CircleView.swift +16 -32
  109. package/ios/map/overlays/CircleViewModule.swift +12 -12
  110. package/ios/map/overlays/ClusterAnnotation.swift +32 -0
  111. package/ios/map/overlays/ClusterView.swift +331 -45
  112. package/ios/map/overlays/ClusterViewModule.swift +20 -6
  113. package/ios/map/overlays/HeatMapView.swift +135 -32
  114. package/ios/map/overlays/HeatMapViewModule.swift +20 -8
  115. package/ios/map/overlays/MarkerView.swift +613 -130
  116. package/ios/map/overlays/MarkerViewModule.swift +38 -18
  117. package/ios/map/overlays/MultiPointView.swift +168 -10
  118. package/ios/map/overlays/MultiPointViewModule.swift +27 -5
  119. package/ios/map/overlays/PolygonView.swift +62 -23
  120. package/ios/map/overlays/PolygonViewModule.swift +18 -12
  121. package/ios/map/overlays/PolylineView.swift +21 -13
  122. package/ios/map/overlays/PolylineViewModule.swift +18 -12
  123. package/ios/map/utils/ClusterNative.h +96 -0
  124. package/ios/map/utils/ClusterNative.mm +377 -0
  125. package/ios/map/utils/ColorParser.swift +12 -1
  126. package/ios/map/utils/CppBridging.mm +13 -0
  127. package/ios/map/utils/GeometryUtils.swift +34 -0
  128. package/ios/map/utils/LatLngParser.swift +87 -0
  129. package/ios/map/utils/PermissionManager.swift +135 -6
  130. package/package.json +1 -1
  131. package/build/map/ExpoGaodeMap.types.d.ts +0 -41
  132. package/build/map/ExpoGaodeMap.types.js +0 -24
  133. package/build/map/utils/EventManager.d.ts +0 -10
  134. package/build/map/utils/EventManager.js +0 -26
  135. package/build/map/utils/ModuleLoader.d.ts +0 -73
  136. package/build/map/utils/ModuleLoader.js +0 -112
@@ -17,6 +17,9 @@ class UIManager: NSObject, MAMapViewDelegate {
17
17
  /// 定位变化回调
18
18
  var onLocationChanged: ((_ latitude: Double, _ longitude: Double, _ accuracy: Double) -> Void)?
19
19
 
20
+ /// 缓存的自定义样式配置
21
+ private var cachedCustomStyleOptions: MAMapCustomStyleOptions?
22
+
20
23
  init(mapView: MAMapView) {
21
24
  self.mapView = mapView
22
25
  super.init()
@@ -36,6 +39,13 @@ class UIManager: NSObject, MAMapViewDelegate {
36
39
  case 3: mapView.mapType = .navi
37
40
  default: mapView.mapType = .standard
38
41
  }
42
+
43
+ // 🔑 关键修复:切换地图类型后重新应用自定义样式
44
+ // 某些地图类型切换可能会重置样式设置
45
+ if let cachedOptions = cachedCustomStyleOptions {
46
+ mapView.setCustomMapStyleOptions(cachedOptions)
47
+ mapView.customMapStyleEnabled = true
48
+ }
39
49
  }
40
50
 
41
51
  // MARK: - 控件显示
@@ -109,7 +119,8 @@ class UIManager: NSObject, MAMapViewDelegate {
109
119
  }
110
120
  mapView.showsUserLocation = true
111
121
  if followUser {
112
- mapView.userTrackingMode = .follow
122
+ // 🔑 使用 followWithHeading 模式以支持方向指示器
123
+ mapView.userTrackingMode = .followWithHeading
113
124
  } else {
114
125
  mapView.userTrackingMode = .none
115
126
  }
@@ -146,6 +157,12 @@ class UIManager: NSObject, MAMapViewDelegate {
146
157
  guard let mapView = mapView else { return }
147
158
  let representation = MAUserLocationRepresentation()
148
159
 
160
+ // 是否显示定位蓝点 (showMyLocation) - 对应 Android 的 showMyLocation
161
+ // iOS 通过 mapView.showsUserLocation 控制,这里提供统一的 API
162
+ if let showMyLocation = config["showMyLocation"] as? Bool {
163
+ mapView.showsUserLocation = showMyLocation
164
+ }
165
+
149
166
  // 精度圈是否显示
150
167
  if let showsAccuracyRing = config["showsAccuracyRing"] as? Bool {
151
168
  representation.showsAccuracyRing = showsAccuracyRing
@@ -265,4 +282,58 @@ class UIManager: NSObject, MAMapViewDelegate {
265
282
  func setShowsIndoorMap(_ show: Bool) {
266
283
  mapView?.isShowsIndoorMap = show
267
284
  }
285
+
286
+ // MARK: - 自定义地图样式
287
+
288
+ /**
289
+ * 设置自定义地图样式
290
+ * @param styleData 样式数据,支持以下格式:
291
+ * - styleId: String - 在线样式ID(从高德开放平台获取)
292
+ * - styleDataPath: String - 本地样式文件路径
293
+ * - extraStyleDataPath: String - 额外样式文件路径(可选)
294
+ */
295
+ func setCustomMapStyle(_ styleData: [String: Any]) {
296
+ guard let mapView = mapView else { return }
297
+
298
+ // 在线样式 ID
299
+ if let styleId = styleData["styleId"] as? String, !styleId.isEmpty {
300
+ let customStyle = MAMapCustomStyleOptions()
301
+ customStyle.styleId = styleId
302
+
303
+ // 🔑 缓存样式配置
304
+ cachedCustomStyleOptions = customStyle
305
+
306
+ mapView.setCustomMapStyleOptions(customStyle)
307
+ mapView.customMapStyleEnabled = true
308
+ return
309
+ }
310
+
311
+ // 本地样式文件
312
+ if let styleDataPath = styleData["styleDataPath"] as? String, !styleDataPath.isEmpty {
313
+ // 读取样式文件数据
314
+ if let stylePath = Bundle.main.path(forResource: styleDataPath, ofType: nil),
315
+ let styleFileData = try? Data(contentsOf: URL(fileURLWithPath: stylePath)) {
316
+ let customStyle = MAMapCustomStyleOptions()
317
+ customStyle.styleData = styleFileData
318
+
319
+ // 额外样式文件(可选)
320
+ if let extraPath = styleData["extraStyleDataPath"] as? String, !extraPath.isEmpty,
321
+ let extraFilePath = Bundle.main.path(forResource: extraPath, ofType: nil),
322
+ let extraFileData = try? Data(contentsOf: URL(fileURLWithPath: extraFilePath)) {
323
+ customStyle.styleExtraData = extraFileData
324
+ }
325
+
326
+ // 🔑 缓存样式配置
327
+ cachedCustomStyleOptions = customStyle
328
+
329
+ mapView.setCustomMapStyleOptions(customStyle)
330
+ mapView.customMapStyleEnabled = true
331
+ return
332
+ }
333
+ }
334
+
335
+ // 如果没有提供任何样式,禁用自定义样式并清除缓存
336
+ cachedCustomStyleOptions = nil
337
+ mapView.customMapStyleEnabled = false
338
+ }
268
339
  }
@@ -1,5 +1,6 @@
1
1
  import Foundation
2
2
  import AMapLocationKit
3
+ import AMapFoundationKit
3
4
  import CoreLocation
4
5
  import ExpoModulesCore
5
6
 
@@ -12,117 +13,76 @@ import ExpoModulesCore
12
13
  * - 方向传感器管理
13
14
  * - 定位结果回调
14
15
  */
16
+
15
17
  class LocationManager: NSObject, AMapLocationManagerDelegate {
16
- /// 高德定位管理器实例
18
+
19
+ // 高德定位对象
17
20
  var locationManager: AMapLocationManager?
18
- /// 定位是否已启动
21
+
22
+ // 连续定位是否已开启
19
23
  private var isLocationStarted = false
20
- /// 定位更新回调
24
+
25
+ // 连续定位 event 回调(给 JS map listener 用)
21
26
  var onLocationUpdate: (([String: Any]) -> Void)?
22
- /// 方向更新回调
23
27
  var onHeadingUpdate: (([String: Any]) -> Void)?
24
-
28
+
25
29
  override init() {
26
30
  super.init()
27
31
  initLocationManager()
28
32
  }
29
-
30
- // MARK: - 定位控制
31
-
32
- /**
33
- * 开始连续定位
34
- */
33
+
34
+ // MARK: - 连续定位控制
35
+
35
36
  func start() {
36
37
  locationManager?.startUpdatingLocation()
37
38
  isLocationStarted = true
38
39
  }
39
-
40
- /**
41
- * 停止定位
42
- */
40
+
43
41
  func stop() {
44
42
  locationManager?.stopUpdatingLocation()
45
43
  isLocationStarted = false
46
44
  }
47
-
48
- /**
49
- * 检查定位是否已启动
50
- * @return 是否正在定位
51
- */
45
+
52
46
  func isStarted() -> Bool {
53
47
  return isLocationStarted
54
48
  }
55
-
56
- // MARK: - 定位配置
57
-
58
- /**
59
- * 设置是否返回逆地理信息
60
- * @param isReGeocode 是否返回逆地理信息
61
- */
49
+
50
+ // MARK: - 高德定位配置 API
51
+
62
52
  func setLocatingWithReGeocode(_ isReGeocode: Bool) {
63
53
  locationManager?.locatingWithReGeocode = isReGeocode
64
54
  }
65
-
66
- /**
67
- * 设置定位距离过滤器(米)
68
- * @param distance 最小距离变化才触发定位更新
69
- */
55
+
70
56
  func setDistanceFilter(_ distance: Double) {
71
57
  locationManager?.distanceFilter = distance
72
58
  }
73
-
74
- /**
75
- * 设置定位超时时间(秒)
76
- * @param timeout 超时时间
77
- */
59
+
78
60
  func setLocationTimeout(_ timeout: Int) {
79
61
  locationManager?.locationTimeout = timeout
80
62
  }
81
-
82
- /**
83
- * 设置逆地理超时时间(秒)
84
- * @param timeout 超时时间
85
- */
63
+
86
64
  func setReGeocodeTimeout(_ timeout: Int) {
87
65
  locationManager?.reGeocodeTimeout = timeout
88
66
  }
89
-
90
- /**
91
- * 设置定位精度
92
- * @param accuracy 精度级别
93
- * - 0: 最适合导航
94
- * - 1: 最佳精度
95
- * - 2: 10米精度
96
- * - 3: 100米精度
97
- * - 4: 1公里精度
98
- * - 5: 3公里精度
99
- */
67
+
100
68
  func setDesiredAccuracy(_ accuracy: Int) {
101
- let accuracyValue: CLLocationAccuracy
69
+ let value: CLLocationAccuracy
102
70
  switch accuracy {
103
- case 0: accuracyValue = kCLLocationAccuracyBestForNavigation
104
- case 1: accuracyValue = kCLLocationAccuracyBest
105
- case 2: accuracyValue = kCLLocationAccuracyNearestTenMeters
106
- case 3: accuracyValue = kCLLocationAccuracyHundredMeters
107
- case 4: accuracyValue = kCLLocationAccuracyKilometer
108
- case 5: accuracyValue = kCLLocationAccuracyThreeKilometers
109
- default: accuracyValue = kCLLocationAccuracyBest
71
+ case 0: value = kCLLocationAccuracyBestForNavigation
72
+ case 1: value = kCLLocationAccuracyBest
73
+ case 2: value = kCLLocationAccuracyNearestTenMeters
74
+ case 3: value = kCLLocationAccuracyHundredMeters
75
+ case 4: value = kCLLocationAccuracyKilometer
76
+ case 5: value = kCLLocationAccuracyThreeKilometers
77
+ default: value = kCLLocationAccuracyBest
110
78
  }
111
- locationManager?.desiredAccuracy = accuracyValue
79
+ locationManager?.desiredAccuracy = value
112
80
  }
113
-
114
- /**
115
- * 设置是否自动暂停定位更新
116
- * @param pauses 是否自动暂停
117
- */
81
+
118
82
  func setPausesLocationUpdatesAutomatically(_ pauses: Bool) {
119
83
  locationManager?.pausesLocationUpdatesAutomatically = pauses
120
84
  }
121
-
122
- /**
123
- * 设置是否允许后台定位
124
- * @param allows 是否允许后台定位
125
- */
85
+
126
86
  func setAllowsBackgroundLocationUpdates(_ allows: Bool) {
127
87
  if allows {
128
88
  let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
@@ -133,14 +93,7 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
133
93
  }
134
94
  locationManager?.allowsBackgroundLocationUpdates = allows
135
95
  }
136
-
137
- /**
138
- * 设置逆地理语言
139
- * @param language 语言类型
140
- * - 0: 默认
141
- * - 1: 中文
142
- * - 2: 英文
143
- */
96
+
144
97
  func setGeoLanguage(_ language: Int) {
145
98
  switch language {
146
99
  case 0: locationManager?.reGeocodeLanguage = .default
@@ -149,71 +102,41 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
149
102
  default: break
150
103
  }
151
104
  }
152
-
153
- // MARK: - 方向传感器
154
-
155
- /**
156
- * 开始更新设备方向
157
- */
105
+
106
+ // MARK: - 方向
107
+
158
108
  func startUpdatingHeading() {
159
109
  locationManager?.startUpdatingHeading()
160
110
  }
161
-
162
- /**
163
- * 停止更新设备方向
164
- */
111
+
165
112
  func stopUpdatingHeading() {
166
113
  locationManager?.stopUpdatingHeading()
167
114
  }
168
-
169
- // MARK: - 生命周期
170
-
171
- /**
172
- * 销毁定位管理器
173
- */
174
- func destroy() {
175
- locationManager?.stopUpdatingLocation()
176
- locationManager?.stopUpdatingHeading()
177
- locationManager?.delegate = nil
178
- locationManager = nil
179
- onLocationUpdate = nil
180
- onHeadingUpdate = nil
181
- }
182
-
183
- /**
184
- * 初始化定位管理器
185
- */
115
+
116
+ // MARK: - 初始化
117
+
186
118
  private func initLocationManager() {
187
119
  locationManager = AMapLocationManager()
188
120
  locationManager?.delegate = self
189
- // 推荐配置:百米精度,快速定位
121
+
122
+ // 默认配置
190
123
  locationManager?.desiredAccuracy = kCLLocationAccuracyHundredMeters
191
124
  locationManager?.distanceFilter = 10
192
- // 增加超时时间,避免首次授权时超时(首次定位建议10秒以上)
193
- locationManager?.locationTimeout = 10 // 10秒超时
194
- locationManager?.reGeocodeTimeout = 5 // 5秒超时
125
+ locationManager?.locationTimeout = 10
126
+ locationManager?.reGeocodeTimeout = 5
195
127
  locationManager?.locatingWithReGeocode = true
196
-
197
- // iOS 9 之前:防止后台被系统挂起(默认关闭,用户可通过 setPausesLocationUpdatesAutomatically 配置)
198
128
  locationManager?.pausesLocationUpdatesAutomatically = false
199
129
  }
200
-
201
- // MARK: - AMapLocationManagerDelegate
202
-
203
- /**
204
- * 定位更新回调
205
- * @param manager 定位管理器
206
- * @param location 位置信息
207
- * @param reGeocode 逆地理信息
208
- */
209
- func amapLocationManager(_ manager: AMapLocationManager!, didUpdate location: CLLocation!, reGeocode: AMapLocationReGeocode!) {
210
- // 🔑 坐标验证:防止无效坐标
211
- guard location.coordinate.latitude >= -90 && location.coordinate.latitude <= 90,
212
- location.coordinate.longitude >= -180 && location.coordinate.longitude <= 180 else {
213
- return
214
- }
215
-
216
- var locationData: [String: Any] = [
130
+
131
+ // MARK: - Delegate(连续定位回调)
132
+
133
+ func amapLocationManager(_ manager: AMapLocationManager!,
134
+ didUpdate location: CLLocation!,
135
+ reGeocode: AMapLocationReGeocode!) {
136
+
137
+ guard let location = location else { return }
138
+
139
+ var data: [String: Any] = [
217
140
  "latitude": location.coordinate.latitude,
218
141
  "longitude": location.coordinate.longitude,
219
142
  "accuracy": location.horizontalAccuracy,
@@ -222,28 +145,23 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
222
145
  "speed": location.speed,
223
146
  "timestamp": location.timestamp.timeIntervalSince1970 * 1000
224
147
  ]
225
-
226
- // 添加逆地理信息
227
- if let reGeocode = reGeocode {
228
- locationData["address"] = reGeocode.formattedAddress
229
- locationData["province"] = reGeocode.province
230
- locationData["city"] = reGeocode.city
231
- locationData["district"] = reGeocode.district
232
- locationData["street"] = reGeocode.street
233
- locationData["streetNumber"] = reGeocode.number
234
- locationData["country"] = reGeocode.country
235
- locationData["cityCode"] = reGeocode.citycode
236
- locationData["adCode"] = reGeocode.adcode
148
+
149
+ if let geo = reGeocode {
150
+ data["address"] = geo.formattedAddress
151
+ data["province"] = geo.province
152
+ data["city"] = geo.city
153
+ data["district"] = geo.district
154
+ data["street"] = geo.street
155
+ data["streetNumber"] = geo.number
156
+ data["country"] = geo.country
157
+ data["cityCode"] = geo.citycode
158
+ data["adCode"] = geo.adcode
237
159
  }
238
-
239
- onLocationUpdate?(locationData)
160
+
161
+ // 触发连续定位回调
162
+ onLocationUpdate?(data)
240
163
  }
241
-
242
- /**
243
- * 方向更新回调
244
- * @param manager 定位管理器
245
- * @param heading 方向信息
246
- */
164
+
247
165
  func amapLocationManager(_ manager: AMapLocationManager!, didUpdate heading: CLHeading!) {
248
166
  let headingData: [String: Any] = [
249
167
  "heading": heading.trueHeading,
@@ -252,22 +170,53 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
252
170
  ]
253
171
  onHeadingUpdate?(headingData)
254
172
  }
255
-
256
- /**
257
- * 需要定位权限回调
258
- * @param manager 定位管理器
259
- * @param locationManager 系统定位管理器
260
- */
261
- func amapLocationManager(_ manager: AMapLocationManager!, doRequireLocationAuth locationManager: CLLocationManager!) {
262
- locationManager.requestAlwaysAuthorization()
173
+
174
+ func amapLocationManager(_ manager: AMapLocationManager!, didFailWithError error: Error!) {
175
+ // 定位失败 - 静默处理(连续定位会自动重试)
263
176
  }
264
-
177
+
178
+ // MARK: - 工具方法
179
+
265
180
  /**
266
- * 定位失败回调
267
- * @param manager 定位管理器
268
- * @param error 错误信息
181
+ * 坐标转换
182
+ * @param coordinate 原始坐标
183
+ * @param type 坐标类型 (0: GPS/Google, 1: MapBar, 2: Baidu, 3: MapABC/SoSo)
184
+ * @param promise Promise
269
185
  */
270
- func amapLocationManager(_ manager: AMapLocationManager!, didFailWithError error: Error!) {
271
- // 定位失败 - 静默处理
186
+ func coordinateConvert(_ coordinate: [String: Double], type: Int, promise: Promise) {
187
+ guard let lat = coordinate["latitude"],
188
+ let lon = coordinate["longitude"] else {
189
+ promise.reject("INVALID_ARGUMENT", "Invalid coordinate")
190
+ return
191
+ }
192
+
193
+ let coord = CLLocationCoordinate2D(latitude: lat, longitude: lon)
194
+ var amapType: AMapCoordinateType
195
+
196
+ // 根据文档映射
197
+ switch type {
198
+ case 0: amapType = AMapCoordinateType.GPS
199
+ case 1: amapType = AMapCoordinateType.mapBar
200
+ case 2: amapType = AMapCoordinateType.baidu
201
+ case 3: amapType = AMapCoordinateType.mapABC
202
+ default: amapType = AMapCoordinateType.GPS
203
+ }
204
+
205
+ let converted = AMapCoordinateConvert(coord, amapType)
206
+
207
+ promise.resolve([
208
+ "latitude": converted.latitude,
209
+ "longitude": converted.longitude
210
+ ])
211
+ }
212
+
213
+ // MARK: - 销毁
214
+ func destroy() {
215
+ locationManager?.stopUpdatingLocation()
216
+ locationManager?.stopUpdatingHeading()
217
+ locationManager?.delegate = nil
218
+ locationManager = nil
219
+ onLocationUpdate = nil
220
+ onHeadingUpdate = nil
272
221
  }
273
222
  }
@@ -1,5 +1,7 @@
1
1
  import ExpoModulesCore
2
2
  import AMapNaviKit
3
+ import CoreLocation
4
+
3
5
 
4
6
  /**
5
7
  * 圆形覆盖物视图
@@ -9,18 +11,18 @@ import AMapNaviKit
9
11
  * - 管理圆形的样式(填充色、边框色、边框宽度)
10
12
  * - 响应属性变化并更新渲染
11
13
  */
12
- class NaviCircleView: ExpoView {
14
+ class CircleView: ExpoView {
13
15
  /// 事件派发器 - 使用 onCirclePress 避免与 MarkerPress 冲突
14
16
  let onCirclePress = EventDispatcher()
15
17
 
16
18
  /// 圆心坐标
17
- var circleCenter: [String: Double] = [:]
19
+ var circleCenter: [String: Double]?
18
20
  /// 半径(米)
19
21
  var radius: Double = 0
20
22
  /// 填充颜色
21
- var fillColor: Any?
23
+ var fillColor: String?
22
24
  /// 边框颜色
23
- var strokeColor: Any?
25
+ var strokeColor: String?
24
26
  /// 边框宽度
25
27
  var strokeWidth: Float = 0
26
28
  /// z-index 图层顺序
@@ -89,34 +91,17 @@ class NaviCircleView: ExpoView {
89
91
  return
90
92
  }
91
93
 
92
- guard let latitude = circleCenter["latitude"],
93
- let longitude = circleCenter["longitude"],
94
+ guard let center = LatLngParser.parseLatLng(circleCenter),
94
95
  radius > 0 else {
95
96
  return
96
97
  }
97
98
 
98
- // 🔑 坐标验证:防止无效坐标导致崩溃
99
- guard latitude >= -90 && latitude <= 90,
100
- longitude >= -180 && longitude <= 180 else {
101
- return
99
+ if let old = circle {
100
+ mapView.remove(old)
102
101
  }
103
102
 
104
- // 🔑 半径验证:防止负数或过大的半径
105
- let validRadius = max(0.1, min(radius, 1000000))
106
-
107
- if circle == nil {
108
- let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
109
- circle = MACircle(center: coordinate, radius: validRadius)
110
- mapView.add(circle!)
111
- } else {
112
- // 先移除旧的
113
- mapView.remove(circle!)
114
- // 更新属性
115
- circle?.coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
116
- circle?.radius = validRadius
117
- // 重新添加
118
- mapView.add(circle!)
119
- }
103
+ circle = MACircle(center: center, radius: radius)
104
+ mapView.add(circle!)
120
105
 
121
106
  renderer = nil
122
107
  }
@@ -142,11 +127,10 @@ class NaviCircleView: ExpoView {
142
127
  }
143
128
 
144
129
  /**
145
- * 设置中心点
146
- * @param center 中心点坐标 {latitude, longitude}
130
+ * 设置圆心
147
131
  */
148
- func setCenter(_ center: [String: Double]) {
149
- circleCenter = center
132
+ func setCenter(_ center: [String: Double]?) {
133
+ self.circleCenter = center
150
134
  updateCircle()
151
135
  }
152
136
 
@@ -163,7 +147,7 @@ class NaviCircleView: ExpoView {
163
147
  * 设置填充颜色
164
148
  * @param color 颜色值
165
149
  */
166
- func setFillColor(_ color: Any?) {
150
+ func setFillColor(_ color: String?) {
167
151
  fillColor = color
168
152
  renderer = nil
169
153
  updateCircle()
@@ -173,7 +157,7 @@ class NaviCircleView: ExpoView {
173
157
  * 设置边框颜色
174
158
  * @param color 颜色值
175
159
  */
176
- func setStrokeColor(_ color: Any?) {
160
+ func setStrokeColor(_ color: String?) {
177
161
  strokeColor = color
178
162
  renderer = nil
179
163
  updateCircle()
@@ -1,43 +1,43 @@
1
1
  import ExpoModulesCore
2
2
 
3
- public class NaviCircleViewModule: Module {
3
+ public class CircleViewModule: Module {
4
4
  public func definition() -> ModuleDefinition {
5
- Name("NaviCircleView")
5
+ Name("CircleView")
6
6
 
7
- View(NaviCircleView.self) {
7
+ View(CircleView.self) {
8
8
  Events("onCirclePress")
9
9
 
10
- Prop("center") { (view: NaviCircleView, center: [String: Double]) in
10
+ Prop("center") { (view: CircleView, center: [String: Double]?) in
11
11
  view.setCenter(center)
12
12
  }
13
13
 
14
- Prop("radius") { (view: NaviCircleView, radius: Double) in
14
+ Prop("radius") { (view: CircleView, radius: Double) in
15
15
  view.setRadius(radius)
16
16
  }
17
17
 
18
- Prop("fillColor") { (view: NaviCircleView, color: String) in
18
+ Prop("fillColor") { (view: CircleView, color: String?) in
19
19
  view.setFillColor(color)
20
20
  }
21
21
 
22
- Prop("strokeColor") { (view: NaviCircleView, color: String) in
22
+ Prop("strokeColor") { (view: CircleView, color: String?) in
23
23
  view.setStrokeColor(color)
24
24
  }
25
25
 
26
- Prop("strokeWidth") { (view: NaviCircleView, width: Double) in
26
+ Prop("strokeWidth") { (view: CircleView, width: Double) in
27
27
  view.setStrokeWidth(Float(width))
28
28
  }
29
29
 
30
- Prop("zIndex") { (view: NaviCircleView, zIndex: Double) in
30
+ Prop("zIndex") { (view: CircleView, zIndex: Double) in
31
31
  view.setZIndex(zIndex)
32
32
  }
33
33
 
34
- OnViewDidUpdateProps { (view: NaviCircleView) in
34
+ OnViewDidUpdateProps { (view: CircleView) in
35
35
  // 属性更新完成后,如果还没连接地图,尝试连接
36
36
  if !view.isMapConnected() {
37
- // 查找父视图 NaviMapView
37
+ // 查找父视图 ExpoGaodeMapView
38
38
  var parent = view.superview
39
39
  while parent != nil {
40
- if let mapView = parent as? NaviMapView {
40
+ if let mapView = parent as? ExpoGaodeMapView {
41
41
  view.setMap(mapView.mapView)
42
42
  return
43
43
  }
@@ -0,0 +1,32 @@
1
+ import Foundation
2
+ import CoreLocation
3
+ import AMapNaviKit
4
+
5
+ class ClusterAnnotation: NSObject, MAAnnotation {
6
+ @objc dynamic var coordinate: CLLocationCoordinate2D
7
+ var count: Int
8
+ var pois: [[String: Any]]
9
+
10
+ // MAAnnotation required properties
11
+ var title: String?
12
+ var subtitle: String?
13
+
14
+ init(coordinate: CLLocationCoordinate2D, count: Int, pois: [[String: Any]]) {
15
+ self.coordinate = coordinate
16
+ self.count = count
17
+ self.pois = pois
18
+ self.title = "\(count)个点"
19
+ super.init()
20
+ }
21
+
22
+ override func isEqual(_ object: Any?) -> Bool {
23
+ guard let other = object as? ClusterAnnotation else { return false }
24
+ return self.coordinate.latitude == other.coordinate.latitude &&
25
+ self.coordinate.longitude == other.coordinate.longitude &&
26
+ self.count == other.count
27
+ }
28
+
29
+ override var hash: Int {
30
+ return "\(coordinate.latitude),\(coordinate.longitude),\(count)".hashValue
31
+ }
32
+ }