expo-gaode-map 1.1.1 → 1.1.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.
|
@@ -2,6 +2,10 @@ package expo.modules.gaodemap.managers
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.graphics.BitmapFactory
|
|
5
|
+
import android.location.Location
|
|
6
|
+
import android.location.LocationListener
|
|
7
|
+
import android.location.LocationManager as AndroidLocationManager
|
|
8
|
+
import android.os.Bundle
|
|
5
9
|
import com.amap.api.maps.AMap
|
|
6
10
|
import com.amap.api.maps.LocationSource
|
|
7
11
|
import com.amap.api.maps.model.BitmapDescriptorFactory
|
|
@@ -14,10 +18,13 @@ import java.net.URL
|
|
|
14
18
|
* UI 和手势管理器
|
|
15
19
|
* 负责地图控件显示、手势控制、图层显示等
|
|
16
20
|
*/
|
|
17
|
-
class UIManager(private val aMap: AMap, private val context: Context) {
|
|
21
|
+
class UIManager(private val aMap: AMap, private val context: Context) : LocationListener {
|
|
18
22
|
|
|
19
23
|
var onLocationChanged: ((latitude: Double, longitude: Double, accuracy: Float) -> Unit)? = null
|
|
20
24
|
|
|
25
|
+
private var locationManager: AndroidLocationManager? = null
|
|
26
|
+
private var locationChangedListener: LocationSource.OnLocationChangedListener? = null
|
|
27
|
+
|
|
21
28
|
// ==================== 控件显示 ====================
|
|
22
29
|
|
|
23
30
|
/**
|
|
@@ -79,27 +86,37 @@ class UIManager(private val aMap: AMap, private val context: Context) {
|
|
|
79
86
|
* 设置是否显示用户位置
|
|
80
87
|
*/
|
|
81
88
|
fun setShowsUserLocation(show: Boolean, followUserLocation: Boolean = false) {
|
|
89
|
+
android.util.Log.d("UIManager", "🔵 setShowsUserLocation: show=$show, follow=$followUserLocation")
|
|
90
|
+
|
|
82
91
|
if (show) {
|
|
92
|
+
// 创建默认的定位样式
|
|
83
93
|
if (currentLocationStyle == null) {
|
|
84
|
-
currentLocationStyle = MyLocationStyle()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
currentLocationStyle = MyLocationStyle().apply {
|
|
95
|
+
// 根据是否跟随设置定位类型
|
|
96
|
+
val locationType = if (followUserLocation) {
|
|
97
|
+
MyLocationStyle.LOCATION_TYPE_FOLLOW // 连续定位并跟随
|
|
98
|
+
} else {
|
|
99
|
+
MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE // 连续定位,点会旋转
|
|
100
|
+
}
|
|
101
|
+
myLocationType(locationType)
|
|
102
|
+
interval(2000) // 2秒定位一次
|
|
103
|
+
showMyLocation(true)
|
|
104
|
+
}
|
|
105
|
+
android.util.Log.d("UIManager", "✨ 创建默认 MyLocationStyle")
|
|
88
106
|
} else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
// 更新定位类型
|
|
108
|
+
val locationType = if (followUserLocation) {
|
|
109
|
+
MyLocationStyle.LOCATION_TYPE_FOLLOW
|
|
110
|
+
} else {
|
|
111
|
+
MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE
|
|
112
|
+
}
|
|
113
|
+
currentLocationStyle?.apply {
|
|
114
|
+
myLocationType(locationType)
|
|
115
|
+
interval(2000)
|
|
98
116
|
}
|
|
99
|
-
|
|
100
|
-
})
|
|
117
|
+
}
|
|
101
118
|
|
|
102
|
-
//
|
|
119
|
+
// 监听定位变化(用于通知 React Native)
|
|
103
120
|
aMap.setOnMyLocationChangeListener { location ->
|
|
104
121
|
onLocationChanged?.invoke(
|
|
105
122
|
location.latitude,
|
|
@@ -108,112 +125,266 @@ class UIManager(private val aMap: AMap, private val context: Context) {
|
|
|
108
125
|
)
|
|
109
126
|
}
|
|
110
127
|
|
|
128
|
+
// 应用定位样式
|
|
129
|
+
aMap.myLocationStyle = currentLocationStyle
|
|
130
|
+
|
|
131
|
+
// 启用定位(使用高德地图自己的定位)
|
|
111
132
|
aMap.isMyLocationEnabled = true
|
|
133
|
+
android.util.Log.d("UIManager", "✅ 定位已启用")
|
|
134
|
+
|
|
112
135
|
} else {
|
|
113
136
|
aMap.setOnMyLocationChangeListener(null)
|
|
114
137
|
aMap.isMyLocationEnabled = false
|
|
138
|
+
android.util.Log.d("UIManager", "❌ 定位已禁用")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 启动真实的系统定位
|
|
144
|
+
*/
|
|
145
|
+
private fun startRealLocation() {
|
|
146
|
+
try {
|
|
147
|
+
if (locationManager == null) {
|
|
148
|
+
locationManager = context.getSystemService(Context.LOCATION_SERVICE) as AndroidLocationManager
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
val providers = locationManager?.getProviders(true) ?: emptyList()
|
|
152
|
+
android.util.Log.d("UIManager", "📡 可用的定位提供者: $providers")
|
|
153
|
+
|
|
154
|
+
// 优先使用 GPS,其次是网络定位
|
|
155
|
+
val provider = when {
|
|
156
|
+
providers.contains(AndroidLocationManager.GPS_PROVIDER) -> {
|
|
157
|
+
android.util.Log.d("UIManager", "✅ 使用 GPS 定位")
|
|
158
|
+
AndroidLocationManager.GPS_PROVIDER
|
|
159
|
+
}
|
|
160
|
+
providers.contains(AndroidLocationManager.NETWORK_PROVIDER) -> {
|
|
161
|
+
android.util.Log.d("UIManager", "✅ 使用网络定位")
|
|
162
|
+
AndroidLocationManager.NETWORK_PROVIDER
|
|
163
|
+
}
|
|
164
|
+
else -> {
|
|
165
|
+
android.util.Log.e("UIManager", "❌ 没有可用的定位提供者")
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 请求位置更新
|
|
171
|
+
locationManager?.requestLocationUpdates(
|
|
172
|
+
provider,
|
|
173
|
+
2000L, // 最小时间间隔 2秒
|
|
174
|
+
10f, // 最小距离变化 10米
|
|
175
|
+
this
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
// 立即获取最后已知位置
|
|
179
|
+
val lastLocation = locationManager?.getLastKnownLocation(provider)
|
|
180
|
+
if (lastLocation != null) {
|
|
181
|
+
android.util.Log.d("UIManager", "📍 获取到最后已知位置: ${lastLocation.latitude}, ${lastLocation.longitude}")
|
|
182
|
+
onLocationChanged(lastLocation)
|
|
183
|
+
} else {
|
|
184
|
+
android.util.Log.d("UIManager", "⏳ 等待首次定位...")
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
} catch (e: SecurityException) {
|
|
188
|
+
android.util.Log.e("UIManager", "❌ 定位权限未授予: ${e.message}")
|
|
189
|
+
} catch (e: Exception) {
|
|
190
|
+
android.util.Log.e("UIManager", "❌ 启动定位失败: ${e.message}", e)
|
|
115
191
|
}
|
|
116
192
|
}
|
|
117
193
|
|
|
194
|
+
/**
|
|
195
|
+
* 停止系统定位
|
|
196
|
+
*/
|
|
197
|
+
private fun stopRealLocation() {
|
|
198
|
+
try {
|
|
199
|
+
locationManager?.removeUpdates(this)
|
|
200
|
+
android.util.Log.d("UIManager", "🛑 已停止系统定位")
|
|
201
|
+
} catch (e: Exception) {
|
|
202
|
+
android.util.Log.e("UIManager", "停止定位失败: ${e.message}")
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 位置变化回调
|
|
208
|
+
*/
|
|
209
|
+
override fun onLocationChanged(location: Location) {
|
|
210
|
+
android.util.Log.d("UIManager", "📍📍📍 系统定位回调: lat=${location.latitude}, lng=${location.longitude}, accuracy=${location.accuracy}m")
|
|
211
|
+
|
|
212
|
+
// 通知高德地图
|
|
213
|
+
locationChangedListener?.onLocationChanged(location)
|
|
214
|
+
|
|
215
|
+
// 通知 React Native
|
|
216
|
+
onLocationChanged?.invoke(
|
|
217
|
+
location.latitude,
|
|
218
|
+
location.longitude,
|
|
219
|
+
location.accuracy
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
|
|
224
|
+
android.util.Log.d("UIManager", "定位状态变化: provider=$provider, status=$status")
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
override fun onProviderEnabled(provider: String) {
|
|
228
|
+
android.util.Log.d("UIManager", "✅ 定位提供者已启用: $provider")
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
override fun onProviderDisabled(provider: String) {
|
|
232
|
+
android.util.Log.d("UIManager", "❌ 定位提供者已禁用: $provider")
|
|
233
|
+
}
|
|
234
|
+
|
|
118
235
|
/**
|
|
119
236
|
* 设置用户位置样式
|
|
120
237
|
* 统一 iOS 和 Android 的 API
|
|
121
238
|
*/
|
|
122
239
|
fun setUserLocationRepresentation(config: Map<String, Any>) {
|
|
240
|
+
android.util.Log.d("UIManager", "🎨 setUserLocationRepresentation 被调用,配置: $config")
|
|
241
|
+
|
|
123
242
|
if (currentLocationStyle == null) {
|
|
124
|
-
currentLocationStyle = MyLocationStyle()
|
|
243
|
+
currentLocationStyle = MyLocationStyle().apply {
|
|
244
|
+
myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE)
|
|
245
|
+
interval(2000)
|
|
246
|
+
showMyLocation(true)
|
|
247
|
+
}
|
|
248
|
+
android.util.Log.d("UIManager", "创建新的 MyLocationStyle")
|
|
125
249
|
}
|
|
126
250
|
|
|
127
251
|
val style = currentLocationStyle!!
|
|
128
252
|
|
|
129
|
-
//
|
|
130
|
-
config["
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
253
|
+
// 是否显示精度圈 (showsAccuracyRing) - 先处理这个,设置默认值
|
|
254
|
+
val showsAccuracyRing = config["showsAccuracyRing"] as? Boolean ?: true
|
|
255
|
+
if (!showsAccuracyRing) {
|
|
256
|
+
// 不显示精度圈 - 设置透明色
|
|
257
|
+
style.radiusFillColor(android.graphics.Color.TRANSPARENT)
|
|
258
|
+
style.strokeColor(android.graphics.Color.TRANSPARENT)
|
|
259
|
+
style.strokeWidth(0f)
|
|
260
|
+
} else {
|
|
261
|
+
// 显示精度圈 - 使用自定义颜色或默认值
|
|
262
|
+
|
|
263
|
+
// 精度圈填充颜色 (fillColor)
|
|
264
|
+
config["fillColor"]?.let {
|
|
265
|
+
style.radiusFillColor(ColorParser.parseColor(it))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// 精度圈边线颜色 (strokeColor)
|
|
269
|
+
config["strokeColor"]?.let {
|
|
270
|
+
style.strokeColor(ColorParser.parseColor(it))
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// 精度圈边线宽度 (lineWidth)
|
|
274
|
+
(config["lineWidth"] as? Number)?.let {
|
|
275
|
+
style.strokeWidth(it.toFloat())
|
|
150
276
|
}
|
|
151
277
|
}
|
|
152
278
|
|
|
153
279
|
// 自定义图标 (image)
|
|
154
|
-
|
|
280
|
+
val imagePath = config["image"] as? String
|
|
281
|
+
if (imagePath != null && imagePath.isNotEmpty()) {
|
|
282
|
+
android.util.Log.d("UIManager", "开始加载自定义定位图标: $imagePath")
|
|
155
283
|
|
|
156
284
|
// 将 dp 转换为 px (与 iOS points 对应)
|
|
157
285
|
val density = context.resources.displayMetrics.density
|
|
158
286
|
val imageWidth = (config["imageWidth"] as? Number)?.let { (it.toFloat() * density).toInt() }
|
|
159
287
|
val imageHeight = (config["imageHeight"] as? Number)?.let { (it.toFloat() * density).toInt() }
|
|
160
288
|
|
|
289
|
+
android.util.Log.d("UIManager", "图标尺寸: width=$imageWidth, height=$imageHeight, density=$density")
|
|
290
|
+
|
|
161
291
|
// 网络图片需要在后台线程加载
|
|
162
292
|
if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
|
|
163
293
|
Thread {
|
|
164
294
|
try {
|
|
165
295
|
val originalBitmap = BitmapFactory.decodeStream(URL(imagePath).openStream())
|
|
166
296
|
android.os.Handler(android.os.Looper.getMainLooper()).post {
|
|
167
|
-
originalBitmap
|
|
297
|
+
if (originalBitmap != null) {
|
|
168
298
|
val scaledBitmap = if (imageWidth != null && imageHeight != null) {
|
|
169
|
-
android.graphics.Bitmap.createScaledBitmap(
|
|
170
|
-
} else
|
|
299
|
+
android.graphics.Bitmap.createScaledBitmap(originalBitmap, imageWidth, imageHeight, true)
|
|
300
|
+
} else originalBitmap
|
|
171
301
|
|
|
302
|
+
android.util.Log.d("UIManager", "✅ 网络图片加载成功 (${scaledBitmap.width}x${scaledBitmap.height}),应用到定位样式")
|
|
172
303
|
style.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap))
|
|
304
|
+
|
|
305
|
+
// 重新应用样式并确保定位开启
|
|
173
306
|
aMap.myLocationStyle = style
|
|
174
|
-
|
|
307
|
+
|
|
308
|
+
// 如果定位没开,重新开启
|
|
309
|
+
if (!aMap.isMyLocationEnabled) {
|
|
310
|
+
android.util.Log.d("UIManager", "⚠️ 定位未启用,重新启用")
|
|
311
|
+
aMap.isMyLocationEnabled = true
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
android.util.Log.d("UIManager", "✅ 定位样式重新应用完成,定位状态: ${aMap.isMyLocationEnabled}")
|
|
315
|
+
} else {
|
|
316
|
+
android.util.Log.e("UIManager", "❌ 网络图片加载失败: bitmap is null")
|
|
317
|
+
}
|
|
175
318
|
}
|
|
176
319
|
} catch (e: Exception) {
|
|
177
|
-
android.util.Log.e("UIManager", "
|
|
320
|
+
android.util.Log.e("UIManager", "❌ 加载网络图片异常: ${e.message}", e)
|
|
178
321
|
}
|
|
179
322
|
}.start()
|
|
323
|
+
return // 异步加载,提前返回
|
|
180
324
|
} else {
|
|
181
|
-
//
|
|
325
|
+
// 本地图片在后台线程加载
|
|
182
326
|
Thread {
|
|
183
327
|
try {
|
|
184
328
|
val originalBitmap = when {
|
|
185
329
|
imagePath.startsWith("file://") -> {
|
|
330
|
+
android.util.Log.d("UIManager", "加载文件路径图片: ${imagePath.substring(7)}")
|
|
186
331
|
BitmapFactory.decodeFile(imagePath.substring(7))
|
|
187
332
|
}
|
|
188
333
|
else -> {
|
|
334
|
+
// 尝试从资源加载
|
|
335
|
+
val fileName = imagePath.substringBeforeLast('.')
|
|
336
|
+
android.util.Log.d("UIManager", "尝试从资源加载: $fileName")
|
|
189
337
|
val resId = context.resources.getIdentifier(
|
|
190
|
-
|
|
338
|
+
fileName,
|
|
191
339
|
"drawable",
|
|
192
340
|
context.packageName
|
|
193
341
|
)
|
|
342
|
+
android.util.Log.d("UIManager", "资源 ID: $resId")
|
|
194
343
|
if (resId != 0) {
|
|
195
344
|
BitmapFactory.decodeResource(context.resources, resId)
|
|
196
|
-
} else
|
|
345
|
+
} else {
|
|
346
|
+
// 尝试直接作为文件路径
|
|
347
|
+
android.util.Log.d("UIManager", "尝试作为文件路径加载: $imagePath")
|
|
348
|
+
BitmapFactory.decodeFile(imagePath)
|
|
349
|
+
}
|
|
197
350
|
}
|
|
198
351
|
}
|
|
199
352
|
|
|
200
353
|
android.os.Handler(android.os.Looper.getMainLooper()).post {
|
|
201
|
-
originalBitmap
|
|
354
|
+
if (originalBitmap != null) {
|
|
202
355
|
val scaledBitmap = if (imageWidth != null && imageHeight != null) {
|
|
203
|
-
android.graphics.Bitmap.createScaledBitmap(
|
|
204
|
-
} else
|
|
356
|
+
android.graphics.Bitmap.createScaledBitmap(originalBitmap, imageWidth, imageHeight, true)
|
|
357
|
+
} else originalBitmap
|
|
205
358
|
|
|
359
|
+
android.util.Log.d("UIManager", "✅ 本地图片加载成功 (${scaledBitmap.width}x${scaledBitmap.height}),应用到定位样式")
|
|
206
360
|
style.myLocationIcon(BitmapDescriptorFactory.fromBitmap(scaledBitmap))
|
|
361
|
+
|
|
362
|
+
// 重新应用样式并确保定位开启
|
|
207
363
|
aMap.myLocationStyle = style
|
|
208
|
-
|
|
364
|
+
|
|
365
|
+
// 如果定位没开,重新开启
|
|
366
|
+
if (!aMap.isMyLocationEnabled) {
|
|
367
|
+
android.util.Log.d("UIManager", "⚠️ 定位未启用,重新启用")
|
|
368
|
+
aMap.isMyLocationEnabled = true
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
android.util.Log.d("UIManager", "✅ 定位样式重新应用完成,定位状态: ${aMap.isMyLocationEnabled}")
|
|
372
|
+
} else {
|
|
373
|
+
android.util.Log.e("UIManager", "❌ 本地图片加载失败: bitmap is null, path=$imagePath")
|
|
374
|
+
}
|
|
209
375
|
}
|
|
210
376
|
} catch (e: Exception) {
|
|
211
|
-
android.util.Log.e("UIManager", "
|
|
377
|
+
android.util.Log.e("UIManager", "❌ 加载本地图片异常: ${e.message}", e)
|
|
212
378
|
}
|
|
213
379
|
}.start()
|
|
380
|
+
return // 异步加载,提前返回
|
|
214
381
|
}
|
|
382
|
+
} else {
|
|
383
|
+
// 没有自定义图标,使用默认蓝点
|
|
384
|
+
android.util.Log.d("UIManager", "使用默认定位图标(蓝点)")
|
|
215
385
|
}
|
|
216
386
|
|
|
387
|
+
// 立即应用样式(针对没有自定义图标的情况)
|
|
217
388
|
aMap.myLocationStyle = style
|
|
218
389
|
}
|
|
219
390
|
|