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

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.
Files changed (34) hide show
  1. package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +14 -0
  2. package/android/src/main/java/expo/modules/gaodemap/modules/SDKInitializer.kt +107 -5
  3. package/build/ExpoGaodeMapModule.d.ts +245 -4
  4. package/build/ExpoGaodeMapModule.d.ts.map +1 -1
  5. package/build/ExpoGaodeMapModule.js +114 -2
  6. package/build/ExpoGaodeMapModule.js.map +1 -1
  7. package/build/ExpoGaodeMapOfflineModule.d.ts.map +1 -1
  8. package/build/ExpoGaodeMapOfflineModule.js +8 -1
  9. package/build/ExpoGaodeMapOfflineModule.js.map +1 -1
  10. package/build/components/overlays/HeatMap.d.ts.map +1 -1
  11. package/build/components/overlays/HeatMap.js.map +1 -1
  12. package/build/components/overlays/Marker.d.ts.map +1 -1
  13. package/build/components/overlays/Marker.js.map +1 -1
  14. package/build/types/common.types.d.ts +17 -0
  15. package/build/types/common.types.d.ts.map +1 -1
  16. package/build/types/common.types.js.map +1 -1
  17. package/build/types/native-module.types.d.ts +16 -1
  18. package/build/types/native-module.types.d.ts.map +1 -1
  19. package/build/types/native-module.types.js.map +1 -1
  20. package/build/utils/ErrorHandler.d.ts.map +1 -1
  21. package/build/utils/ErrorHandler.js +13 -2
  22. package/build/utils/ErrorHandler.js.map +1 -1
  23. package/build/utils/GeoUtils.d.ts.map +1 -1
  24. package/build/utils/GeoUtils.js.map +1 -1
  25. package/build/utils/lazyNativeViewManager.d.ts +1 -1
  26. package/build/utils/lazyNativeViewManager.d.ts.map +1 -1
  27. package/build/utils/lazyNativeViewManager.js.map +1 -1
  28. package/build/utils/throttle.d.ts +1 -1
  29. package/build/utils/throttle.d.ts.map +1 -1
  30. package/build/utils/throttle.js +1 -1
  31. package/build/utils/throttle.js.map +1 -1
  32. package/ios/ExpoGaodeMapModule.swift +10 -1
  33. package/ios/GaodeMapPrivacyManager.swift +92 -2
  34. package/package.json +1 -1
