expo-gaode-map 2.2.26-next.1 → 2.2.26

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 CHANGED
@@ -44,6 +44,14 @@
44
44
 
45
45
  ## 📦 安装
46
46
 
47
+ > ⚠️ **版本兼容性说明**:
48
+ > - 如果你的项目使用 **Expo SDK 54 及以上**,请安装 默认的 版本。
49
+ > - 如果你的项目使用 **Expo SDK 53 及以下**(如 50, 51, 52, 53),请使用 **V1** 版本(Tag: `v1`)。
50
+ > ```bash
51
+ > npm install expo-gaode-map@v1
52
+ > ```
53
+ > **说明**:V1 版本除了不支持**世界地图**功能外,其余 API 与 V2 (Latest) 版本完全一致。
54
+
47
55
  ### 方案一:仅使用地图和定位(核心包)
48
56
 
49
57
  ```bash
@@ -222,6 +230,7 @@ MIT
222
230
 
223
231
  - [在线文档](https://TomWq.github.io/expo-gaode-map/)
224
232
  - [错误处理指南](./ERROR_HANDLING_GUIDE.md) 🆕
233
+ - [性能优化指南](./PERFORMANCE_GUIDE.md) 🆕
225
234
  - [GitHub 仓库](https://github.com/TomWq/expo-gaode-map)
226
235
  - [示例项目(地图)](https://github.com/TomWq/expo-gaode-map-example)
227
236
  - [示例项目(导航)](https://github.com/TomWq/expo-gaode-map-navigation-example)
@@ -22,3 +22,5 @@ find_library(log-lib log)
22
22
  target_link_libraries(gaodecluster
23
23
  ${log-lib}
24
24
  )
25
+
26
+ target_link_options(gaodecluster PRIVATE "-Wl,-z,max-page-size=16384")
@@ -5,7 +5,7 @@ import android.content.Context
5
5
  import android.view.View
6
6
  import android.view.ViewGroup
7
7
  import com.amap.api.maps.AMap
8
- import com.amap.api.maps.MapView
8
+ import com.amap.api.maps.TextureMapView
9
9
  import com.amap.api.maps.MapsInitializer
10
10
  import com.amap.api.maps.model.LatLng
11
11
  import expo.modules.kotlin.AppContext
@@ -64,23 +64,11 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
64
64
  private val onCameraMove by EventDispatcher()
65
65
  private val onCameraIdle by EventDispatcher()
66
66
 
67
- // 事件节流控制
68
- /** 相机移动事件节流间隔(毫秒) */
69
- private val CAMERA_MOVE_THROTTLE_MS = 100L
70
- /** 上次触发相机移动事件的时间戳 */
71
- private var lastCameraMoveTime = 0L
72
- /** 缓存的相机移动事件数据 */
67
+ // 缓存的相机移动事件数据
73
68
  private var pendingCameraMoveData: Map<String, Any>? = null
74
- /** 节流定时器 Runnable */
75
- private val throttleRunnable = Runnable {
76
- pendingCameraMoveData?.let { data ->
77
- onCameraMove(data)
78
- pendingCameraMoveData = null
79
- }
80
- }
81
69
 
82
70
  // 高德地图视图
83
- private lateinit var mapView: MapView
71
+ private lateinit var mapView: TextureMapView
84
72
  private lateinit var aMap: AMap
85
73
 
86
74
  // 管理器
@@ -97,18 +85,9 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
97
85
  MapsInitializer.updatePrivacyShow(context, true, true)
98
86
  MapsInitializer.updatePrivacyAgree(context, true)
99
87
 
100
- // 尝试从预加载池获取 MapView
101
- val preloadedMapView = MapPreloadManager.getPreloadedMapView()
102
-
103
- if (preloadedMapView != null) {
104
- mapView = preloadedMapView
105
- android.util.Log.i("ExpoGaodeMapView", "🚀 使用预加载的 MapView 实例")
106
- } else {
107
- // 创建地图视图
108
- mapView = MapView(context)
109
- mapView.onCreate(null)
110
- android.util.Log.i("ExpoGaodeMapView", "⚠️ 创建新的 MapView 实例 (未命中预加载池)")
111
- }
88
+ // 创建地图视图 - 使用 TextureMapView 以支持截图
89
+ mapView = TextureMapView(context)
90
+ mapView.onCreate(null)
112
91
 
113
92
  aMap = mapView.map
114
93
 
@@ -184,7 +163,6 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
184
163
 
185
164
  // 相机移动中 - 应用节流优化
186
165
  cameraPosition?.let {
187
- val currentTime = System.currentTimeMillis()
188
166
  val visibleRegion = aMap.projection.visibleRegion
189
167
  val eventData = mapOf(
190
168
  "cameraPosition" to mapOf(
@@ -208,23 +186,16 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
208
186
  )
209
187
  )
210
188
 
211
- // 节流逻辑:100ms 内只触发一次
212
- if (currentTime - lastCameraMoveTime >= CAMERA_MOVE_THROTTLE_MS) {
213
- // 超过节流时间,立即触发事件
214
- lastCameraMoveTime = currentTime
215
- onCameraMove(eventData)
216
- // 清除待处理的事件和定时器
217
- mainHandler.removeCallbacks(throttleRunnable)
218
- pendingCameraMoveData = null
219
- } else {
220
- // 在节流时间内,缓存事件数据,使用定时器延迟触发
221
- pendingCameraMoveData = eventData
222
- mainHandler.removeCallbacks(throttleRunnable)
223
- mainHandler.postDelayed(
224
- throttleRunnable,
225
- CAMERA_MOVE_THROTTLE_MS - (currentTime - lastCameraMoveTime)
226
- )
227
- }
189
+ // 使用 onCameraMove 自身的节流机制(如果在 Module 定义中配置了 Coalescing)
190
+ // 或者在这里简单发送,让 JS 端处理节流,或者依赖 Expo 的事件批处理
191
+ // 这里我们移除自定义的 Handler 实现,直接发送事件,简化代码逻辑
192
+ // 注意:高德地图的 onCameraChange 调用频率非常高,
193
+ // 建议在 Module 定义中使用 Events("onCameraMove") 时考虑是否需要原生侧节流
194
+ // 目前 Expo Modules 默认没有自动节流,但为了代码简洁和避免 Handler 泄漏风险,
195
+ // 我们可以依赖 JS 端的 debounce/throttle,或者如果性能是瓶颈,再加回轻量级的节流。
196
+ // 鉴于之前的 Handler 实现比较复杂且容易出错,我们先简化。
197
+
198
+ onCameraMove(eventData)
228
199
  }
229
200
  }
230
201
 
@@ -493,27 +464,34 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
493
464
 
494
465
  aMap.getMapScreenShot(object : AMap.OnMapScreenShotListener {
495
466
  override fun onMapScreenShot(bitmap: android.graphics.Bitmap?) {
496
- // 如果已经处理过,直接返回
467
+ // 这个回调通常在旧版 SDK 或部分机型触发
468
+ // 如果已经处理过(通过带 status 的回调),则忽略
497
469
  if (isSettled.getAndSet(true)) return
498
470
 
499
- // 旧版本回调,为了兼容性也处理
500
- bitmap?.let { handleSnapshot(it, promise) } ?: run {
501
- promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
471
+ if (bitmap == null) {
472
+ promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
473
+ return
502
474
  }
475
+ handleSnapshot(bitmap, promise)
503
476
  }
504
477
 
505
478
  override fun onMapScreenShot(bitmap: android.graphics.Bitmap?, status: Int) {
506
479
  // 如果已经处理过,直接返回
507
480
  if (isSettled.getAndSet(true)) return
508
481
 
509
- // status != 0 表示失败
510
- if (status != 0) {
511
- promise.reject("SNAPSHOT_FAILED", "Failed to take snapshot, status code: $status", null)
482
+ if (bitmap == null) {
483
+ promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
512
484
  return
513
485
  }
514
- bitmap?.let { handleSnapshot(it, promise) } ?: run {
515
- promise.reject("SNAPSHOT_FAILED", "Bitmap is null", null)
486
+
487
+ // 根据高德文档:
488
+ // status != 0 地图渲染完成,截屏无网格
489
+ // status == 0 地图未渲染完成,截屏有网格
490
+ if (status == 0) {
491
+ android.util.Log.w("ExpoGaodeMapView", "Warning: Map snapshot taken before rendering completed (grid may be visible)")
516
492
  }
493
+
494
+ handleSnapshot(bitmap, promise)
517
495
  }
518
496
  })
519
497
  }
@@ -601,10 +579,6 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
601
579
  @Suppress("unused")
602
580
  fun onDestroy() {
603
581
  try {
604
- // 清理节流定时器
605
- mainHandler.removeCallbacks(throttleRunnable)
606
- pendingCameraMoveData = null
607
-
608
582
  // 清理 Handler 回调,防止内存泄露
609
583
  mainHandler.removeCallbacksAndMessages(null)
610
584
 
@@ -654,7 +628,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
654
628
  return
655
629
  }
656
630
 
657
- if (child is MapView) {
631
+ if (child is TextureMapView) {
658
632
  super.addView(child, index)
659
633
  return
660
634
  }
@@ -702,7 +676,7 @@ class ExpoGaodeMapView(context: Context, appContext: AppContext) : ExpoView(cont
702
676
  try {
703
677
  val child = super.getChildAt(index)
704
678
 
705
- if (child is MapView) {
679
+ if (child is TextureMapView) {
706
680
  return
707
681
  }
708
682
 
@@ -3,6 +3,16 @@ package expo.modules.gaodemap
3
3
  import expo.modules.kotlin.modules.Module
4
4
  import expo.modules.kotlin.modules.ModuleDefinition
5
5
 
6
+ import expo.modules.kotlin.types.Enumerable
7
+
8
+ enum class MapType(val value: Int) : Enumerable {
9
+ STANDARD(1),
10
+ SATELLITE(2),
11
+ NIGHT(3),
12
+ NAVI(4),
13
+ BUS(5)
14
+ }
15
+
6
16
  /**
7
17
  * 高德地图视图 Module
8
18
  */
@@ -24,9 +34,9 @@ class ExpoGaodeMapViewModule : Module() {
24
34
  }
25
35
 
26
36
 
27
- Prop<Int>("mapType") { view, type ->
28
- view.mapType = type
29
- view.setMapType(type)
37
+ Prop<MapType>("mapType") { view, type ->
38
+ view.mapType = type.value
39
+ view.setMapType(type.value)
30
40
  }
31
41
 
32
42
  Prop<Map<String, Any?>?>("initialCameraPosition") { view, position ->
package/build/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export { PlatformDetector, DeviceType, FoldState, isAndroid14Plus, isiOS17Plus,
10
10
  export type { DeviceInfo, SystemVersion } from './utils/PlatformDetector';
11
11
  export { PermissionUtils, PermissionManager, // 向后兼容的别名
12
12
  LocationPermissionType, } from './utils/PermissionUtils';
13
+ export { throttle } from './utils/throttle';
13
14
  export { FoldableMapView, useFoldableMap, } from './components/FoldableMapView';
14
15
  export type { FoldableMapViewProps, FoldableConfig, } from './components/FoldableMapView';
15
16
  export { default as ExpoGaodeMapOfflineModule } from './utils/OfflineMapManager';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,OAAO,GACR,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,EACV,MAAM,GACP,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EACL,eAAe,EACf,iBAAiB,EAAE,UAAU;AAC7B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,eAAe,EACf,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEjF,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAM/B;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,wOAGjC,CAAA;AAGF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAGrE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG3C,OAAO,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,OAAO,GACR,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,EACV,MAAM,GACP,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG1E,OAAO,EACL,eAAe,EACf,iBAAiB,EAAE,UAAU;AAC7B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,EACL,eAAe,EACf,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,oBAAoB,EACpB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEjF,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAM/B;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,wOAGjC,CAAA;AAGF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG/D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC"}
package/build/index.js CHANGED
@@ -17,6 +17,8 @@ export { PlatformDetector, DeviceType, FoldState, isAndroid14Plus, isiOS17Plus,
17
17
  // 导出权限工具类(仅提供文案和诊断,实际权限请求使用 ExpoGaodeMapModule)
18
18
  export { PermissionUtils, PermissionManager, // 向后兼容的别名
19
19
  LocationPermissionType, } from './utils/PermissionUtils';
20
+ // 导出节流工具函数
21
+ export { throttle } from './utils/throttle';
20
22
  // 导出折叠屏适配组件
21
23
  export { FoldableMapView, useFoldableMap, } from './components/FoldableMapView';
22
24
  // 导出离线地图 API
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,6BAA6B,MAAM,sBAAsB,CAAC;AAEjE,mBAAmB;AACnB,cAAc,SAAS,CAAC;AACxB,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,WAAW;AACX,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,UAAU;AACV,OAAO,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,OAAO,GACR,MAAM,uBAAuB,CAAC;AAE/B,WAAW;AACX,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,sBAAsB,CAAC;AAG9B,WAAW;AACX,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,EACV,MAAM,GACP,MAAM,0BAA0B,CAAC;AAGlC,gDAAgD;AAChD,OAAO,EACL,eAAe,EACf,iBAAiB,EAAE,UAAU;AAC7B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,YAAY;AACZ,OAAO,EACL,eAAe,EACf,cAAc,GACf,MAAM,8BAA8B,CAAC;AAMtC,aAAa;AACb,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAejF,MAAM,uBAAuB,GAAG,6BAA6B,CAAC,yBAAyB,CAAA;AACvF,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,uBAAuB,CAAA;AAGjF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;IACzD,SAAS,EAAE,mBAAmB;IAC9B,aAAa,EAAE,uBAAuB;CACvC,CAAC,CAAA;AAEF,yBAAyB;AACzB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE/D,WAAW;AACX,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["\nimport { createPermissionHook } from 'expo-modules-core';\nimport ExpoGaodeMapModuleWithHelpers from './ExpoGaodeMapModule';\n\n// 导出类型定义(包含所有通用类型)\nexport * from './types';\n// 导出原生模块\nexport { default as ExpoGaodeMapModule } from './ExpoGaodeMapModule';\n\n// 导出地图视图组件\nexport { default as MapView } from './ExpoGaodeMapView';\nexport { useMap } from './components/MapContext';\nexport { MapUI } from './components/MapUI';\n\n// 导出覆盖物组件\nexport {\n Marker,\n Polyline,\n Polygon,\n Circle,\n HeatMap,\n MultiPoint,\n Cluster,\n} from './components/overlays';\n\n// 导出错误处理工具\nexport {\n ErrorHandler,\n ErrorLogger,\n GaodeMapError,\n ErrorType,\n} from './utils/ErrorHandler';\nexport type { ErrorDetails } from './utils/ErrorHandler';\n\n// 导出平台检测工具\nexport {\n PlatformDetector,\n DeviceType,\n FoldState,\n isAndroid14Plus,\n isiOS17Plus,\n isTablet,\n isFoldable,\n isIPad,\n} from './utils/PlatformDetector';\nexport type { DeviceInfo, SystemVersion } from './utils/PlatformDetector';\n\n// 导出权限工具类(仅提供文案和诊断,实际权限请求使用 ExpoGaodeMapModule)\nexport {\n PermissionUtils,\n PermissionManager, // 向后兼容的别名\n LocationPermissionType,\n} from './utils/PermissionUtils';\n\n// 导出折叠屏适配组件\nexport {\n FoldableMapView,\n useFoldableMap,\n} from './components/FoldableMapView';\nexport type {\n FoldableMapViewProps,\n FoldableConfig,\n} from './components/FoldableMapView';\n\n// 导出离线地图 API\nexport { default as ExpoGaodeMapOfflineModule } from './utils/OfflineMapManager';\n\nexport type {\n OfflineMapInfo,\n OfflineMapStatus,\n OfflineMapDownloadConfig,\n OfflineMapDownloadEvent,\n OfflineMapCompleteEvent,\n OfflineMapErrorEvent,\n OfflineMapPausedEvent,\n OfflineMapCancelledEvent,\n OfflineMapStorageInfo,\n OfflineMapEvents,\n} from './types/offline.types';\n\nconst requestPermissionsAsync = ExpoGaodeMapModuleWithHelpers.requestLocationPermission\nconst getPermissionsAsync = ExpoGaodeMapModuleWithHelpers.checkLocationPermission\n\n\n/**\n * Check or request permissions to access the location.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = useLocationPermissions();\n * ```\n */\nexport const useLocationPermissions = createPermissionHook({\n getMethod: getPermissionsAsync,\n requestMethod: requestPermissionsAsync,\n})\n\n// 导出便捷读取的 SDK 配置与 webKey\nexport { getSDKConfig, getWebKey } from './ExpoGaodeMapModule';\n\n// 默认导出原生模块\nexport { default } from './ExpoGaodeMapModule';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,6BAA6B,MAAM,sBAAsB,CAAC;AAEjE,mBAAmB;AACnB,cAAc,SAAS,CAAC;AACxB,SAAS;AACT,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAErE,WAAW;AACX,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,UAAU;AACV,OAAO,EACL,MAAM,EACN,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,OAAO,GACR,MAAM,uBAAuB,CAAC;AAE/B,WAAW;AACX,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,GACV,MAAM,sBAAsB,CAAC;AAG9B,WAAW;AACX,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,eAAe,EACf,WAAW,EACX,QAAQ,EACR,UAAU,EACV,MAAM,GACP,MAAM,0BAA0B,CAAC;AAGlC,gDAAgD;AAChD,OAAO,EACL,eAAe,EACf,iBAAiB,EAAE,UAAU;AAC7B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,WAAW;AACX,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,YAAY;AACZ,OAAO,EACL,eAAe,EACf,cAAc,GACf,MAAM,8BAA8B,CAAC;AAMtC,aAAa;AACb,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAejF,MAAM,uBAAuB,GAAG,6BAA6B,CAAC,yBAAyB,CAAA;AACvF,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,uBAAuB,CAAA;AAGjF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;IACzD,SAAS,EAAE,mBAAmB;IAC9B,aAAa,EAAE,uBAAuB;CACvC,CAAC,CAAA;AAEF,yBAAyB;AACzB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE/D,WAAW;AACX,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["\nimport { createPermissionHook } from 'expo-modules-core';\nimport ExpoGaodeMapModuleWithHelpers from './ExpoGaodeMapModule';\n\n// 导出类型定义(包含所有通用类型)\nexport * from './types';\n// 导出原生模块\nexport { default as ExpoGaodeMapModule } from './ExpoGaodeMapModule';\n\n// 导出地图视图组件\nexport { default as MapView } from './ExpoGaodeMapView';\nexport { useMap } from './components/MapContext';\nexport { MapUI } from './components/MapUI';\n\n// 导出覆盖物组件\nexport {\n Marker,\n Polyline,\n Polygon,\n Circle,\n HeatMap,\n MultiPoint,\n Cluster,\n} from './components/overlays';\n\n// 导出错误处理工具\nexport {\n ErrorHandler,\n ErrorLogger,\n GaodeMapError,\n ErrorType,\n} from './utils/ErrorHandler';\nexport type { ErrorDetails } from './utils/ErrorHandler';\n\n// 导出平台检测工具\nexport {\n PlatformDetector,\n DeviceType,\n FoldState,\n isAndroid14Plus,\n isiOS17Plus,\n isTablet,\n isFoldable,\n isIPad,\n} from './utils/PlatformDetector';\nexport type { DeviceInfo, SystemVersion } from './utils/PlatformDetector';\n\n// 导出权限工具类(仅提供文案和诊断,实际权限请求使用 ExpoGaodeMapModule)\nexport {\n PermissionUtils,\n PermissionManager, // 向后兼容的别名\n LocationPermissionType,\n} from './utils/PermissionUtils';\n\n// 导出节流工具函数\nexport { throttle } from './utils/throttle';\n\n// 导出折叠屏适配组件\nexport {\n FoldableMapView,\n useFoldableMap,\n} from './components/FoldableMapView';\nexport type {\n FoldableMapViewProps,\n FoldableConfig,\n} from './components/FoldableMapView';\n\n// 导出离线地图 API\nexport { default as ExpoGaodeMapOfflineModule } from './utils/OfflineMapManager';\n\nexport type {\n OfflineMapInfo,\n OfflineMapStatus,\n OfflineMapDownloadConfig,\n OfflineMapDownloadEvent,\n OfflineMapCompleteEvent,\n OfflineMapErrorEvent,\n OfflineMapPausedEvent,\n OfflineMapCancelledEvent,\n OfflineMapStorageInfo,\n OfflineMapEvents,\n} from './types/offline.types';\n\nconst requestPermissionsAsync = ExpoGaodeMapModuleWithHelpers.requestLocationPermission\nconst getPermissionsAsync = ExpoGaodeMapModuleWithHelpers.checkLocationPermission\n\n\n/**\n * Check or request permissions to access the location.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [status, requestPermission] = useLocationPermissions();\n * ```\n */\nexport const useLocationPermissions = createPermissionHook({\n getMethod: getPermissionsAsync,\n requestMethod: requestPermissionsAsync,\n})\n\n// 导出便捷读取的 SDK 配置与 webKey\nexport { getSDKConfig, getWebKey } from './ExpoGaodeMapModule';\n\n// 默认导出原生模块\nexport { default } from './ExpoGaodeMapModule';\n"]}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 一个轻量级的节流函数,用于限制函数调用的频率。
3
+ * 特别适用于处理高频事件,如地图移动、滚动等。
4
+ *
5
+ * @param func 需要节流的函数
6
+ * @param limit 时间间隔(毫秒)
7
+ * @returns 节流后的函数
8
+ */
9
+ export declare function throttle<T extends (...args: any[]) => void>(func: T, limit: number): T;
10
+ //# sourceMappingURL=throttle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throttle.d.ts","sourceRoot":"","sources":["../../src/utils/throttle.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAStF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 一个轻量级的节流函数,用于限制函数调用的频率。
3
+ * 特别适用于处理高频事件,如地图移动、滚动等。
4
+ *
5
+ * @param func 需要节流的函数
6
+ * @param limit 时间间隔(毫秒)
7
+ * @returns 节流后的函数
8
+ */
9
+ export function throttle(func, limit) {
10
+ let inThrottle;
11
+ return function (...args) {
12
+ if (!inThrottle) {
13
+ func.apply(this, args);
14
+ inThrottle = true;
15
+ setTimeout(() => (inThrottle = false), limit);
16
+ }
17
+ };
18
+ }
19
+ //# sourceMappingURL=throttle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"throttle.js","sourceRoot":"","sources":["../../src/utils/throttle.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAqC,IAAO,EAAE,KAAa;IACjF,IAAI,UAAmB,CAAC;IACxB,OAAO,UAAoB,GAAG,IAAW;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACvB,UAAU,GAAG,IAAI,CAAC;YAClB,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,UAAU,GAAG,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QAChD,CAAC;IACH,CAAM,CAAC;AACT,CAAC","sourcesContent":["\n/**\n * 一个轻量级的节流函数,用于限制函数调用的频率。\n * 特别适用于处理高频事件,如地图移动、滚动等。\n *\n * @param func 需要节流的函数\n * @param limit 时间间隔(毫秒)\n * @returns 节流后的函数\n */\nexport function throttle<T extends (...args: any[]) => void>(func: T, limit: number): T {\n let inThrottle: boolean;\n return function(this: any, ...args: any[]) {\n if (!inThrottle) {\n func.apply(this, args);\n inThrottle = true;\n setTimeout(() => (inThrottle = false), limit);\n }\n } as T;\n}\n"]}
@@ -19,11 +19,9 @@ Pod::Spec.new do |s|
19
19
  s.static_framework = true
