expo-gaode-map-navigation 1.1.5-next.0 → 1.1.5-next.2
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/README.md +213 -73
- package/android/build.gradle +10 -0
- package/android/src/main/cpp/CMakeLists.txt +24 -0
- package/android/src/main/cpp/cluster_jni.cpp +848 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
- package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
- package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
- package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
- package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
- package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
- package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
- package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
- package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
- package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviView.kt +13 -3
- package/android/src/main/java/expo/modules/gaodemap/navigation/ExpoGaodeMapNaviViewModule.kt +4 -0
- package/build/ExpoGaodeMapNaviView.d.ts +7 -7
- package/build/ExpoGaodeMapNaviView.js +10 -11
- package/build/index.d.ts +1 -1
- package/build/index.js +2 -2
- package/build/map/ExpoGaodeMapModule.d.ts +2 -201
- package/build/map/ExpoGaodeMapModule.js +586 -18
- package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
- package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
- package/build/map/ExpoGaodeMapView.js +66 -58
- package/build/map/components/FoldableMapView.d.ts +38 -0
- package/build/map/components/FoldableMapView.js +209 -0
- package/build/map/components/MapContext.d.ts +12 -0
- package/build/map/components/MapContext.js +54 -0
- package/build/map/components/MapUI.d.ts +18 -0
- package/build/map/components/MapUI.js +29 -0
- package/build/map/components/overlays/Circle.js +34 -3
- package/build/map/components/overlays/Cluster.d.ts +3 -1
- package/build/map/components/overlays/Cluster.js +31 -2
- package/build/map/components/overlays/HeatMap.d.ts +3 -1
- package/build/map/components/overlays/HeatMap.js +33 -3
- package/build/map/components/overlays/Marker.d.ts +1 -1
- package/build/map/components/overlays/Marker.js +37 -32
- package/build/map/components/overlays/MultiPoint.js +1 -1
- package/build/map/components/overlays/Polygon.js +30 -3
- package/build/map/components/overlays/Polyline.js +36 -3
- package/build/map/index.d.ts +25 -5
- package/build/map/index.js +59 -18
- package/build/map/types/common.types.d.ts +40 -0
- package/build/map/types/common.types.js +0 -4
- package/build/map/types/index.d.ts +3 -2
- package/build/map/types/map-view.types.d.ts +108 -3
- package/build/map/types/native-module.types.d.ts +363 -0
- package/build/map/types/native-module.types.js +5 -0
- package/build/map/types/offline.types.d.ts +132 -0
- package/build/map/types/offline.types.js +5 -0
- package/build/map/types/overlays.types.d.ts +137 -24
- package/build/map/utils/ErrorHandler.d.ts +110 -0
- package/build/map/utils/ErrorHandler.js +421 -0
- package/build/map/utils/GeoUtils.d.ts +20 -0
- package/build/map/utils/GeoUtils.js +76 -0
- package/build/map/utils/OfflineMapManager.d.ts +148 -0
- package/build/map/utils/OfflineMapManager.js +217 -0
- package/build/map/utils/PermissionUtils.d.ts +91 -0
- package/build/map/utils/PermissionUtils.js +255 -0
- package/build/map/utils/PlatformDetector.d.ts +102 -0
- package/build/map/utils/PlatformDetector.js +186 -0
- package/build/types/naviview.types.d.ts +6 -1
- package/expo-module.config.json +12 -10
- package/ios/ExpoGaodeMapNavigation.podspec +9 -0
- package/ios/map/ExpoGaodeMapModule.swift +485 -75
- package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
- package/ios/map/ExpoGaodeMapView.swift +611 -62
- package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
- package/ios/map/MapPreloadManager.swift +348 -0
- package/ios/map/cpp/ClusterEngine.cpp +110 -0
- package/ios/map/cpp/ClusterEngine.hpp +20 -0
- package/ios/map/cpp/ColorParser.cpp +135 -0
- package/ios/map/cpp/ColorParser.hpp +14 -0
- package/ios/map/cpp/GeometryEngine.cpp +574 -0
- package/ios/map/cpp/GeometryEngine.hpp +159 -0
- package/ios/map/cpp/QuadTree.cpp +92 -0
- package/ios/map/cpp/QuadTree.hpp +42 -0
- package/ios/map/cpp/README.md +55 -0
- package/ios/map/cpp/tests/benchmark_js.js +41 -0
- package/ios/map/cpp/tests/run.sh +17 -0
- package/ios/map/cpp/tests/test_main.cpp +276 -0
- package/ios/map/managers/UIManager.swift +72 -1
- package/ios/map/modules/LocationManager.swift +123 -166
- package/ios/map/overlays/CircleView.swift +16 -32
- package/ios/map/overlays/CircleViewModule.swift +12 -12
- package/ios/map/overlays/ClusterAnnotation.swift +32 -0
- package/ios/map/overlays/ClusterView.swift +331 -45
- package/ios/map/overlays/ClusterViewModule.swift +20 -6
- package/ios/map/overlays/HeatMapView.swift +135 -32
- package/ios/map/overlays/HeatMapViewModule.swift +20 -8
- package/ios/map/overlays/MarkerView.swift +613 -130
- package/ios/map/overlays/MarkerViewModule.swift +38 -18
- package/ios/map/overlays/MultiPointView.swift +168 -10
- package/ios/map/overlays/MultiPointViewModule.swift +27 -5
- package/ios/map/overlays/PolygonView.swift +62 -23
- package/ios/map/overlays/PolygonViewModule.swift +18 -12
- package/ios/map/overlays/PolylineView.swift +21 -13
- package/ios/map/overlays/PolylineViewModule.swift +18 -12
- package/ios/map/utils/ClusterNative.h +96 -0
- package/ios/map/utils/ClusterNative.mm +377 -0
- package/ios/map/utils/ColorParser.swift +12 -1
- package/ios/map/utils/CppBridging.mm +13 -0
- package/ios/map/utils/GeometryUtils.swift +34 -0
- package/ios/map/utils/LatLngParser.swift +87 -0
- package/ios/map/utils/PermissionManager.swift +135 -6
- package/package.json +2 -2
- package/build/map/ExpoGaodeMap.types.d.ts +0 -41
- package/build/map/ExpoGaodeMap.types.js +0 -24
- package/build/map/utils/EventManager.d.ts +0 -10
- package/build/map/utils/EventManager.js +0 -26
- package/build/map/utils/ModuleLoader.d.ts +0 -73
- 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
|
-
|
|
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,6 +1,8 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import AMapLocationKit
|
|
3
|
+
import AMapFoundationKit
|
|
3
4
|
import CoreLocation
|
|
5
|
+
import ExpoModulesCore
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* 定位管理器
|
|
@@ -11,128 +13,87 @@ import CoreLocation
|
|
|
11
13
|
* - 方向传感器管理
|
|
12
14
|
* - 定位结果回调
|
|
13
15
|
*/
|
|
16
|
+
|
|
14
17
|
class LocationManager: NSObject, AMapLocationManagerDelegate {
|
|
15
|
-
|
|
18
|
+
|
|
19
|
+
// 高德定位对象
|
|
16
20
|
var locationManager: AMapLocationManager?
|
|
17
|
-
|
|
21
|
+
|
|
22
|
+
// 连续定位是否已开启
|
|
18
23
|
private var isLocationStarted = false
|
|
19
|
-
|
|
24
|
+
|
|
25
|
+
// 连续定位 event 回调(给 JS map listener 用)
|
|
20
26
|
var onLocationUpdate: (([String: Any]) -> Void)?
|
|
21
|
-
/// 方向更新回调
|
|
22
27
|
var onHeadingUpdate: (([String: Any]) -> Void)?
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
override init() {
|
|
25
30
|
super.init()
|
|
26
31
|
initLocationManager()
|
|
27
32
|
}
|
|
28
|
-
|
|
29
|
-
// MARK: -
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 开始连续定位
|
|
33
|
-
*/
|
|
33
|
+
|
|
34
|
+
// MARK: - 连续定位控制
|
|
35
|
+
|
|
34
36
|
func start() {
|
|
35
37
|
locationManager?.startUpdatingLocation()
|
|
36
38
|
isLocationStarted = true
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 停止定位
|
|
41
|
-
*/
|
|
40
|
+
|
|
42
41
|
func stop() {
|
|
43
42
|
locationManager?.stopUpdatingLocation()
|
|
44
43
|
isLocationStarted = false
|
|
45
44
|
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 检查定位是否已启动
|
|
49
|
-
* @return 是否正在定位
|
|
50
|
-
*/
|
|
45
|
+
|
|
51
46
|
func isStarted() -> Bool {
|
|
52
47
|
return isLocationStarted
|
|
53
48
|
}
|
|
54
|
-
|
|
55
|
-
// MARK: -
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 设置是否返回逆地理信息
|
|
59
|
-
* @param isReGeocode 是否返回逆地理信息
|
|
60
|
-
*/
|
|
49
|
+
|
|
50
|
+
// MARK: - 高德定位配置 API
|
|
51
|
+
|
|
61
52
|
func setLocatingWithReGeocode(_ isReGeocode: Bool) {
|
|
62
53
|
locationManager?.locatingWithReGeocode = isReGeocode
|
|
63
54
|
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 设置定位距离过滤器(米)
|
|
67
|
-
* @param distance 最小距离变化才触发定位更新
|
|
68
|
-
*/
|
|
55
|
+
|
|
69
56
|
func setDistanceFilter(_ distance: Double) {
|
|
70
57
|
locationManager?.distanceFilter = distance
|
|
71
58
|
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 设置定位超时时间(秒)
|
|
75
|
-
* @param timeout 超时时间
|
|
76
|
-
*/
|
|
59
|
+
|
|
77
60
|
func setLocationTimeout(_ timeout: Int) {
|
|
78
61
|
locationManager?.locationTimeout = timeout
|
|
79
62
|
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* 设置逆地理超时时间(秒)
|
|
83
|
-
* @param timeout 超时时间
|
|
84
|
-
*/
|
|
63
|
+
|
|
85
64
|
func setReGeocodeTimeout(_ timeout: Int) {
|
|
86
65
|
locationManager?.reGeocodeTimeout = timeout
|
|
87
66
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* 设置定位精度
|
|
91
|
-
* @param accuracy 精度级别
|
|
92
|
-
* - 0: 最适合导航
|
|
93
|
-
* - 1: 最佳精度
|
|
94
|
-
* - 2: 10米精度
|
|
95
|
-
* - 3: 100米精度
|
|
96
|
-
* - 4: 1公里精度
|
|
97
|
-
* - 5: 3公里精度
|
|
98
|
-
*/
|
|
67
|
+
|
|
99
68
|
func setDesiredAccuracy(_ accuracy: Int) {
|
|
100
|
-
let
|
|
69
|
+
let value: CLLocationAccuracy
|
|
101
70
|
switch accuracy {
|
|
102
|
-
case 0:
|
|
103
|
-
case 1:
|
|
104
|
-
case 2:
|
|
105
|
-
case 3:
|
|
106
|
-
case 4:
|
|
107
|
-
case 5:
|
|
108
|
-
default:
|
|
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
|
|
109
78
|
}
|
|
110
|
-
locationManager?.desiredAccuracy =
|
|
79
|
+
locationManager?.desiredAccuracy = value
|
|
111
80
|
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 设置是否自动暂停定位更新
|
|
115
|
-
* @param pauses 是否自动暂停
|
|
116
|
-
*/
|
|
81
|
+
|
|
117
82
|
func setPausesLocationUpdatesAutomatically(_ pauses: Bool) {
|
|
118
83
|
locationManager?.pausesLocationUpdatesAutomatically = pauses
|
|
119
84
|
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* 设置是否允许后台定位
|
|
123
|
-
* @param allows 是否允许后台定位
|
|
124
|
-
*/
|
|
85
|
+
|
|
125
86
|
func setAllowsBackgroundLocationUpdates(_ allows: Bool) {
|
|
87
|
+
if allows {
|
|
88
|
+
let backgroundModes = Bundle.main.object(forInfoDictionaryKey: "UIBackgroundModes") as? [String]
|
|
89
|
+
if backgroundModes?.contains("location") != true {
|
|
90
|
+
log.warn("⚠️ [ExpoGaodeMap] iOS 后台定位未正确配置,setAllowsBackgroundLocationUpdates(true) 可能不会生效,请检查 Info.plist 是否包含 UIBackgroundModes: location,或者在 app.json 中配置 enableBackgroundLocation: true,然后重新执行 npx expo prebuild")
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
}
|
|
126
94
|
locationManager?.allowsBackgroundLocationUpdates = allows
|
|
127
95
|
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* 设置逆地理语言
|
|
131
|
-
* @param language 语言类型
|
|
132
|
-
* - 0: 默认
|
|
133
|
-
* - 1: 中文
|
|
134
|
-
* - 2: 英文
|
|
135
|
-
*/
|
|
96
|
+
|
|
136
97
|
func setGeoLanguage(_ language: Int) {
|
|
137
98
|
switch language {
|
|
138
99
|
case 0: locationManager?.reGeocodeLanguage = .default
|
|
@@ -141,71 +102,41 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
|
|
|
141
102
|
default: break
|
|
142
103
|
}
|
|
143
104
|
}
|
|
144
|
-
|
|
145
|
-
// MARK: -
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* 开始更新设备方向
|
|
149
|
-
*/
|
|
105
|
+
|
|
106
|
+
// MARK: - 方向
|
|
107
|
+
|
|
150
108
|
func startUpdatingHeading() {
|
|
151
109
|
locationManager?.startUpdatingHeading()
|
|
152
110
|
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* 停止更新设备方向
|
|
156
|
-
*/
|
|
111
|
+
|
|
157
112
|
func stopUpdatingHeading() {
|
|
158
113
|
locationManager?.stopUpdatingHeading()
|
|
159
114
|
}
|
|
160
|
-
|
|
161
|
-
// MARK: -
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* 销毁定位管理器
|
|
165
|
-
*/
|
|
166
|
-
func destroy() {
|
|
167
|
-
locationManager?.stopUpdatingLocation()
|
|
168
|
-
locationManager?.stopUpdatingHeading()
|
|
169
|
-
locationManager?.delegate = nil
|
|
170
|
-
locationManager = nil
|
|
171
|
-
onLocationUpdate = nil
|
|
172
|
-
onHeadingUpdate = nil
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 初始化定位管理器
|
|
177
|
-
*/
|
|
115
|
+
|
|
116
|
+
// MARK: - 初始化
|
|
117
|
+
|
|
178
118
|
private func initLocationManager() {
|
|
179
119
|
locationManager = AMapLocationManager()
|
|
180
120
|
locationManager?.delegate = self
|
|
181
|
-
|
|
121
|
+
|
|
122
|
+
// 默认配置
|
|
182
123
|
locationManager?.desiredAccuracy = kCLLocationAccuracyHundredMeters
|
|
183
124
|
locationManager?.distanceFilter = 10
|
|
184
|
-
|
|
185
|
-
locationManager?.
|
|
186
|
-
locationManager?.reGeocodeTimeout = 5 // 5秒超时
|
|
125
|
+
locationManager?.locationTimeout = 10
|
|
126
|
+
locationManager?.reGeocodeTimeout = 5
|
|
187
127
|
locationManager?.locatingWithReGeocode = true
|
|
188
|
-
|
|
189
|
-
// iOS 9 之前:防止后台被系统挂起(默认关闭,用户可通过 setPausesLocationUpdatesAutomatically 配置)
|
|
190
128
|
locationManager?.pausesLocationUpdatesAutomatically = false
|
|
191
129
|
}
|
|
192
|
-
|
|
193
|
-
// MARK: -
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// 🔑 坐标验证:防止无效坐标
|
|
203
|
-
guard location.coordinate.latitude >= -90 && location.coordinate.latitude <= 90,
|
|
204
|
-
location.coordinate.longitude >= -180 && location.coordinate.longitude <= 180 else {
|
|
205
|
-
return
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
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] = [
|
|
209
140
|
"latitude": location.coordinate.latitude,
|
|
210
141
|
"longitude": location.coordinate.longitude,
|
|
211
142
|
"accuracy": location.horizontalAccuracy,
|
|
@@ -214,28 +145,23 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
|
|
|
214
145
|
"speed": location.speed,
|
|
215
146
|
"timestamp": location.timestamp.timeIntervalSince1970 * 1000
|
|
216
147
|
]
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
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
|
|
229
159
|
}
|
|
230
|
-
|
|
231
|
-
|
|
160
|
+
|
|
161
|
+
// 触发连续定位回调
|
|
162
|
+
onLocationUpdate?(data)
|
|
232
163
|
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* 方向更新回调
|
|
236
|
-
* @param manager 定位管理器
|
|
237
|
-
* @param heading 方向信息
|
|
238
|
-
*/
|
|
164
|
+
|
|
239
165
|
func amapLocationManager(_ manager: AMapLocationManager!, didUpdate heading: CLHeading!) {
|
|
240
166
|
let headingData: [String: Any] = [
|
|
241
167
|
"heading": heading.trueHeading,
|
|
@@ -244,22 +170,53 @@ class LocationManager: NSObject, AMapLocationManagerDelegate {
|
|
|
244
170
|
]
|
|
245
171
|
onHeadingUpdate?(headingData)
|
|
246
172
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
* @param manager 定位管理器
|
|
251
|
-
* @param locationManager 系统定位管理器
|
|
252
|
-
*/
|
|
253
|
-
func amapLocationManager(_ manager: AMapLocationManager!, doRequireLocationAuth locationManager: CLLocationManager!) {
|
|
254
|
-
locationManager.requestAlwaysAuthorization()
|
|
173
|
+
|
|
174
|
+
func amapLocationManager(_ manager: AMapLocationManager!, didFailWithError error: Error!) {
|
|
175
|
+
// 定位失败 - 静默处理(连续定位会自动重试)
|
|
255
176
|
}
|
|
256
|
-
|
|
177
|
+
|
|
178
|
+
// MARK: - 工具方法
|
|
179
|
+
|
|
257
180
|
/**
|
|
258
|
-
*
|
|
259
|
-
* @param
|
|
260
|
-
* @param
|
|
181
|
+
* 坐标转换
|
|
182
|
+
* @param coordinate 原始坐标
|
|
183
|
+
* @param type 坐标类型 (0: GPS/Google, 1: MapBar, 2: Baidu, 3: MapABC/SoSo)
|
|
184
|
+
* @param promise Promise
|
|
261
185
|
*/
|
|
262
|
-
func
|
|
263
|
-
|
|
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
|
|
264
221
|
}
|
|
265
|
-
}
|
|
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
|
|
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:
|
|
23
|
+
var fillColor: String?
|
|
22
24
|
/// 边框颜色
|
|
23
|
-
var strokeColor:
|
|
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
|
|
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
|
-
|
|
100
|
-
longitude >= -180 && longitude <= 180 else {
|
|
101
|
-
return
|
|
99
|
+
if let old = circle {
|
|
100
|
+
mapView.remove(old)
|
|
102
101
|
}
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
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:
|
|
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:
|
|
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
|
|
3
|
+
public class CircleViewModule: Module {
|
|
4
4
|
public func definition() -> ModuleDefinition {
|
|
5
|
-
Name("
|
|
5
|
+
Name("CircleView")
|
|
6
6
|
|
|
7
|
-
View(
|
|
7
|
+
View(CircleView.self) {
|
|
8
8
|
Events("onCirclePress")
|
|
9
9
|
|
|
10
|
-
Prop("center") { (view:
|
|
10
|
+
Prop("center") { (view: CircleView, center: [String: Double]?) in
|
|
11
11
|
view.setCenter(center)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
Prop("radius") { (view:
|
|
14
|
+
Prop("radius") { (view: CircleView, radius: Double) in
|
|
15
15
|
view.setRadius(radius)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
Prop("fillColor") { (view:
|
|
18
|
+
Prop("fillColor") { (view: CircleView, color: String?) in
|
|
19
19
|
view.setFillColor(color)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
Prop("strokeColor") { (view:
|
|
22
|
+
Prop("strokeColor") { (view: CircleView, color: String?) in
|
|
23
23
|
view.setStrokeColor(color)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
Prop("strokeWidth") { (view:
|
|
26
|
+
Prop("strokeWidth") { (view: CircleView, width: Double) in
|
|
27
27
|
view.setStrokeWidth(Float(width))
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
Prop("zIndex") { (view:
|
|
30
|
+
Prop("zIndex") { (view: CircleView, zIndex: Double) in
|
|
31
31
|
view.setZIndex(zIndex)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
OnViewDidUpdateProps { (view:
|
|
34
|
+
OnViewDidUpdateProps { (view: CircleView) in
|
|
35
35
|
// 属性更新完成后,如果还没连接地图,尝试连接
|
|
36
36
|
if !view.isMapConnected() {
|
|
37
|
-
// 查找父视图
|
|
37
|
+
// 查找父视图 ExpoGaodeMapView
|
|
38
38
|
var parent = view.superview
|
|
39
39
|
while parent != nil {
|
|
40
|
-
if let mapView = parent as?
|
|
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
|
+
}
|