@@ -30,6 +30,12 @@ class ExpoGaodeMapModule : Module() {
30
30
  override fun definition() = ModuleDefinition {
31
31
  Name("ExpoGaodeMap")
32
32
 
33
+ OnCreate {
34
+ appContext.reactContext?.let { context ->
35
+ SDKInitializer.restorePersistedState(context)
36
+ }
37
+ }
38
+
33
39
  // ==================== SDK 初始化 ====================
34
40
 
35
41
  /**
@@ -71,6 +77,14 @@ class ExpoGaodeMapModule : Module() {
71
77
  SDKInitializer.setPrivacyAgree(appContext.reactContext!!, hasAgree)
72
78
  }
73
79
 
80
+ Function("setPrivacyVersion") { version: String ->
81
+ SDKInitializer.setPrivacyVersion(appContext.reactContext!!, version)
82
+ }
83
+
84
+ Function("resetPrivacyConsent") {
85
+ SDKInitializer.resetPrivacyConsent(appContext.reactContext!!)
86
+ }
87
+
74
88
  Function("getPrivacyStatus") {
75
89
  SDKInitializer.getPrivacyStatus()
76
90
  }
@@ -14,23 +14,85 @@ import com.amap.api.maps.MapsInitializer
14
14
  * - 获取 SDK 版本信息
15
15
  */
16
16
  object SDKInitializer {
17
+ private const val PREFS_NAME = "expo_gaodemap_privacy"
18
+ private const val KEY_PRIVACY_SHOWN = "privacy_shown"
19
+ private const val KEY_PRIVACY_CONTAINS = "privacy_contains"
20
+ private const val KEY_PRIVACY_AGREED = "privacy_agreed"
21
+ private const val KEY_PRIVACY_VERSION = "privacy_version"
22
+ private const val KEY_AGREED_PRIVACY_VERSION = "agreed_privacy_version"
23
+
17
24
  private var privacyAgreed = false
18
25
  private var privacyShown = false
19
26
  private var privacyContains = false
27
+ private var privacyVersion: String? = null
28
+ private var agreedPrivacyVersion: String? = null
29
+ private var restoredFromStorage = false
20
30
 
21
31
  private fun resolveContext(context: Context): Context {
22
32
  return context.applicationContext ?: context
23
33
  }
24
34
 
35
+ private fun prefs(context: Context) =
36
+ resolveContext(context).getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
37
+
38
+ fun restorePersistedState(context: Context) {
39
+ val appContext = resolveContext(context)
40
+ val preferences = prefs(appContext)
41
+
42
+ privacyShown = preferences.getBoolean(KEY_PRIVACY_SHOWN, false)
43
+ privacyContains = preferences.getBoolean(KEY_PRIVACY_CONTAINS, false)
44
+ privacyAgreed = preferences.getBoolean(KEY_PRIVACY_AGREED, false)
45
+ privacyVersion = preferences.getString(KEY_PRIVACY_VERSION, null)
46
+ agreedPrivacyVersion = preferences.getString(KEY_AGREED_PRIVACY_VERSION, null)
47
+ restoredFromStorage = true
48
+
49
+ if (!privacyVersion.isNullOrEmpty() &&
50
+ !agreedPrivacyVersion.isNullOrEmpty() &&
51
+ privacyVersion != agreedPrivacyVersion
52
+ ) {
53
+ clearConsentPersistedState(appContext, keepCurrentVersion = true)
54
+ }
55
+
56
+ applyPrivacyState(appContext)
57
+ }
58
+
25
59
  fun setPrivacyShow(context: Context, hasShow: Boolean, hasContainsPrivacy: Boolean) {
26
60
  privacyShown = hasShow
27
61
  privacyContains = hasContainsPrivacy
28
- applyPrivacyState(resolveContext(context))
62
+ val appContext = resolveContext(context)
63
+ persistState(appContext)
64
+ applyPrivacyState(appContext)
29
65
  }
30
66
 
31
67
  fun setPrivacyAgree(context: Context, hasAgree: Boolean) {
32
68
  privacyAgreed = hasAgree
33
- applyPrivacyState(resolveContext(context))
69
+ agreedPrivacyVersion = if (hasAgree) privacyVersion else null
70
+ val appContext = resolveContext(context)
71
+ persistState(appContext)
72
+ applyPrivacyState(appContext)
73
+ }
74
+
75
+ fun setPrivacyVersion(context: Context, version: String) {
76
+ val sanitizedVersion = version.trim().takeIf { it.isNotEmpty() }
77
+ privacyVersion = sanitizedVersion
78
+
79
+ val appContext = resolveContext(context)
80
+ if (!privacyVersion.isNullOrEmpty() &&
81
+ !agreedPrivacyVersion.isNullOrEmpty() &&
82
+ privacyVersion != agreedPrivacyVersion
83
+ ) {
84
+ clearConsentPersistedState(appContext, keepCurrentVersion = true)
85
+ } else {
86
+ persistState(appContext)
87
+ }
88
+
89
+ applyPrivacyState(appContext)
90
+ }
91
+
92
+ fun resetPrivacyConsent(context: Context) {
93
+ val appContext = resolveContext(context)
94
+ clearConsentPersistedState(appContext, keepCurrentVersion = false)
95
+ applyPrivacyState(appContext)
34
96
  }
35
97
 
36
98
  fun applyPrivacyState(context: Context) {
@@ -49,12 +111,15 @@ object SDKInitializer {
49
111
  return privacyShown && privacyContains && privacyAgreed
50
112
  }
51
113
 
52
- fun getPrivacyStatus(): Map<String, Boolean> {
114
+ fun getPrivacyStatus(): Map<String, Any?> {
53
115
  return mapOf(
54
116
  "hasShow" to privacyShown,
55
117
  "hasContainsPrivacy" to privacyContains,
56
118
  "hasAgree" to privacyAgreed,
57
- "isReady" to isPrivacyReady()
119
+ "isReady" to isPrivacyReady(),
120
+ "privacyVersion" to privacyVersion,
121
+ "agreedPrivacyVersion" to agreedPrivacyVersion,
122
+ "restoredFromStorage" to restoredFromStorage,
58
123
  )
59
124
  }
60
125
 
@@ -67,9 +132,14 @@ object SDKInitializer {
67
132
  */
68
133
  fun initSDK(context: Context, androidKey: String) {
69
134
  val appContext = resolveContext(context)
135
+ restorePersistedState(appContext)
70
136
  // 检查隐私协议状态
71
137
  if (!isPrivacyReady()) {
72
- throw expo.modules.kotlin.exception.CodedException("隐私协议未完成确认,请先调用 setPrivacyShow/setPrivacyAgree")
138
+ throw expo.modules.kotlin.exception.CodedException(
139
+ "PRIVACY_NOT_AGREED",
140
+ "隐私协议未完成确认,请先调用 setPrivacyShow/setPrivacyAgree",
141
+ null
142
+ )
73
143
  }
74
144
 
75
145
  try {
@@ -92,4 +162,36 @@ object SDKInitializer {
92
162
  fun getVersion(): String {
93
163
  return MapsInitializer.getVersion()
94
164
  }
165
+
166
+ private fun persistState(context: Context) {
167
+ prefs(context).edit()
168
+ .putBoolean(KEY_PRIVACY_SHOWN, privacyShown)
169
+ .putBoolean(KEY_PRIVACY_CONTAINS, privacyContains)
170
+ .putBoolean(KEY_PRIVACY_AGREED, privacyAgreed)
171
+ .putString(KEY_PRIVACY_VERSION, privacyVersion)
172
+ .putString(KEY_AGREED_PRIVACY_VERSION, agreedPrivacyVersion)
173
+ .apply()
174
+ }
175
+
176
+ private fun clearConsentPersistedState(context: Context, keepCurrentVersion: Boolean) {
177
+ privacyShown = false
178
+ privacyContains = false
179
+ privacyAgreed = false
180
+ agreedPrivacyVersion = null
181
+
182
+ val editor = prefs(context).edit()
183
+ .putBoolean(KEY_PRIVACY_SHOWN, false)
184
+ .putBoolean(KEY_PRIVACY_CONTAINS, false)
185
+ .putBoolean(KEY_PRIVACY_AGREED, false)
186
+ .remove(KEY_AGREED_PRIVACY_VERSION)
187
+
188
+ if (keepCurrentVersion) {
189
+ editor.putString(KEY_PRIVACY_VERSION, privacyVersion)
190
+ } else {
191
+ privacyVersion = null
192
+ editor.remove(KEY_PRIVACY_VERSION)
193
+ }
194
+
195
+ editor.apply()
196
+ }
95
197
  }
@@ -1,13 +1,254 @@
1
- import type { ExpoGaodeMapModule } from './types/native-module.types';
2
- import { SDKConfig } from './types/common.types';
1
+ import { LatLng, Coordinates, ReGeocode, LocationListener, LatLngPoint, CoordinateType } from './types';
2
+ import type { ExpoGaodeMapModule as NativeExpoGaodeMapModule } from './types/native-module.types';
3
+ import { PrivacyConfig, PrivacyStatus, SDKConfig, PermissionStatus } from './types/common.types';
4
+ declare const helperMethods: {
5
+ /**
6
+ * 初始化 SDK,并缓存配置(包含 webKey)
7
+ * 注意:允许不提供任何 API Key,因为原生端可能已通过 Config Plugin 配置
8
+ */
9
+ initSDK(config: SDKConfig): void;
10
+ isSDKInitialized(): boolean;
11
+ /**
12
+ * 设置是否显示隐私政策弹窗
13
+ * @deprecated 请优先使用 `setPrivacyConfig`
14
+ */
15
+ setPrivacyShow(hasShow: boolean, hasContainsPrivacy: boolean): void;
16
+ /**
17
+ * 设置用户是否同意隐私政策
18
+ * @deprecated 请优先使用 `setPrivacyConfig`
19
+ */
20
+ setPrivacyAgree(hasAgree: boolean): void;
21
+ /**
22
+ * 设置当前隐私协议版本
23
+ * 当版本号变化时,之前的同意状态会失效
24
+ */
25
+ setPrivacyVersion(version: string): void;
26
+ /**
27
+ * 清空已持久化的隐私同意状态
28
+ */
29
+ resetPrivacyConsent(): void;
30
+ /**
31
+ * 一次性同步完整的隐私状态
32
+ * 推荐业务层只调用这个方法
33
+ */
34
+ setPrivacyConfig(config: PrivacyConfig): void;
35
+ getPrivacyStatus(): PrivacyStatus;
36
+ calculateDistanceBetweenPoints(p1: LatLngPoint, p2: LatLngPoint): number;
37
+ calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number;
38
+ setLoadWorldVectorMap(enabled: boolean): void;
39
+ getVersion(): string;
40
+ start(): void;
41
+ stop(): void;
42
+ isStarted(): Promise<boolean>;
43
+ getCurrentLocation(): Promise<Coordinates | ReGeocode>;
44
+ coordinateConvert(coordinate: LatLngPoint, type: CoordinateType): Promise<LatLng>;
45
+ setLocatingWithReGeocode(isReGeocode: boolean): void;
46
+ readonly isBackgroundLocationEnabled: boolean;
47
+ /**
48
+ * 检查位置权限状态
49
+ */
50
+ checkLocationPermission(): Promise<PermissionStatus>;
51
+ /**
52
+ * 请求前台位置权限(增强版)
53
+ */
54
+ requestLocationPermission(): Promise<PermissionStatus>;
55
+ /**
56
+ * 请求后台位置权限
57
+ * 注意:必须在前台权限已授予后才能请求
58
+ */
59
+ requestBackgroundLocationPermission(): Promise<PermissionStatus>;
60
+ /**
61
+ * 打开应用设置页面
62
+ * 引导用户手动授予权限
63
+ */
64
+ openAppSettings(): void;
65
+ setAllowsBackgroundLocationUpdates(allows: boolean): void;
66
+ /**
67
+ * 添加定位监听器(便捷方法)
68
+ * 自动订阅 onLocationUpdate 事件,提供容错处理
69
+ * @param listener 定位回调函数
70
+ * @returns 订阅对象,调用 remove() 取消监听
71
+ * 注意:如果使用 Config Plugin 配置了 API Key,无需调用 initSDK()
72
+ */
73
+ addLocationListener(listener: LocationListener): {
74
+ remove: () => void;
75
+ };
76
+ /**
77
+ * 计算两个坐标点之间的距离
78
+ * @param coordinate1 第一个坐标点
79
+ * @param coordinate2 第二个坐标点
80
+ * @returns 两点之间的距离(单位:米)
81
+ */
82
+ distanceBetweenCoordinates(coordinate1: LatLngPoint, coordinate2: LatLngPoint): number;
83
+ /**
84
+ * 判断点是否在圆内
85
+ * @param point 要判断的点
86
+ * @param center 圆心坐标
87
+ * @param radius 圆半径(单位:米)
88
+ * @returns 是否在圆内
89
+ */
90
+ isPointInCircle(point: LatLngPoint, center: LatLngPoint, radius: number): boolean;
91
+ /**
92
+ * 判断点是否在多边形内
93
+ * @param point 要判断的点
94
+ * @param polygon 多边形的顶点坐标数组
95
+ * @returns 是否在多边形内
96
+ */
97
+ isPointInPolygon(point: LatLngPoint, polygon: LatLngPoint[]): boolean;
98
+ /**
99
+ * 计算多边形面积
100
+ * @param polygon 多边形的顶点坐标数组
101
+ * @returns 面积(单位:平方米)
102
+ */
103
+ calculatePolygonArea(polygon: LatLngPoint[]): number;
104
+ /**
105
+ * 计算矩形面积
106
+ * @param southWest 西南角坐标
107
+ * @param northEast 东北角坐标
108
+ * @returns 面积(单位:平方米)
109
+ */
110
+ calculateRectangleArea(southWest: LatLngPoint, northEast: LatLngPoint): number;
111
+ /**
112
+ * 获取路径上距离目标点最近的点
113
+ * @param path 路径点集合
114
+ * @param target 目标点
115
+ * @returns 最近点信息,包含坐标、索引和距离
116
+ */
117
+ getNearestPointOnPath(path: LatLngPoint[], target: LatLngPoint): {
118
+ latitude: number;
119
+ longitude: number;
120
+ index: number;
121
+ distanceMeters: number;
122
+ } | null;
123
+ /**
124
+ * 计算多边形质心
125
+ * @param polygon 多边形顶点坐标数组
126
+ * @returns 质心坐标
127
+ */
128
+ calculateCentroid(polygon: LatLngPoint[]): LatLng | null;
129
+ /**
130
+ * 计算路径边界和中心点
131
+ * @param points 路径点集合
132
+ * @returns 边界信息,包含 north, south, east, west 和 center
133
+ */
134
+ calculatePathBounds(points: LatLngPoint[]): {
135
+ north: number;
136
+ south: number;
137
+ east: number;
138
+ west: number;
139
+ center: LatLngPoint;
140
+ } | null;
141
+ /**
142
+ * GeoHash 编码
143
+ * @param coordinate 坐标点
144
+ * @param precision 精度 (1-12)
145
+ * @returns GeoHash 字符串
146
+ */
147
+ encodeGeoHash(coordinate: LatLngPoint, precision: number): string;
148
+ /**
149
+ * 轨迹抽稀 (RDP 算法)
150
+ * @param points 原始轨迹点
151
+ * @param tolerance 允许误差(米)
152
+ * @returns 简化后的轨迹点
153
+ */
154
+ simplifyPolyline(points: LatLngPoint[], tolerance: number): LatLng[];
155
+ /**
156
+ * 计算路径总长度
157
+ * @param points 路径点
158
+ * @returns 长度(米)
159
+ */
160
+ calculatePathLength(points: LatLngPoint[]): number;
161
+ /**
162
+ * 解析高德地图 API 返回的 Polyline 字符串
163
+ * 格式: "lng,lat;lng,lat;..."
164
+ * @param polylineStr 高德原始 polyline 字符串,或包含 polyline 属性的对象
165
+ * @returns 解析后的点集
166
+ */
167
+ parsePolyline(polylineStr: string | {
168
+ polyline: string;
169
+ }): LatLng[];
170
+ /**
171
+ * 获取路径上指定距离的点
172
+ * @param points 路径点
173
+ * @param distance 距离起点的米数
174
+ * @returns 点信息(坐标+角度)
175
+ */
176
+ getPointAtDistance(points: LatLngPoint[], distance: number): {
177
+ latitude: number;
178
+ longitude: number;
179
+ angle: number;
180
+ } | null;
181
+ /**
182
+ * 经纬度转换为地图瓦片坐标
183
+ * @param coordinate 经纬度点
184
+ * @param zoom 缩放级别
185
+ * @returns 瓦片坐标(x, y, z)
186
+ */
187
+ latLngToTile(coordinate: LatLngPoint, zoom: number): {
188
+ x: number;
189
+ y: number;
190
+ z: number;
191
+ } | null;
192
+ /**
193
+ * 地图瓦片坐标转换为经纬度
194
+ * @param tile 瓦片坐标(x, y, z)
195
+ * @returns 经纬度点
196
+ */
197
+ tileToLatLng(tile: {
198
+ x: number;
199
+ y: number;
200
+ z: number;
201
+ }): LatLng | null;
202
+ /**
203
+ * 经纬度转换为地图像素坐标
204
+ * @param coordinate 经纬度点
205
+ * @param zoom 缩放级别
206
+ * @returns 像素坐标(x, y)
207
+ */
208
+ latLngToPixel(coordinate: LatLngPoint, zoom: number): {
209
+ x: number;
210
+ y: number;
211
+ } | null;
212
+ /**
213
+ * 地图像素坐标转换为经纬度
214
+ * @param pixel 像素坐标(x, y)
215
+ * @param zoom 缩放级别
216
+ * @returns 经纬度点
217
+ */
218
+ pixelToLatLng(pixel: {
219
+ x: number;
220
+ y: number;
221
+ }, zoom: number): LatLng | null;
222
+ /**
223
+ * 批量地理围栏检测
224
+ * @param point 待检查的点
225
+ * @param polygons 多边形数组,格式为 LatLngPoint[][] 或 LatLngPoint[][][]
226
+ * @returns 包含点索引的数组(-1 表示不在任何多边形内)
227
+ */
228
+ findPointInPolygons(point: LatLngPoint, polygons: LatLngPoint[][] | LatLngPoint[][][]): number;
229
+ /**
230
+ * 生成网格聚合数据 (常用于展示网格聚合图或大规模点数据处理)
231
+ * @param points 包含经纬度和权重的点数组
232
+ * @param gridSizeMeters 网格大小(米)
233
+ * @returns 包含经纬度和强度的网格点数组
234
+ */
235
+ generateHeatmapGrid(points: Array<LatLngPoint & {
236
+ weight?: number;
237
+ }>, gridSizeMeters: number): Array<{
238
+ latitude: number;
239
+ longitude: number;
240
+ intensity: number;
241
+ }>;
242
+ };
3
243
  /**
4
244
  * 获取最近一次 initSDK 的配置
5
245
  */
6
246
  export declare function getSDKConfig(): SDKConfig | null;
247
+ export type ExpoGaodeMapModule = typeof helperMethods & NativeExpoGaodeMapModule;
248
+ declare const ExpoGaodeMapModuleWithHelpers: ExpoGaodeMapModule;
7
249
  /**
8
250
  * 获取用于 Web API 的 webKey(若未初始化或未提供则返回 undefined)
9
251
  */
10
252
  export declare function getWebKey(): string | undefined;
11
- declare const _default: ExpoGaodeMapModule;
12
- export default _default;
253
+ export default ExpoGaodeMapModuleWithHelpers;
13
254
  //# sourceMappingURL=ExpoGaodeMapModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoGaodeMapModule.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapModule.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAAiB,SAAS,EAAoB,MAAM,sBAAsB,CAAC;AA2tBlF;;EAEE;AACF,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAE/C;AAYD;;EAEE;AACF,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;wBAE0D,kBAAkB;AAA7E,wBAA8E"}
1
+ {"version":3,"file":"ExpoGaodeMapModule.d.ts","sourceRoot":"","sources":["../src/ExpoGaodeMapModule.ts"],"names":[],"mappings":"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"}
@@ -20,15 +20,63 @@ function getNativeModule(optional = false) {
20
20
  throw moduleError;
21
21
  }
22
22
  }
23
+ function getBoundNativeValue(module, prop) {
24
+ const value = Reflect.get(module, prop, module);
25
+ if (typeof value === 'function') {
26
+ return (...args) => value.apply(module, args);
27
+ }
28
+ return value;
29
+ }
23
30
  const nativeModule = new Proxy({}, {
24
31
  get(_target, prop) {
25
32
  const module = getNativeModule(true);
26
- return module ? Reflect.get(module, prop) : undefined;
33
+ return module ? getBoundNativeValue(module, prop) : undefined;
27
34
  },
28
35
  });
29
36
  // 记录最近一次 initSDK 的配置(含 webKey)
30
37
  let _sdkConfig = null;
31
38
  let _isSDKInitialized = false;
39
+ const privacySensitiveMethodNames = new Set([
40
+ 'start',
41
+ 'stop',
42
+ 'isStarted',
43
+ 'getCurrentLocation',
44
+ 'coordinateConvert',
45
+ 'setLocatingWithReGeocode',
46
+ 'setLocationMode',
47
+ 'setInterval',
48
+ 'setOnceLocation',
49
+ 'setSensorEnable',
50
+ 'setWifiScan',
51
+ 'setGpsFirst',
52
+ 'setOnceLocationLatest',
53
+ 'setGeoLanguage',
54
+ 'setLocationCacheEnable',
55
+ 'setHttpTimeOut',
56
+ 'setDesiredAccuracy',
57
+ 'setLocationTimeout',
58
+ 'setReGeocodeTimeout',
59
+ 'setDistanceFilter',
60
+ 'setPausesLocationUpdatesAutomatically',
61
+ 'setAllowsBackgroundLocationUpdates',
62
+ 'setLocationProtocol',
63
+ 'startUpdatingHeading',
64
+ 'stopUpdatingHeading',
65
+ 'checkLocationPermission',
66
+ 'requestLocationPermission',
67
+ 'requestBackgroundLocationPermission',
68
+ 'addLocationListener',
69
+ ]);
70
+ function assertPrivacyReady(scene = 'sdk') {
71
+ const nativeModule = getNativeModule();
72
+ if (!nativeModule) {
73
+ throw ErrorHandler.nativeModuleUnavailable();
74
+ }
75
+ const status = nativeModule.getPrivacyStatus();
76
+ if (!status.isReady) {
77
+ throw ErrorHandler.privacyNotAgreed(scene);
78
+ }
79
+ }
32
80
  // 扩展原生模块,添加便捷方法
33
81
  const helperMethods = {
34
82
  /**
@@ -40,6 +88,10 @@ const helperMethods = {
40
88
  if (!nativeModule)
41
89
  throw ErrorHandler.nativeModuleUnavailable();
42
90
  try {
91
+ const privacyStatus = nativeModule.getPrivacyStatus();
92
+ if (!privacyStatus.isReady) {
93
+ throw ErrorHandler.privacyNotAgreed('sdk');
94
+ }
43
95
  // 检查是否有任何 key 被提供
44
96
  const hasJSKeys = !!(config.androidKey || config.iosKey);
45
97
  const hasWebKey = !!config.webKey;
@@ -67,22 +119,56 @@ const helperMethods = {
67
119
  isSDKInitialized() {
68
120
  return _isSDKInitialized;
69
121
  },
122
+ /**
123
+ * 设置是否显示隐私政策弹窗
124
+ * @deprecated 请优先使用 `setPrivacyConfig`
125
+ */
70
126
  setPrivacyShow(hasShow, hasContainsPrivacy) {
71
127
  const nativeModule = getNativeModule();
72
128
  if (!nativeModule)
73
129
  throw ErrorHandler.nativeModuleUnavailable();
74
130
  nativeModule.setPrivacyShow(hasShow, hasContainsPrivacy);
75
131
  },
132
+ /**
133
+ * 设置用户是否同意隐私政策
134
+ * @deprecated 请优先使用 `setPrivacyConfig`
135
+ */
76
136
  setPrivacyAgree(hasAgree) {
77
137
  const nativeModule = getNativeModule();
78
138
  if (!nativeModule)
79
139
  throw ErrorHandler.nativeModuleUnavailable();
80
140
  nativeModule.setPrivacyAgree(hasAgree);
81
141
  },
142
+ /**
143
+ * 设置当前隐私协议版本
144
+ * 当版本号变化时,之前的同意状态会失效
145
+ */
146
+ setPrivacyVersion(version) {
147
+ const nativeModule = getNativeModule();
148
+ if (!nativeModule)
149
+ throw ErrorHandler.nativeModuleUnavailable();
150
+ nativeModule.setPrivacyVersion(version);
151
+ },
152
+ /**
153
+ * 清空已持久化的隐私同意状态
154
+ */
155
+ resetPrivacyConsent() {
156
+ const nativeModule = getNativeModule();
157
+ if (!nativeModule)
158
+ throw ErrorHandler.nativeModuleUnavailable();
159
+ nativeModule.resetPrivacyConsent();
160
+ },
161
+ /**
162
+ * 一次性同步完整的隐私状态
163
+ * 推荐业务层只调用这个方法
164
+ */
82
165
  setPrivacyConfig(config) {
83
166
  const nativeModule = getNativeModule();
84
167
  if (!nativeModule)
85
168
  throw ErrorHandler.nativeModuleUnavailable();
169
+ if (typeof config.privacyVersion === 'string') {
170
+ nativeModule.setPrivacyVersion(config.privacyVersion);
171
+ }
86
172
  nativeModule.setPrivacyShow(config.hasShow, config.hasContainsPrivacy);
87
173
  nativeModule.setPrivacyAgree(config.hasAgree);
88
174
  },
@@ -94,6 +180,9 @@ const helperMethods = {
94
180
  hasContainsPrivacy: false,
95
181
  hasAgree: false,
96
182
  isReady: false,
183
+ privacyVersion: null,
184
+ agreedPrivacyVersion: null,
185
+ restoredFromStorage: false,
97
186
  };
98
187
  }
99
188
  return nativeModule.getPrivacyStatus();
@@ -136,6 +225,7 @@ const helperMethods = {
136
225
  }
137
226
  },
138
227
  start() {
228
+ assertPrivacyReady('sdk');
139
229
  const nativeModule = getNativeModule(true);
140
230
  if (!nativeModule)
141
231
  return;
@@ -147,6 +237,7 @@ const helperMethods = {
147
237
  }
148
238
  },
149
239
  stop() {
240
+ assertPrivacyReady('sdk');
150
241
  const nativeModule = getNativeModule(true);
151
242
  if (!nativeModule)
152
243
  return;
@@ -158,6 +249,7 @@ const helperMethods = {
158
249
  }
159
250
  },
160
251
  isStarted() {
252
+ assertPrivacyReady('sdk');
161
253
  const nativeModule = getNativeModule(true);
162
254
  if (!nativeModule)
163
255
  return Promise.resolve(false);
@@ -170,6 +262,7 @@ const helperMethods = {
170
262
  }
171
263
  },
172
264
  async getCurrentLocation() {
265
+ assertPrivacyReady('sdk');
173
266
  const nativeModule = getNativeModule();
174
267
  if (!nativeModule) {
175
268
  throw ErrorHandler.nativeModuleUnavailable();
@@ -182,6 +275,7 @@ const helperMethods = {
182
275
  }
183
276
  },
184
277
  async coordinateConvert(coordinate, type) {
278
+ assertPrivacyReady('sdk');
185
279
  const nativeModule = getNativeModule();
186
280
  if (!nativeModule) {
187
281
  throw ErrorHandler.nativeModuleUnavailable();
@@ -194,6 +288,7 @@ const helperMethods = {
194
288
  }
195
289
  },
196
290
  setLocatingWithReGeocode(isReGeocode) {
291
+ assertPrivacyReady('sdk');
197
292
  const nativeModule = getNativeModule(true);
198
293
  if (!nativeModule)
199
294
  return;
@@ -214,6 +309,7 @@ const helperMethods = {
214
309
  * 检查位置权限状态
215
310
  */
216
311
  async checkLocationPermission() {
312
+ assertPrivacyReady('sdk');
217
313
  const nativeModule = getNativeModule();
218
314
  if (!nativeModule) {
219
315
  throw ErrorHandler.nativeModuleUnavailable();
@@ -229,6 +325,7 @@ const helperMethods = {
229
325
  * 请求前台位置权限(增强版)
230
326
  */
231
327
  async requestLocationPermission() {
328
+ assertPrivacyReady('sdk');
232
329
  const nativeModule = getNativeModule();
233
330
  if (!nativeModule) {
234
331
  throw ErrorHandler.nativeModuleUnavailable();
@@ -249,6 +346,7 @@ const helperMethods = {
249
346
  * 注意:必须在前台权限已授予后才能请求
250
347
  */
251
348
  async requestBackgroundLocationPermission() {
349
+ assertPrivacyReady('sdk');
252
350
  const nativeModule = getNativeModule();
253
351
  if (!nativeModule) {
254
352
  throw ErrorHandler.nativeModuleUnavailable();
@@ -281,6 +379,7 @@ const helperMethods = {
281
379
  }
282
380
  },
283
381
  setAllowsBackgroundLocationUpdates(allows) {
382
+ assertPrivacyReady('sdk');
284
383
  const nativeModule = getNativeModule();
285
384
  if (!nativeModule) {
286
385
  throw ErrorHandler.nativeModuleUnavailable();
@@ -316,6 +415,7 @@ const helperMethods = {
316
415
  * 注意:如果使用 Config Plugin 配置了 API Key,无需调用 initSDK()
317
416
  */
318
417
  addLocationListener(listener) {
418
+ assertPrivacyReady('sdk');
319
419
  const module = getNativeModule();
320
420
  if (!module) {
321
421
  throw ErrorHandler.nativeModuleUnavailable();
@@ -688,7 +788,19 @@ const ExpoGaodeMapModuleWithHelpers = new Proxy(helperMethods, {
688
788
  return Reflect.get(target, prop, receiver);
689
789
  }
690
790
  const nativeModule = getNativeModule(true);
691
- return nativeModule ? Reflect.get(nativeModule, prop) : undefined;
791
+ if (!nativeModule) {
792
+ return undefined;
793
+ }
794
+ const value = Reflect.get(nativeModule, prop, nativeModule);
795
+ if (typeof prop === 'string' &&
796
+ privacySensitiveMethodNames.has(prop) &&
797
+ typeof value === 'function') {
798
+ return (...args) => {
799
+ assertPrivacyReady('sdk');
800
+ return value.apply(nativeModule, args);
801
+ };
802
+ }
803
+ return getBoundNativeValue(nativeModule, prop);
692
804
  },
693
805
  });
694
806
  /**