20
20
 
21
21
  s.dependency 'ExpoModulesCore'
22
- s.dependency 'AMapFoundation'
23
- s.dependency 'AMapLocation'
24
22
  s.dependency 'AMap3DMap'
25
-
26
- s.library = 'c++'
23
+ s.dependency "AMapLocation"
24
+ s.dependency "AMapLocation"
27
25
 
28
26
  # Swift/Objective-C compatibility
29
27
  s.pod_target_xcconfig = {
@@ -124,7 +124,7 @@ public class ExpoGaodeMapModule: Module {
124
124
  * @param enable 是否开启
125
125
  */
126
126
  Function("setLoadWorldVectorMap") { (enable: Bool) in
127
- MAMapView.loadWorldVectorMap = enable
127
+ MAMapView.loadWorldVectorMap = enable
128
128
  }
129
129
 
130
130
  /**
@@ -92,14 +92,8 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
92
92
 
93
93
  // MARK: - 事件节流控制
94
94
 
95
- /// 相机移动事件节流间隔(秒)
96
- private let cameraMoveThrottleInterval: TimeInterval = 0.1
97
- /// 上次触发相机移动事件的时间戳
98
- private var lastCameraMoveTime: TimeInterval = 0
99
95
  /// 缓存的相机移动事件数据
100
96
  private var pendingCameraMoveData: [String: Any]?
101
- /// 节流定时器
102
- private var throttleTimer: Timer?
103
97
 
104
98
  /// 缩放手势识别器(用于模拟惯性)
105
99
  private var pinchGesture: UIPinchGestureRecognizer!
@@ -856,9 +850,7 @@ class ExpoGaodeMapView: ExpoView, MAMapViewDelegate, UIGestureRecognizerDelegate
856
850
  * 当视图从层级中移除并释放时自动调用
857
851
  */
858
852
  deinit {
859
- // 清理节流定时器
860
- throttleTimer?.invalidate()
861
- throttleTimer = nil
853
+ // 清理资源
862
854
  pendingCameraMoveData = nil
863
855
 
864
856
  // 清理代理,停止接收回调
@@ -935,11 +927,10 @@ extension ExpoGaodeMapView {
935
927
  }
936
928
 
937
929
  /**
938
- * 地图区域即将改变时触发 - 应用节流优化
930
+ * 地图区域即将改变时触发
939
931
  */
940
932
  public func mapView(_ mapView: MAMapView, regionWillChangeAnimated animated: Bool) {
941
- // 相机开始移动 - 应用节流优化
942
- let currentTime = Date().timeIntervalSince1970
933
+ // 相机开始移动
943
934
  let cameraPosition = cameraManager.getCameraPosition()
944
935
  let visibleRegion = mapView.region
945
936
 
@@ -957,29 +948,9 @@ extension ExpoGaodeMapView {
957
948
  ]
958
949
  ]
959
950
 
960
- // 节流逻辑:0.1秒 内只触发一次
961
- if currentTime - lastCameraMoveTime >= cameraMoveThrottleInterval {
962
- // 超过节流时间,立即触发事件
963
- lastCameraMoveTime = currentTime
964
- onCameraMove(eventData)
965
- // 清除待处理的事件和定时器
966
- throttleTimer?.invalidate()
967
- throttleTimer = nil
968
- pendingCameraMoveData = nil
969
- } else {
970
- // 在节流时间内,缓存事件数据,使用定时器延迟触发
971
- pendingCameraMoveData = eventData
972
- throttleTimer?.invalidate()
973
-
974
- let delay = cameraMoveThrottleInterval - (currentTime - lastCameraMoveTime)
975
- throttleTimer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { [weak self] _ in
976
- guard let self = self, let data = self.pendingCameraMoveData else { return }
977
- self.lastCameraMoveTime = Date().timeIntervalSince1970
978
- self.onCameraMove(data)
979
- self.pendingCameraMoveData = nil
980
- self.throttleTimer = nil
981
- }
982
- }
951
+ // 直接触发事件,移除手动节流
952
+ // 建议在 JS 端进行 debounce/throttle 处理
953
+ onCameraMove(eventData)
983
954
  }
984
955
 
985
956
  /**
@@ -1,6 +1,14 @@
1
1
  import ExpoModulesCore
2
2
  import MAMapKit
3
3
 
4
+ enum MapType: Int, Enumerable {
5
+ case standard = 0
6
+ case satellite = 1
7
+ case night = 2
8
+ case navi = 3
9
+ case bus = 4
10
+ }
11
+
4
12
  /**
5
13
  * 高德地图视图 Module
6
14
  */
@@ -11,8 +19,8 @@ public class ExpoGaodeMapViewModule: Module {
11
19
  View(ExpoGaodeMapView.self) {
12
20
  Events("onMapPress", "onMapLongPress", "onLoad", "onLocation", "onCameraMove", "onCameraIdle")
13
21
 
14
- Prop("mapType") { (view: ExpoGaodeMapView, type: Int) in
15
- view.mapType = type
22
+ Prop("mapType") { (view: ExpoGaodeMapView, type: MapType) in
23
+ view.mapType = type.rawValue
16
24
  }
17
25
 
18
26
  Prop("initialCameraPosition") { (view: ExpoGaodeMapView, position: [String: Any]?) in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-gaode-map",
3
- "version": "2.2.26-next.1",
3
+ "version": "2.2.26",
4
4
  "description": "A full-featured AMap (Gaode Map) React Native component library built with Expo Modules, providing map display, location services, overlays, and more.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -14,18 +14,18 @@
14
14
  "plugin/build"
15
15
  ],
16
16
  "scripts": {
17
- "build": "expo-module build && bun run build:plugin",
17
+ "build": "expo-module build && yarn build:plugin",
18
18
  "build:plugin": "tsc --project plugin/tsconfig.json",
19
19
  "clean": "expo-module clean && rm -rf plugin/build",
20
20
  "lint": "expo-module lint",
21
21
  "test": "expo-module test",
22
- "prepare": "expo-module prepare && bun run build:plugin",
22
+ "prepare": "expo-module prepare && yarn build:plugin",
23
23
  "prepublishOnly": "echo 'Skipping proofread check' && exit 0",
24
24
  "expo-module": "expo-module",
25
25
  "open:ios": "xed example/ios",
26
26
  "open:android": "open -a \"Android Studio\" example/android",
27
- "publish:next": "bun publish --tag next",
28
- "publish:latest": "bun publish --tag latest"
27
+ "publish:next": "npm publish --tag next",
28
+ "publish:latest": "npm publish --tag latest"
29
29
  },
30
30
  "keywords": [
31
31
  "react-native",
@@ -50,19 +50,15 @@
50
50
  "registry": "https://registry.npmjs.org/"
51
51
  },
52
52
  "devDependencies": {
53
- "@expo/config-plugins": "~54.0.4",
54
- "@testing-library/react-native": "^13.3.3",
55
53
  "@babel/runtime": "^7.25.7",
54
+ "@testing-library/react-native": "^13.3.3",
56
55
  "@types/jest": "^29.5.14",
57
56
  "@types/react": "~19.1.0",
58
- "eslint": "^9.15.0",
59
- "babel-preset-expo": "^54.0.8",
60
- "expo": "^54.0.31",
57
+ "expo": "^54.0.27",
61
58
  "expo-module-scripts": "^5.0.8",
62
59
  "jest": "~29.7.0",
63
60
  "jest-expo": "^54.0.16",
64
61
  "react-native": "0.81.5",
65
- "react-test-renderer": "19.1.0",
66
62
  "typescript": "^5.9.3"
67
63
  },
68
64
  "peerDependencies": {
@@ -1,4 +1,4 @@
1
- import { ConfigPlugin } from '@expo/config-plugins';
1
+ import { ConfigPlugin } from 'expo/config-plugins';
2
2
  /**
3
3
  * 高德地图插件配置类型
4
4
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const config_plugins_1 = require("@expo/config-plugins");
3
+ const config_plugins_1 = require("expo/config-plugins");
4
4
  const pkg = require('../../package.json');
5
5
  /** 默认定位权限描述 */
6
6
  const DEFAULT_LOCATION_USAGE = '需要访问您的位置信息以提供地图服务';
@@ -11,22 +11,24 @@ const withGaodeMapIOSPermissions = (config, props) => {
11
11
  if (props.enableLocation === false) {
12
12
  return config;
13
13
  }
14
- const description = props.locationDescription || DEFAULT_LOCATION_USAGE;
14
+ // 使用 IOSConfig.Permissions 简化权限配置
15
+ // 注意:locationDescription 的检查已移至 withGaodeMapInfoPlist 中以避免重复打印
16
+ const description = props.locationDescription;
17
+ const finalDescription = description || DEFAULT_LOCATION_USAGE;
15
18
  // 构建权限配置对象
16
19
  const permissionDefaults = {
17
20
  NSLocationWhenInUseUsageDescription: DEFAULT_LOCATION_USAGE,
18
21
  };
19
22
  const permissionValues = {
20
- NSLocationWhenInUseUsageDescription: description,
23
+ NSLocationWhenInUseUsageDescription: finalDescription,
21
24
  };
22
25
  // 如果启用后台定位,添加额外权限
23
26
  if (props.enableBackgroundLocation) {
24
27
  permissionDefaults.NSLocationAlwaysUsageDescription = DEFAULT_LOCATION_USAGE;
25
28
  permissionDefaults.NSLocationAlwaysAndWhenInUseUsageDescription = DEFAULT_LOCATION_USAGE;
26
- permissionValues.NSLocationAlwaysUsageDescription = description;
27
- permissionValues.NSLocationAlwaysAndWhenInUseUsageDescription = description;
29
+ permissionValues.NSLocationAlwaysUsageDescription = finalDescription;
30
+ permissionValues.NSLocationAlwaysAndWhenInUseUsageDescription = finalDescription;
28
31
  }
29
- // 使用 IOSConfig.Permissions 简化权限配置
30
32
  return config_plugins_1.IOSConfig.Permissions.createPermissionsPlugin(permissionDefaults)(config, permissionValues);
31
33
  };
32
34
  /**
@@ -34,6 +36,16 @@ const withGaodeMapIOSPermissions = (config, props) => {
34
36
  */
35
37
  const withGaodeMapInfoPlist = (config, props) => {
36
38
  return (0, config_plugins_1.withInfoPlist)(config, (config) => {
39
+ // 检查 iOS API Key
40
+ if (!props.iosKey && !props.androidKey) {
41
+ // 仅当两个平台都未配置时提示 Notice,避免打扰单平台开发者
42
+ // 这里使用 console.log 而不是 WarningAggregator,因为这只是一个提示
43
+ console.log('\u001b[33m[expo-gaode-map] Notice: 未在 app.json 中配置 API Key。请确保在应用启动时通过代码配置 Key,否则地图将无法加载。建议在 app.json 中配置 API Key 以避免运行时错误。\u001b[0m');
44
+ }
45
+ // 检查 locationDescription
46
+ if (props.enableLocation !== false && !props.locationDescription) {
47
+ config_plugins_1.WarningAggregator.addWarningIOS('expo-gaode-map', `未配置 iOS 定位权限描述 (locationDescription)。将使用默认描述: "${DEFAULT_LOCATION_USAGE}"。建议在 app.json 中配置以满足 App Store 审核要求。`);
48
+ }
37
49
  // 添加高德地图 API Key
38
50
  if (props.iosKey) {
39
51
  config.modResults.AMapApiKey = props.iosKey;
@@ -195,10 +207,6 @@ const withGaodeMapAndroidSdk = (config, props) => {
195
207
  * 主插件函数 - 组合所有修改器
196
208
  */
197
209
  const withGaodeMap = (config, props = {}) => {
198
- // 验证配置
199
- if (!props.iosKey && !props.androidKey) {
200
- config_plugins_1.WarningAggregator.addWarningIOS('expo-gaode-map', '未配置 API Key。请在 app.json 的 plugins 中配置 iosKey 和 androidKey');
201
- }
202
210
  // 应用 iOS 配置
203
211
  config = withGaodeMapIOSPermissions(config, props); // 使用 IOSConfig 添加权限
204
212
  config = withGaodeMapInfoPlist(config, props); // 添加 API Key 和后台模式