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
- val locationType = if (followUserLocation) {
87
- MyLocationStyle.LOCATION_TYPE_FOLLOW
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
- MyLocationStyle.LOCATION_TYPE_SHOW
90
- }
91
- currentLocationStyle?.myLocationType(locationType)
92
- aMap.myLocationStyle = currentLocationStyle
93
-
94
- // 设置定位监听
95
- aMap.setLocationSource(object : LocationSource {
96
- override fun activate(listener: LocationSource.OnLocationChangedListener?) {
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
- override fun deactivate() {}
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
- // 精度圈边线颜色 (strokeColor)
130
- config["strokeColor"]?.let {
131
- style.strokeColor(ColorParser.parseColor(it))
132
- }
133
-
134
- // 精度圈填充颜色 (fillColor)
135
- config["fillColor"]?.let {
136
- style.radiusFillColor(ColorParser.parseColor(it))
137
- }
138
-
139
- // 精度圈边线宽度 (lineWidth)
140
- (config["lineWidth"] as? Number)?.let {
141
- style.strokeWidth(it.toFloat())
142
- }
143
-
144
- // 是否显示精度圈 (showsAccuracyRing)
145
- (config["showsAccuracyRing"] as? Boolean)?.let { showRing ->
146
- if (!showRing) {
147
- // 不显示精度圈,但要显示蓝点
148
- style.radiusFillColor(android.graphics.Color.TRANSPARENT)
149
- style.strokeColor(android.graphics.Color.TRANSPARENT)
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
- (config["image"] as? String)?.let { imagePath ->
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?.let { bitmap ->
297
+ if (originalBitmap != null) {
168
298
  val scaledBitmap = if (imageWidth != null && imageHeight != null) {
169
- android.graphics.Bitmap.createScaledBitmap(bitmap, imageWidth, imageHeight, true)
170
- } else bitmap
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
- } ?: android.util.Log.e("UIManager", "网络图片加载失败")
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", "加载网络图片异常", e)
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
- imagePath.substringBeforeLast('.'),
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 null
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?.let { bitmap ->
354
+ if (originalBitmap != null) {
202
355
  val scaledBitmap = if (imageWidth != null && imageHeight != null) {
203
- android.graphics.Bitmap.createScaledBitmap(bitmap, imageWidth, imageHeight, true)
204
- } else bitmap
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
- } ?: android.util.Log.e("UIManager", "本地图片加载失败")
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", "加载本地图片异常", e)
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "一个功能完整的高德地图 React Native 组件库,基于 Expo Modules 开发,提供地图显示、定位、覆盖物等功能。",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",