expo-gaode-map-navigation 1.1.5 → 1.1.7
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/build/ExpoGaodeMapNaviView.d.ts +7 -7
- package/build/ExpoGaodeMapNaviView.js +10 -11
- package/build/ExpoGaodeMapNavigationModule.d.ts +2 -1
- package/build/index.d.ts +35 -33
- package/build/index.js +70 -106
- 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/index.d.ts +1 -0
- package/build/types/index.js +1 -0
- package/build/types/native-module.types.d.ts +69 -0
- package/build/types/native-module.types.js +2 -0
- package/build/types/naviview.types.d.ts +1 -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/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 +3 -2
- package/shared/cpp/ClusterEngine.cpp +110 -0
- package/shared/cpp/ClusterEngine.hpp +20 -0
- package/shared/cpp/ColorParser.cpp +135 -0
- package/shared/cpp/ColorParser.hpp +14 -0
- package/shared/cpp/GeometryEngine.cpp +574 -0
- package/shared/cpp/GeometryEngine.hpp +159 -0
- package/shared/cpp/QuadTree.cpp +92 -0
- package/shared/cpp/QuadTree.hpp +42 -0
- package/shared/cpp/README.md +55 -0
- package/shared/cpp/tests/benchmark_js.js +41 -0
- package/shared/cpp/tests/run.sh +17 -0
- package/shared/cpp/tests/test_main.cpp +276 -0
- 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
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 地图预加载管理器 (Android)
|
|
3
|
+
* 在后台预先初始化地图实例,提升首次显示速度
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
package expo.modules.gaodemap.map
|
|
7
|
+
|
|
8
|
+
import android.app.ActivityManager
|
|
9
|
+
import android.content.ComponentCallbacks2
|
|
10
|
+
import android.content.Context
|
|
11
|
+
import android.content.res.Configuration
|
|
12
|
+
import android.util.Log
|
|
13
|
+
import com.amap.api.maps.AMap
|
|
14
|
+
import com.amap.api.maps.CameraUpdateFactory
|
|
15
|
+
import com.amap.api.maps.MapView
|
|
16
|
+
import com.amap.api.maps.model.CameraPosition
|
|
17
|
+
import com.amap.api.maps.model.LatLng
|
|
18
|
+
import kotlinx.coroutines.*
|
|
19
|
+
|
|
20
|
+
import java.util.concurrent.ConcurrentLinkedQueue
|
|
21
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
22
|
+
import java.util.concurrent.atomic.AtomicInteger
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 地图预加载实例数据
|
|
26
|
+
*/
|
|
27
|
+
data class PreloadedMapInstance(
|
|
28
|
+
val mapView: MapView,
|
|
29
|
+
val timestamp: Long = System.currentTimeMillis()
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 地图预加载管理器单例
|
|
34
|
+
*/
|
|
35
|
+
object MapPreloadManager : ComponentCallbacks2 {
|
|
36
|
+
private const val TAG = "MapPreloadManager"
|
|
37
|
+
|
|
38
|
+
// 动态池大小配置(根据内存自适应)
|
|
39
|
+
private const val MAX_POOL_SIZE_HIGH_MEMORY = 3 // 高内存设备:>= 500MB
|
|
40
|
+
private const val MAX_POOL_SIZE_MEDIUM_MEMORY = 2 // 中等内存:300-500MB
|
|
41
|
+
private const val MAX_POOL_SIZE_LOW_MEMORY = 1 // 低内存设备:150-300MB
|
|
42
|
+
private const val MIN_MEMORY_THRESHOLD_MB = 150 // 最低内存要求
|
|
43
|
+
|
|
44
|
+
// 动态 TTL 配置(根据内存压力自适应)
|
|
45
|
+
private const val TTL_NORMAL = 5 * 60 * 1000L // 正常:5分钟
|
|
46
|
+
private const val TTL_MEMORY_PRESSURE = 2 * 60 * 1000L // 内存压力:2分钟
|
|
47
|
+
private const val TTL_LOW_MEMORY = 1 * 60 * 1000L // 低内存:1分钟
|
|
48
|
+
|
|
49
|
+
private val preloadedMapViews = ConcurrentLinkedQueue<PreloadedMapInstance>()
|
|
50
|
+
private val isPreloading = AtomicBoolean(false)
|
|
51
|
+
private val preloadScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
52
|
+
|
|
53
|
+
// 动态配置
|
|
54
|
+
@Volatile private var currentMaxPoolSize = MAX_POOL_SIZE_MEDIUM_MEMORY
|
|
55
|
+
@Volatile private var currentTTL = TTL_NORMAL
|
|
56
|
+
@Volatile private var memoryPressureLevel = 0 // 0=正常, 1=压力, 2=严重
|
|
57
|
+
|
|
58
|
+
// 性能统计
|
|
59
|
+
private val totalPreloads = AtomicInteger(0)
|
|
60
|
+
private val successfulPreloads = AtomicInteger(0)
|
|
61
|
+
private val failedPreloads = AtomicInteger(0)
|
|
62
|
+
private val instancesUsed = AtomicInteger(0)
|
|
63
|
+
private val instancesExpired = AtomicInteger(0)
|
|
64
|
+
private val totalDuration = AtomicInteger(0)
|
|
65
|
+
|
|
66
|
+
private var appContext: Context? = null
|
|
67
|
+
private var cleanupJob: Job? = null
|
|
68
|
+
|
|
69
|
+
init {
|
|
70
|
+
Log.d(TAG, "🔧 初始化预加载管理器")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 初始化管理器(注册内存监听)
|
|
75
|
+
*/
|
|
76
|
+
fun initialize(context: Context) {
|
|
77
|
+
appContext = context.applicationContext
|
|
78
|
+
appContext?.registerComponentCallbacks(this)
|
|
79
|
+
|
|
80
|
+
// 启动定期清理任务
|
|
81
|
+
startPeriodicCleanup()
|
|
82
|
+
|
|
83
|
+
Log.d(TAG, "✅ 预加载管理器已初始化,已注册内存监听")
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 启动定期清理过期实例的任务
|
|
88
|
+
*/
|
|
89
|
+
private fun startPeriodicCleanup() {
|
|
90
|
+
cleanupJob?.cancel()
|
|
91
|
+
cleanupJob = preloadScope.launch {
|
|
92
|
+
while (isActive) {
|
|
93
|
+
delay(60_000) // 每分钟检查一次
|
|
94
|
+
cleanupExpiredInstances()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* 清理过期的预加载实例(使用动态 TTL)
|
|
101
|
+
*/
|
|
102
|
+
private fun cleanupExpiredInstances() {
|
|
103
|
+
val now = System.currentTimeMillis()
|
|
104
|
+
var expiredCount = 0
|
|
105
|
+
|
|
106
|
+
val iterator = preloadedMapViews.iterator()
|
|
107
|
+
while (iterator.hasNext()) {
|
|
108
|
+
val instance = iterator.next()
|
|
109
|
+
// 使用动态 TTL
|
|
110
|
+
if (now - instance.timestamp > currentTTL) {
|
|
111
|
+
try {
|
|
112
|
+
instance.mapView.onDestroy()
|
|
113
|
+
iterator.remove()
|
|
114
|
+
expiredCount++
|
|
115
|
+
} catch (e: Exception) {
|
|
116
|
+
Log.e(TAG, "清理过期实例失败: ${e.message}", e)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (expiredCount > 0) {
|
|
122
|
+
instancesExpired.addAndGet(expiredCount)
|
|
123
|
+
Log.i(TAG, "🧹 清理了 $expiredCount 个过期实例(总计: ${instancesExpired.get()},当前TTL: ${currentTTL/1000}秒)")
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 内存警告回调
|
|
129
|
+
*/
|
|
130
|
+
@Deprecated("Deprecated in Java")
|
|
131
|
+
override fun onLowMemory() {
|
|
132
|
+
Log.w(TAG, "⚠️ 收到低内存警告,清理预加载池")
|
|
133
|
+
clearPool()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 内存trim回调
|
|
138
|
+
*/
|
|
139
|
+
override fun onTrimMemory(level: Int) {
|
|
140
|
+
when (level) {
|
|
141
|
+
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL,
|
|
142
|
+
ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> {
|
|
143
|
+
Log.w(TAG, "⚠️ 内存严重不足 (level: $level),清理预加载池")
|
|
144
|
+
clearPool()
|
|
145
|
+
}
|
|
146
|
+
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
|
|
147
|
+
ComponentCallbacks2.TRIM_MEMORY_MODERATE -> {
|
|
148
|
+
Log.w(TAG, "⚠️ 内存不足 (level: $level),清理部分实例")
|
|
149
|
+
// 只清理一半
|
|
150
|
+
val halfSize = preloadedMapViews.size / 2
|
|
151
|
+
repeat(halfSize) {
|
|
152
|
+
preloadedMapViews.poll()?.mapView?.onDestroy()
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
159
|
+
// 不需要处理
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 开始预加载地图实例(自适应版本)
|
|
164
|
+
* @param context Android 上下文
|
|
165
|
+
* @param poolSize 预加载的地图实例数量(会根据内存自适应调整)
|
|
166
|
+
*/
|
|
167
|
+
fun startPreload(context: Context, poolSize: Int) {
|
|
168
|
+
if (isPreloading.get()) {
|
|
169
|
+
Log.w(TAG, "⚠️ 预加载已在进行中")
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 动态计算最优池大小
|
|
174
|
+
val adaptiveMaxPoolSize = calculateAdaptivePoolSize(context)
|
|
175
|
+
currentMaxPoolSize = adaptiveMaxPoolSize
|
|
176
|
+
|
|
177
|
+
// 动态调整 TTL
|
|
178
|
+
currentTTL = calculateAdaptiveTTL(context)
|
|
179
|
+
|
|
180
|
+
// 检查内存是否充足
|
|
181
|
+
if (!hasEnoughMemory(context)) {
|
|
182
|
+
Log.w(TAG, "⚠️ 内存不足,跳过预加载")
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
isPreloading.set(true)
|
|
187
|
+
val targetSize = minOf(poolSize, adaptiveMaxPoolSize)
|
|
188
|
+
Log.i(TAG, "🚀 开始预加载 $targetSize 个地图实例 (自适应池大小: $adaptiveMaxPoolSize, TTL: ${currentTTL/1000}秒)")
|
|
189
|
+
|
|
190
|
+
val startTime = System.currentTimeMillis()
|
|
191
|
+
totalPreloads.incrementAndGet()
|
|
192
|
+
|
|
193
|
+
preloadScope.launch {
|
|
194
|
+
var successCount = 0
|
|
195
|
+
|
|
196
|
+
repeat(targetSize) { index ->
|
|
197
|
+
try {
|
|
198
|
+
val mapView = createPreloadedMapView(context)
|
|
199
|
+
|
|
200
|
+
withContext(Dispatchers.Main) {
|
|
201
|
+
val instance = PreloadedMapInstance(mapView)
|
|
202
|
+
preloadedMapViews.offer(instance)
|
|
203
|
+
successCount++
|
|
204
|
+
Log.i(TAG, "✅ 预加载实例 ${index + 1}/$targetSize 完成")
|
|
205
|
+
|
|
206
|
+
if (index == targetSize - 1) {
|
|
207
|
+
val duration = (System.currentTimeMillis() - startTime).toInt()
|
|
208
|
+
isPreloading.set(false)
|
|
209
|
+
|
|
210
|
+
if (successCount > 0) {
|
|
211
|
+
successfulPreloads.incrementAndGet()
|
|
212
|
+
totalDuration.addAndGet(duration)
|
|
213
|
+
} else {
|
|
214
|
+
failedPreloads.incrementAndGet()
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Log.i(TAG, "🎉 所有实例预加载完成(耗时: ${duration}ms)")
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
} catch (e: Exception) {
|
|
221
|
+
Log.e(TAG, "❌ 预加载实例 ${index + 1} 失败: ${e.message}", e)
|
|
222
|
+
if (index == targetSize - 1) {
|
|
223
|
+
isPreloading.set(false)
|
|
224
|
+
if (successCount == 0) {
|
|
225
|
+
failedPreloads.incrementAndGet()
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 计算自适应池大小
|
|
235
|
+
* 根据可用内存动态调整池大小
|
|
236
|
+
*/
|
|
237
|
+
private fun calculateAdaptivePoolSize(context: Context): Int {
|
|
238
|
+
val availableMB = getAvailableMemoryMB(context)
|
|
239
|
+
|
|
240
|
+
return when {
|
|
241
|
+
availableMB >= 500 -> {
|
|
242
|
+
Log.i(TAG, "📊 高内存设备 (${availableMB}MB),池大小: $MAX_POOL_SIZE_HIGH_MEMORY")
|
|
243
|
+
MAX_POOL_SIZE_HIGH_MEMORY
|
|
244
|
+
}
|
|
245
|
+
availableMB >= 300 -> {
|
|
246
|
+
Log.i(TAG, "📊 中等内存设备 (${availableMB}MB),池大小: $MAX_POOL_SIZE_MEDIUM_MEMORY")
|
|
247
|
+
MAX_POOL_SIZE_MEDIUM_MEMORY
|
|
248
|
+
}
|
|
249
|
+
availableMB >= 150 -> {
|
|
250
|
+
Log.i(TAG, "📊 低内存设备 (${availableMB}MB),池大小: $MAX_POOL_SIZE_LOW_MEMORY")
|
|
251
|
+
MAX_POOL_SIZE_LOW_MEMORY
|
|
252
|
+
}
|
|
253
|
+
else -> {
|
|
254
|
+
Log.w(TAG, "⚠️ 内存极低 (${availableMB}MB),禁用预加载")
|
|
255
|
+
0
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* 计算自适应 TTL
|
|
262
|
+
* 根据内存压力动态调整过期时间
|
|
263
|
+
*/
|
|
264
|
+
private fun calculateAdaptiveTTL(context: Context): Long {
|
|
265
|
+
val availableMB = getAvailableMemoryMB(context)
|
|
266
|
+
val totalMB = getTotalMemoryMB(context)
|
|
267
|
+
val usagePercent = ((totalMB - availableMB).toFloat() / totalMB * 100).toInt()
|
|
268
|
+
|
|
269
|
+
return when {
|
|
270
|
+
usagePercent < 60 -> {
|
|
271
|
+
memoryPressureLevel = 0
|
|
272
|
+
Log.i(TAG, "📊 内存充足 (使用率: $usagePercent%),TTL: ${TTL_NORMAL/1000}秒")
|
|
273
|
+
TTL_NORMAL
|
|
274
|
+
}
|
|
275
|
+
usagePercent < 80 -> {
|
|
276
|
+
memoryPressureLevel = 1
|
|
277
|
+
Log.i(TAG, "📊 内存压力 (使用率: $usagePercent%),TTL: ${TTL_MEMORY_PRESSURE/1000}秒")
|
|
278
|
+
TTL_MEMORY_PRESSURE
|
|
279
|
+
}
|
|
280
|
+
else -> {
|
|
281
|
+
memoryPressureLevel = 2
|
|
282
|
+
Log.w(TAG, "⚠️ 内存严重不足 (使用率: $usagePercent%),TTL: ${TTL_LOW_MEMORY/1000}秒")
|
|
283
|
+
TTL_LOW_MEMORY
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 获取可用内存(MB)
|
|
290
|
+
*/
|
|
291
|
+
private fun getAvailableMemoryMB(context: Context): Long {
|
|
292
|
+
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
|
|
293
|
+
val memoryInfo = ActivityManager.MemoryInfo()
|
|
294
|
+
activityManager?.getMemoryInfo(memoryInfo)
|
|
295
|
+
return memoryInfo.availMem / (1024 * 1024)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* 获取总内存(MB)
|
|
300
|
+
*/
|
|
301
|
+
private fun getTotalMemoryMB(context: Context): Long {
|
|
302
|
+
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
|
|
303
|
+
val memoryInfo = ActivityManager.MemoryInfo()
|
|
304
|
+
activityManager?.getMemoryInfo(memoryInfo)
|
|
305
|
+
return memoryInfo.totalMem / (1024 * 1024)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* 检查是否有足够的内存
|
|
310
|
+
*/
|
|
311
|
+
private fun hasEnoughMemory(context: Context): Boolean {
|
|
312
|
+
val availableMB = getAvailableMemoryMB(context)
|
|
313
|
+
return availableMB > MIN_MEMORY_THRESHOLD_MB
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 创建预加载的地图视图
|
|
318
|
+
* @param context Android 上下文
|
|
319
|
+
* @return 预加载的地图视图实例
|
|
320
|
+
*/
|
|
321
|
+
private suspend fun createPreloadedMapView(context: Context): MapView {
|
|
322
|
+
return withContext(Dispatchers.Main) {
|
|
323
|
+
val mapView = MapView(context)
|
|
324
|
+
val aMap = mapView.map
|
|
325
|
+
|
|
326
|
+
// 基础配置
|
|
327
|
+
aMap.mapType = AMap.MAP_TYPE_NORMAL
|
|
328
|
+
aMap.isMyLocationEnabled = false
|
|
329
|
+
aMap.uiSettings.isCompassEnabled = false
|
|
330
|
+
aMap.uiSettings.isScaleControlsEnabled = false
|
|
331
|
+
aMap.uiSettings.isZoomControlsEnabled = false
|
|
332
|
+
aMap.uiSettings.isRotateGesturesEnabled = true
|
|
333
|
+
aMap.uiSettings.isScrollGesturesEnabled = true
|
|
334
|
+
aMap.uiSettings.isZoomGesturesEnabled = true
|
|
335
|
+
|
|
336
|
+
// 预加载中心区域(北京天安门)
|
|
337
|
+
val cameraPosition = CameraPosition(
|
|
338
|
+
LatLng(39.9042, 116.4074),
|
|
339
|
+
12f, // zoom
|
|
340
|
+
0f, // tilt
|
|
341
|
+
0f // bearing
|
|
342
|
+
)
|
|
343
|
+
aMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition))
|
|
344
|
+
|
|
345
|
+
// 触发地图初始化
|
|
346
|
+
mapView.onCreate(null)
|
|
347
|
+
|
|
348
|
+
mapView
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* 获取一个预加载的地图实例(使用动态 TTL)
|
|
354
|
+
* @return 预加载的地图视图,如果池为空则返回 null
|
|
355
|
+
*/
|
|
356
|
+
fun getPreloadedMapView(): MapView? {
|
|
357
|
+
val now = System.currentTimeMillis()
|
|
358
|
+
|
|
359
|
+
// 检查并移除过期实例(使用动态 TTL)
|
|
360
|
+
while (true) {
|
|
361
|
+
val instance = preloadedMapViews.peek() ?: break
|
|
362
|
+
|
|
363
|
+
if (now - instance.timestamp > currentTTL) {
|
|
364
|
+
preloadedMapViews.poll()
|
|
365
|
+
try {
|
|
366
|
+
instance.mapView.onDestroy()
|
|
367
|
+
instancesExpired.incrementAndGet()
|
|
368
|
+
Log.i(TAG, "🗑️ 预加载实例已过期(TTL: ${currentTTL/1000}秒),已删除")
|
|
369
|
+
} catch (e: Exception) {
|
|
370
|
+
Log.e(TAG, "清理过期实例失败: ${e.message}", e)
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
break
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
val instance = preloadedMapViews.poll()
|
|
378
|
+
|
|
379
|
+
if (instance != null) {
|
|
380
|
+
instancesUsed.incrementAndGet()
|
|
381
|
+
Log.i(TAG, "📤 使用预加载实例,剩余: ${preloadedMapViews.size},总使用: ${instancesUsed.get()}")
|
|
382
|
+
|
|
383
|
+
// 触发自动补充(延迟执行,避免影响当前页面渲染)
|
|
384
|
+
triggerRefill()
|
|
385
|
+
|
|
386
|
+
return instance.mapView
|
|
387
|
+
} else {
|
|
388
|
+
Log.w(TAG, "⚠️ 预加载池为空,返回 null")
|
|
389
|
+
// 尝试触发补充,以便下次使用
|
|
390
|
+
triggerRefill()
|
|
391
|
+
return null
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* 触发自动补充机制
|
|
397
|
+
*/
|
|
398
|
+
private fun triggerRefill() {
|
|
399
|
+
if (isPreloading.get()) return
|
|
400
|
+
|
|
401
|
+
// 延迟 5 秒后尝试补充,避免抢占当前 UI 资源
|
|
402
|
+
preloadScope.launch {
|
|
403
|
+
delay(5000)
|
|
404
|
+
if (!isPreloading.get() && preloadedMapViews.size < currentMaxPoolSize) {
|
|
405
|
+
appContext?.let { context ->
|
|
406
|
+
Log.i(TAG, "🔄 触发自动补充预加载池")
|
|
407
|
+
withContext(Dispatchers.Main) {
|
|
408
|
+
startPreload(context, currentMaxPoolSize)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* 清空预加载池
|
|
417
|
+
*/
|
|
418
|
+
fun clearPool() {
|
|
419
|
+
val count = preloadedMapViews.size
|
|
420
|
+
preloadedMapViews.forEach { instance ->
|
|
421
|
+
try {
|
|
422
|
+
instance.mapView.onDestroy()
|
|
423
|
+
} catch (e: Exception) {
|
|
424
|
+
Log.e(TAG, "清理地图实例失败: ${e.message}", e)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
preloadedMapViews.clear()
|
|
428
|
+
Log.i(TAG, "🗑️ 预加载池已清空,清理了 $count 个实例")
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* 获取预加载状态(包含动态配置信息)
|
|
433
|
+
* @return 预加载状态信息
|
|
434
|
+
*/
|
|
435
|
+
fun getStatus(): Map<String, Any> {
|
|
436
|
+
return mapOf(
|
|
437
|
+
"poolSize" to preloadedMapViews.size,
|
|
438
|
+
"isPreloading" to isPreloading.get(),
|
|
439
|
+
"maxPoolSize" to currentMaxPoolSize,
|
|
440
|
+
"currentTTL" to currentTTL,
|
|
441
|
+
"memoryPressureLevel" to memoryPressureLevel,
|
|
442
|
+
"isAdaptive" to true
|
|
443
|
+
)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* 检查是否有可用的预加载实例
|
|
448
|
+
* @return 是否有可用实例
|
|
449
|
+
*/
|
|
450
|
+
fun hasPreloadedMapView(): Boolean {
|
|
451
|
+
return preloadedMapViews.isNotEmpty()
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* 获取性能统计信息(包含内存信息)
|
|
456
|
+
*/
|
|
457
|
+
fun getPerformanceMetrics(): Map<String, Any> {
|
|
458
|
+
val total = totalPreloads.get()
|
|
459
|
+
val successful = successfulPreloads.get()
|
|
460
|
+
val avgDuration = if (successful > 0) totalDuration.get() / successful else 0
|
|
461
|
+
val successRate = if (total > 0) (successful.toFloat() / total * 100) else 0f
|
|
462
|
+
|
|
463
|
+
val availableMB = appContext?.let { getAvailableMemoryMB(it) } ?: 0
|
|
464
|
+
val totalMB = appContext?.let { getTotalMemoryMB(it) } ?: 0
|
|
465
|
+
val usagePercent = if (totalMB > 0) ((totalMB - availableMB).toFloat() / totalMB * 100).toInt() else 0
|
|
466
|
+
|
|
467
|
+
return mapOf(
|
|
468
|
+
"totalPreloads" to total,
|
|
469
|
+
"successfulPreloads" to successful,
|
|
470
|
+
"failedPreloads" to failedPreloads.get(),
|
|
471
|
+
"averageDuration" to avgDuration,
|
|
472
|
+
"instancesUsed" to instancesUsed.get(),
|
|
473
|
+
"instancesExpired" to instancesExpired.get(),
|
|
474
|
+
"successRate" to successRate,
|
|
475
|
+
"currentMaxPoolSize" to currentMaxPoolSize,
|
|
476
|
+
"currentTTL" to currentTTL,
|
|
477
|
+
"memoryPressureLevel" to memoryPressureLevel,
|
|
478
|
+
"availableMemoryMB" to availableMB,
|
|
479
|
+
"totalMemoryMB" to totalMB,
|
|
480
|
+
"memoryUsagePercent" to usagePercent
|
|
481
|
+
)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* 清理资源
|
|
486
|
+
*/
|
|
487
|
+
fun cleanup() {
|
|
488
|
+
clearPool()
|
|
489
|
+
cleanupJob?.cancel()
|
|
490
|
+
preloadScope.cancel()
|
|
491
|
+
appContext?.unregisterComponentCallbacks(this)
|
|
492
|
+
Log.i(TAG, "🧹 预加载管理器已清理")
|
|
493
|
+
}
|
|
494
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
package expo.modules.gaodemap.map.companion
|
|
2
|
+
|
|
3
|
+
import com.amap.api.maps.model.BitmapDescriptor
|
|
4
|
+
import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
5
|
+
import android.graphics.Bitmap
|
|
6
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
7
|
+
|
|
8
|
+
object BitmapDescriptorCache {
|
|
9
|
+
|
|
10
|
+
private val cache = ConcurrentHashMap<String, BitmapDescriptor>()
|
|
11
|
+
|
|
12
|
+
fun get(key: String): BitmapDescriptor? = cache[key]
|
|
13
|
+
|
|
14
|
+
fun put(key: String, bitmap: Bitmap) {
|
|
15
|
+
val descriptor = BitmapDescriptorFactory.fromBitmap(bitmap)
|
|
16
|
+
cache[key] = descriptor
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fun putDescriptor(key: String, descriptor: BitmapDescriptor) {
|
|
20
|
+
cache[key] = descriptor
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
fun clear() {
|
|
24
|
+
cache.clear()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fun remove(key: String) {
|
|
28
|
+
cache.remove(key)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
package expo.modules.gaodemap.map.companion
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap
|
|
4
|
+
import android.util.LruCache
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 简单的 Bitmap LRU 缓存。
|
|
8
|
+
* key 的格式使用: "<fingerprint>|<width>x<height>"
|
|
9
|
+
*/
|
|
10
|
+
object IconBitmapCache {
|
|
11
|
+
private val maxMemoryKb = (Runtime.getRuntime().maxMemory() / 1024).toInt()
|
|
12
|
+
// 使用 1/8 可用内存作为缓存容积(可按需调整)
|
|
13
|
+
private val cacheSizeKb = maxMemoryKb / 8
|
|
14
|
+
|
|
15
|
+
private val cache = object : LruCache<String, Bitmap>(cacheSizeKb) {
|
|
16
|
+
override fun sizeOf(key: String, value: Bitmap): Int {
|
|
17
|
+
// 以 KB 为单位
|
|
18
|
+
return value.byteCount / 1024
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fun put(key: String, bitmap: Bitmap) {
|
|
23
|
+
if (get(key) == null) {
|
|
24
|
+
cache.put(key, bitmap)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fun get(key: String): Bitmap? = cache.get(key)
|
|
29
|
+
|
|
30
|
+
fun remove(key: String) {
|
|
31
|
+
cache.remove(key)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
fun clear() {
|
|
35
|
+
cache.evictAll()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.gaodemap.map.managers
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint
|
|
3
4
|
import android.content.Context
|
|
4
5
|
import android.graphics.BitmapFactory
|
|
5
6
|
import android.location.Location
|
|
@@ -161,6 +162,7 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
161
162
|
* 设置用户位置样式
|
|
162
163
|
* 统一 iOS 和 Android 的 API
|
|
163
164
|
*/
|
|
165
|
+
@SuppressLint("DiscouragedApi")
|
|
164
166
|
fun setUserLocationRepresentation(config: Map<String, Any>) {
|
|
165
167
|
if (currentLocationStyle == null) {
|
|
166
168
|
currentLocationStyle = MyLocationStyle().apply {
|
|
@@ -172,6 +174,30 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
172
174
|
|
|
173
175
|
val style = currentLocationStyle!!
|
|
174
176
|
|
|
177
|
+
// 定位蓝点展现模式 (locationType) - Android 支持8种模式
|
|
178
|
+
val locationType = config["locationType"] as? String
|
|
179
|
+
if (locationType != null) {
|
|
180
|
+
val locationTypeValue = when (locationType) {
|
|
181
|
+
"SHOW" -> MyLocationStyle.LOCATION_TYPE_SHOW
|
|
182
|
+
"LOCATE" -> MyLocationStyle.LOCATION_TYPE_LOCATE
|
|
183
|
+
"FOLLOW" -> MyLocationStyle.LOCATION_TYPE_FOLLOW
|
|
184
|
+
"MAP_ROTATE" -> MyLocationStyle.LOCATION_TYPE_MAP_ROTATE
|
|
185
|
+
"LOCATION_ROTATE" -> MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE
|
|
186
|
+
"LOCATION_ROTATE_NO_CENTER" -> MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER
|
|
187
|
+
"FOLLOW_NO_CENTER" -> MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER
|
|
188
|
+
"MAP_ROTATE_NO_CENTER" -> MyLocationStyle.LOCATION_TYPE_MAP_ROTATE_NO_CENTER
|
|
189
|
+
else -> MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE // 默认值
|
|
190
|
+
}
|
|
191
|
+
style.myLocationType(locationTypeValue)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 是否显示定位蓝点 (showMyLocation) - Android 5.1.0+ 支持
|
|
195
|
+
// 注意:这个属性在 iOS 中没有对应项,是 Android 特有的
|
|
196
|
+
val showMyLocation = config["showMyLocation"] as? Boolean
|
|
197
|
+
if (showMyLocation != null) {
|
|
198
|
+
style.showMyLocation(showMyLocation)
|
|
199
|
+
}
|
|
200
|
+
|
|
175
201
|
// 是否显示精度圈 (showsAccuracyRing) - 先处理这个,设置默认值
|
|
176
202
|
val showsAccuracyRing = config["showsAccuracyRing"] as? Boolean ?: true
|
|
177
203
|
if (!showsAccuracyRing) {
|
|
@@ -198,6 +224,13 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
198
224
|
}
|
|
199
225
|
}
|
|
200
226
|
|
|
227
|
+
// 定位图标锚点 (anchor) - Android 支持
|
|
228
|
+
val anchorU = config["anchorU"] as? Number
|
|
229
|
+
val anchorV = config["anchorV"] as? Number
|
|
230
|
+
if (anchorU != null && anchorV != null) {
|
|
231
|
+
style.anchor(anchorU.toFloat(), anchorV.toFloat())
|
|
232
|
+
}
|
|
233
|
+
|
|
201
234
|
// 自定义图标 (image)
|
|
202
235
|
val imagePath = config["image"] as? String
|
|
203
236
|
if (imagePath != null && imagePath.isNotEmpty()) {
|
|
@@ -316,4 +349,47 @@ class UIManager(private val aMap: AMap, private val context: Context) : Location
|
|
|
316
349
|
else -> AMap.MAP_TYPE_NORMAL // 标准地图
|
|
317
350
|
}
|
|
318
351
|
}
|
|
352
|
+
|
|
353
|
+
// ==================== 自定义地图样式 ====================
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* 设置自定义地图样式
|
|
357
|
+
* @param styleData 样式数据,支持以下格式:
|
|
358
|
+
* - styleId: String - 在线样式ID(从高德开放平台获取)
|
|
359
|
+
* - styleDataPath: String - 本地样式文件路径
|
|
360
|
+
* - extraStyleDataPath: String - 额外样式文件路径(可选)
|
|
361
|
+
*/
|
|
362
|
+
fun setCustomMapStyle(styleData: Map<String, Any>) {
|
|
363
|
+
// 在线样式 ID
|
|
364
|
+
val styleId = styleData["styleId"] as? String
|
|
365
|
+
if (!styleId.isNullOrEmpty()) {
|
|
366
|
+
val options = com.amap.api.maps.model.CustomMapStyleOptions()
|
|
367
|
+
options.isEnable = true
|
|
368
|
+
options.styleId = styleId
|
|
369
|
+
aMap.setCustomMapStyle(options)
|
|
370
|
+
return
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// 本地样式文件
|
|
374
|
+
val styleDataPath = styleData["styleDataPath"] as? String
|
|
375
|
+
if (!styleDataPath.isNullOrEmpty()) {
|
|
376
|
+
val options = com.amap.api.maps.model.CustomMapStyleOptions()
|
|
377
|
+
options.isEnable = true
|
|
378
|
+
options.styleDataPath = styleDataPath
|
|
379
|
+
|
|
380
|
+
// 额外样式文件(可选)
|
|
381
|
+
val extraPath = styleData["extraStyleDataPath"] as? String
|
|
382
|
+
if (!extraPath.isNullOrEmpty()) {
|
|
383
|
+
options.styleExtraPath = extraPath
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
aMap.setCustomMapStyle(options)
|
|
387
|
+
return
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// 如果没有提供任何样式,禁用自定义样式
|
|
391
|
+
val options = com.amap.api.maps.model.CustomMapStyleOptions()
|
|
392
|
+
options.isEnable = false
|
|
393
|
+
aMap.setCustomMapStyle(options)
|
|
394
|
+
}
|
|
319
395
|
}
|
|
@@ -4,6 +4,7 @@ import android.content.Context
|
|
|
4
4
|
import com.amap.api.location.AMapLocation
|
|
5
5
|
import com.amap.api.location.AMapLocationClient
|
|
6
6
|
import com.amap.api.location.AMapLocationClientOption
|
|
7
|
+
import com.amap.api.maps.CoordinateConverter
|
|
7
8
|
import com.amap.api.maps.model.LatLng
|
|
8
9
|
import expo.modules.kotlin.Promise
|
|
9
10
|
import expo.modules.gaodemap.map.services.LocationForegroundService
|
|
@@ -135,11 +136,22 @@ class LocationManager(context: Context) {
|
|
|
135
136
|
|
|
136
137
|
try {
|
|
137
138
|
val sourceLatLng = LatLng(lat, lng)
|
|
138
|
-
|
|
139
|
+
val converter = CoordinateConverter(appContext)
|
|
140
|
+
// 0: GPS/Google, 1: MapBar, 2: Baidu, 3: MapABC/SoSo
|
|
141
|
+
converter.from(when(type) {
|
|
142
|
+
0 -> CoordinateConverter.CoordType.GPS
|
|
143
|
+
1 -> CoordinateConverter.CoordType.MAPBAR
|
|
144
|
+
2 -> CoordinateConverter.CoordType.BAIDU
|
|
145
|
+
3 -> CoordinateConverter.CoordType.MAPABC
|
|
146
|
+
else -> CoordinateConverter.CoordType.GPS
|
|
147
|
+
})
|
|
148
|
+
converter.coord(sourceLatLng)
|
|
149
|
+
val desLatLng = converter.convert()
|
|
150
|
+
|
|
139
151
|
promise.resolve(
|
|
140
152
|
mapOf(
|
|
141
|
-
"latitude" to
|
|
142
|
-
"longitude" to
|
|
153
|
+
"latitude" to desLatLng.latitude,
|
|
154
|
+
"longitude" to desLatLng.longitude
|
|
143
155
|
)
|
|
144
156
|
)
|
|
145
157
|
} catch (e: Exception) {
|