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,421 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 高德地图错误处理工具
|
|
4
|
+
* 提供友好的错误提示和解决方案指引
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ErrorLogger = exports.ErrorHandler = exports.GaodeMapError = exports.ErrorType = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* 错误类型枚举
|
|
10
|
+
*/
|
|
11
|
+
var ErrorType;
|
|
12
|
+
(function (ErrorType) {
|
|
13
|
+
/** SDK 未初始化 */
|
|
14
|
+
ErrorType["SDK_NOT_INITIALIZED"] = "SDK_NOT_INITIALIZED";
|
|
15
|
+
/** API Key 配置错误 */
|
|
16
|
+
ErrorType["INVALID_API_KEY"] = "INVALID_API_KEY";
|
|
17
|
+
/** 权限未授予 */
|
|
18
|
+
ErrorType["PERMISSION_DENIED"] = "PERMISSION_DENIED";
|
|
19
|
+
/** 定位失败 */
|
|
20
|
+
ErrorType["LOCATION_FAILED"] = "LOCATION_FAILED";
|
|
21
|
+
/** 原生模块不可用 */
|
|
22
|
+
ErrorType["NATIVE_MODULE_UNAVAILABLE"] = "NATIVE_MODULE_UNAVAILABLE";
|
|
23
|
+
/** 地图视图未初始化 */
|
|
24
|
+
ErrorType["MAP_VIEW_NOT_INITIALIZED"] = "MAP_VIEW_NOT_INITIALIZED";
|
|
25
|
+
/** 参数错误 */
|
|
26
|
+
ErrorType["INVALID_PARAMETER"] = "INVALID_PARAMETER";
|
|
27
|
+
/** 网络错误 */
|
|
28
|
+
ErrorType["NETWORK_ERROR"] = "NETWORK_ERROR";
|
|
29
|
+
})(ErrorType || (exports.ErrorType = ErrorType = {}));
|
|
30
|
+
/**
|
|
31
|
+
* 自定义错误类
|
|
32
|
+
*/
|
|
33
|
+
class GaodeMapError extends Error {
|
|
34
|
+
constructor(details) {
|
|
35
|
+
const fullMessage = `
|
|
36
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
37
|
+
🗺️ 高德地图错误 [${details.type}]
|
|
38
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
39
|
+
|
|
40
|
+
❌ 错误信息:
|
|
41
|
+
${details.message}
|
|
42
|
+
|
|
43
|
+
💡 解决方案:
|
|
44
|
+
${details.solution}
|
|
45
|
+
|
|
46
|
+
${details.docUrl ? `📖 详细文档:\n ${details.docUrl}\n` : ''}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
47
|
+
`;
|
|
48
|
+
super(fullMessage);
|
|
49
|
+
this.name = 'GaodeMapError';
|
|
50
|
+
this.type = details.type;
|
|
51
|
+
this.solution = details.solution;
|
|
52
|
+
this.docUrl = details.docUrl;
|
|
53
|
+
this.originalError = details.originalError;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.GaodeMapError = GaodeMapError;
|
|
57
|
+
/**
|
|
58
|
+
* 错误处理器类
|
|
59
|
+
*/
|
|
60
|
+
class ErrorHandler {
|
|
61
|
+
/**
|
|
62
|
+
* SDK 未初始化错误
|
|
63
|
+
*/
|
|
64
|
+
static sdkNotInitialized() {
|
|
65
|
+
return new GaodeMapError({
|
|
66
|
+
type: ErrorType.SDK_NOT_INITIALIZED,
|
|
67
|
+
message: '高德地图 SDK 尚未初始化',
|
|
68
|
+
solution: `请在使用地图功能前先调用 initSDK():
|
|
69
|
+
|
|
70
|
+
import ExpoGaodeMapModule from 'expo-gaode-map';
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
// 在组件挂载时初始化
|
|
74
|
+
ExpoGaodeMapModule.initSDK({
|
|
75
|
+
androidKey: 'your-android-key',
|
|
76
|
+
iosKey: 'your-ios-key',
|
|
77
|
+
});
|
|
78
|
+
}, []);
|
|
79
|
+
|
|
80
|
+
⚠️ 常见原因:
|
|
81
|
+
1. 忘记调用 initSDK() 就使用了定位或地图功能
|
|
82
|
+
2. initSDK() 调用时机过晚(应在 useEffect 中尽早调用)
|
|
83
|
+
3. 使用 Config Plugin 但未重新构建原生代码`,
|
|
84
|
+
docUrl: `${this.docBaseUrl}/guide/initialization.html`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* API Key 配置错误
|
|
89
|
+
*/
|
|
90
|
+
static invalidApiKey(platform) {
|
|
91
|
+
const platformText = {
|
|
92
|
+
android: 'Android',
|
|
93
|
+
ios: 'iOS',
|
|
94
|
+
both: 'Android 和 iOS',
|
|
95
|
+
}[platform];
|
|
96
|
+
return new GaodeMapError({
|
|
97
|
+
type: ErrorType.INVALID_API_KEY,
|
|
98
|
+
message: `${platformText} API Key 配置错误或未配置`,
|
|
99
|
+
solution: `⚠️ API Key 与 Bundle ID 不匹配是最常见的原因!
|
|
100
|
+
|
|
101
|
+
请检查以下步骤:
|
|
102
|
+
|
|
103
|
+
1️⃣ 确认 API Key 的配置:
|
|
104
|
+
• 访问高德开放平台:https://lbs.amap.com/
|
|
105
|
+
• 检查您的应用配置中的 Bundle ID 是否与当前项目一致
|
|
106
|
+
• iOS Bundle ID:在 Xcode → Target → General → Bundle Identifier 查看
|
|
107
|
+
• Android 包名:在 android/app/build.gradle → applicationId 查看
|
|
108
|
+
|
|
109
|
+
2️⃣ 重新创建正确的 API Key(如果 Bundle ID 不同):
|
|
110
|
+
• 在高德开放平台创建新应用
|
|
111
|
+
• 填写正确的 Bundle ID(iOS)或包名(Android)
|
|
112
|
+
• 获取新的 API Key
|
|
113
|
+
|
|
114
|
+
3️⃣ 配置 API Key(推荐使用 Config Plugin):
|
|
115
|
+
|
|
116
|
+
在 app.json 中配置:
|
|
117
|
+
{
|
|
118
|
+
"expo": {
|
|
119
|
+
"plugins": [
|
|
120
|
+
[
|
|
121
|
+
"expo-gaode-map",
|
|
122
|
+
{
|
|
123
|
+
"androidKey": "your-android-key",
|
|
124
|
+
"iosKey": "your-ios-key"
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
然后重新构建:
|
|
132
|
+
npx expo prebuild --clean
|
|
133
|
+
npx expo run:${platform === 'ios' ? 'ios' : 'android'}
|
|
134
|
+
|
|
135
|
+
4️⃣ 或在代码中配置:
|
|
136
|
+
ExpoGaodeMapModule.initSDK({
|
|
137
|
+
androidKey: 'your-android-key',
|
|
138
|
+
iosKey: 'your-ios-key',
|
|
139
|
+
});`,
|
|
140
|
+
docUrl: `${this.docBaseUrl}/guide/initialization.html`,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 权限未授予错误
|
|
145
|
+
*/
|
|
146
|
+
static permissionDenied(permissionType) {
|
|
147
|
+
return new GaodeMapError({
|
|
148
|
+
type: ErrorType.PERMISSION_DENIED,
|
|
149
|
+
message: '定位权限未授予,无法使用定位功能',
|
|
150
|
+
solution: `请按以下步骤授予权限:
|
|
151
|
+
|
|
152
|
+
1️⃣ 请求权限:
|
|
153
|
+
import ExpoGaodeMapModule from 'expo-gaode-map';
|
|
154
|
+
|
|
155
|
+
const checkPermission = async () => {
|
|
156
|
+
// 检查权限状态
|
|
157
|
+
const status = await ExpoGaodeMapModule.checkLocationPermission();
|
|
158
|
+
|
|
159
|
+
if (!status.granted) {
|
|
160
|
+
// 请求权限
|
|
161
|
+
const result = await ExpoGaodeMapModule.requestLocationPermission();
|
|
162
|
+
|
|
163
|
+
if (!result.granted) {
|
|
164
|
+
// 用户拒绝授权,引导用户去设置
|
|
165
|
+
Alert.alert(
|
|
166
|
+
'需要定位权限',
|
|
167
|
+
'请在设置中开启定位权限以使用地图功能',
|
|
168
|
+
[
|
|
169
|
+
{ text: '取消', style: 'cancel' },
|
|
170
|
+
{ text: '去设置', onPress: () => Linking.openSettings() }
|
|
171
|
+
]
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
2️⃣ iOS 配置(在 app.json 中):
|
|
178
|
+
{
|
|
179
|
+
"expo": {
|
|
180
|
+
"ios": {
|
|
181
|
+
"infoPlist": {
|
|
182
|
+
"NSLocationWhenInUseUsageDescription": "需要获取您的位置信息以显示地图",
|
|
183
|
+
"NSLocationAlwaysAndWhenInUseUsageDescription": "需要获取您的位置信息"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
3️⃣ Android 配置(Config Plugin 会自动添加):
|
|
190
|
+
使用 expo-gaode-map 的 Config Plugin 会自动添加必要的权限声明`,
|
|
191
|
+
docUrl: `${this.docBaseUrl}/guide/getting-started.html#权限配置`,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* 定位失败错误
|
|
196
|
+
*/
|
|
197
|
+
static locationFailed(reason) {
|
|
198
|
+
return new GaodeMapError({
|
|
199
|
+
type: ErrorType.LOCATION_FAILED,
|
|
200
|
+
message: `定位失败${reason ? `:${reason}` : ''}`,
|
|
201
|
+
solution: `⚠️ 最常见原因:API Key 与 Bundle ID 不匹配!
|
|
202
|
+
|
|
203
|
+
请按以下顺序排查:
|
|
204
|
+
|
|
205
|
+
1️⃣ 检查 API Key 配置(最常见问题):
|
|
206
|
+
• 访问高德开放平台:https://lbs.amap.com/
|
|
207
|
+
• 确认您的应用的 Bundle ID 与当前项目一致
|
|
208
|
+
• iOS Bundle ID:在 Xcode → Target → General → Bundle Identifier
|
|
209
|
+
• Android 包名:在 android/app/build.gradle → applicationId
|
|
210
|
+
|
|
211
|
+
如果 Bundle ID 不同,必须在高德平台重新创建应用并获取新 Key
|
|
212
|
+
|
|
213
|
+
2️⃣ 检查设备 GPS 和网络:
|
|
214
|
+
• 确认设备 GPS 已开启
|
|
215
|
+
• 检查网络连接是否正常
|
|
216
|
+
• 尝试在室外空旷处测试
|
|
217
|
+
|
|
218
|
+
3️⃣ 检查定位权限:
|
|
219
|
+
• iOS:设置 → 隐私 → 定位服务 → 允许应用访问
|
|
220
|
+
• Android:设置 → 应用 → 权限管理 → 位置信息
|
|
221
|
+
|
|
222
|
+
4️⃣ 配置定位参数(如果 API Key 正确但定位仍失败):
|
|
223
|
+
ExpoGaodeMapModule.setLocationTimeout(30); // 增加超时时间
|
|
224
|
+
ExpoGaodeMapModule.setInterval(2000); // 设置定位间隔
|
|
225
|
+
|
|
226
|
+
// Android 特有配置
|
|
227
|
+
ExpoGaodeMapModule.setLocationMode(2); // 高精度模式
|
|
228
|
+
ExpoGaodeMapModule.setGpsFirst(true); // GPS 优先
|
|
229
|
+
|
|
230
|
+
// iOS 特有配置
|
|
231
|
+
ExpoGaodeMapModule.setDesiredAccuracy(0); // 最佳精度`,
|
|
232
|
+
docUrl: `${this.docBaseUrl}/api/location.html`,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 原生模块不可用错误
|
|
237
|
+
*/
|
|
238
|
+
static nativeModuleUnavailable() {
|
|
239
|
+
return new GaodeMapError({
|
|
240
|
+
type: ErrorType.NATIVE_MODULE_UNAVAILABLE,
|
|
241
|
+
message: 'expo-gaode-map 原生模块不可用',
|
|
242
|
+
solution: `请检查以下步骤:
|
|
243
|
+
|
|
244
|
+
1️⃣ 确认已正确安装:
|
|
245
|
+
npm install expo-gaode-map
|
|
246
|
+
# 或
|
|
247
|
+
bun install expo-gaode-map
|
|
248
|
+
|
|
249
|
+
2️⃣ 重新构建原生代码:
|
|
250
|
+
npx expo prebuild --clean
|
|
251
|
+
npx expo run:android
|
|
252
|
+
npx expo run:ios
|
|
253
|
+
|
|
254
|
+
3️⃣ 检查 Expo 版本兼容性:
|
|
255
|
+
• expo-gaode-map 需要 Expo SDK 49+
|
|
256
|
+
• 不支持 Expo Go,必须使用 Development Build
|
|
257
|
+
|
|
258
|
+
4️⃣ 检查是否与其他包冲突:
|
|
259
|
+
• 不能同时安装 expo-gaode-map 和 expo-gaode-map-navigation
|
|
260
|
+
• 两个包选择其一使用
|
|
261
|
+
|
|
262
|
+
5️⃣ 清理缓存后重试:
|
|
263
|
+
cd android && ./gradlew clean && cd ..
|
|
264
|
+
cd ios && pod deintegrate && pod install && cd ..`,
|
|
265
|
+
docUrl: `${this.docBaseUrl}/guide/getting-started.html`,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* 地图视图未初始化错误
|
|
270
|
+
*/
|
|
271
|
+
static mapViewNotInitialized(methodName) {
|
|
272
|
+
return new GaodeMapError({
|
|
273
|
+
type: ErrorType.MAP_VIEW_NOT_INITIALIZED,
|
|
274
|
+
message: `无法调用 ${methodName}:地图视图尚未初始化`,
|
|
275
|
+
solution: `请确保:
|
|
276
|
+
|
|
277
|
+
1️⃣ MapView 已经渲染完成
|
|
278
|
+
2️⃣ 使用 ref 获取地图实例后再调用方法
|
|
279
|
+
|
|
280
|
+
正确用法:
|
|
281
|
+
import { MapView, MapViewRef } from 'expo-gaode-map';
|
|
282
|
+
|
|
283
|
+
const App = () => {
|
|
284
|
+
const mapRef = useRef<MapViewRef>(null);
|
|
285
|
+
|
|
286
|
+
// ❌ 错误:在渲染前调用
|
|
287
|
+
// mapRef.current?.moveCamera(...);
|
|
288
|
+
|
|
289
|
+
// ✅ 正确:等待地图加载完成
|
|
290
|
+
const handleMapReady = () => {
|
|
291
|
+
mapRef.current?.moveCamera({
|
|
292
|
+
target: { latitude: 39.9, longitude: 116.4 },
|
|
293
|
+
zoom: 15,
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
return (
|
|
298
|
+
<MapView
|
|
299
|
+
ref={mapRef}
|
|
300
|
+
onMapReady={handleMapReady}
|
|
301
|
+
/>
|
|
302
|
+
);
|
|
303
|
+
};`,
|
|
304
|
+
docUrl: `${this.docBaseUrl}/api/mapview.html`,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* 参数错误
|
|
309
|
+
*/
|
|
310
|
+
static invalidParameter(paramName, expected, received) {
|
|
311
|
+
return new GaodeMapError({
|
|
312
|
+
type: ErrorType.INVALID_PARAMETER,
|
|
313
|
+
message: `参数 "${paramName}" 类型错误`,
|
|
314
|
+
solution: `期望类型:${expected}
|
|
315
|
+
实际接收:${typeof received} (${JSON.stringify(received)})
|
|
316
|
+
|
|
317
|
+
请检查传入的参数是否符合要求。
|
|
318
|
+
|
|
319
|
+
💡 提示:
|
|
320
|
+
• 使用 TypeScript 可以在编译时发现类型错误
|
|
321
|
+
• 参考 API 文档了解正确的参数类型`,
|
|
322
|
+
docUrl: `${this.docBaseUrl}/api/`,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* 网络错误
|
|
327
|
+
*/
|
|
328
|
+
static networkError(originalError) {
|
|
329
|
+
return new GaodeMapError({
|
|
330
|
+
type: ErrorType.NETWORK_ERROR,
|
|
331
|
+
message: '网络请求失败',
|
|
332
|
+
solution: `请检查:
|
|
333
|
+
|
|
334
|
+
1️⃣ 网络连接是否正常
|
|
335
|
+
2️⃣ API Key 是否有效
|
|
336
|
+
3️⃣ 是否超出配额限制
|
|
337
|
+
|
|
338
|
+
💡 如果问题持续,请:
|
|
339
|
+
• 检查高德开放平台控制台
|
|
340
|
+
• 查看 API 调用量和配额
|
|
341
|
+
• 确认 Key 的服务是否已开通`,
|
|
342
|
+
docUrl: `${this.docBaseUrl}/guide/troubleshooting.html`,
|
|
343
|
+
originalError,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* 包装原生错误,提供更友好的提示
|
|
348
|
+
*/
|
|
349
|
+
static wrapNativeError(error, context) {
|
|
350
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
351
|
+
// SDK 未初始化相关错误
|
|
352
|
+
if (errorMessage.includes('not initialized') ||
|
|
353
|
+
errorMessage.includes('未初始化') ||
|
|
354
|
+
errorMessage.includes('SDK未设置')) {
|
|
355
|
+
return this.sdkNotInitialized();
|
|
356
|
+
}
|
|
357
|
+
// API Key 相关错误
|
|
358
|
+
if (errorMessage.includes('key') ||
|
|
359
|
+
errorMessage.includes('invalid') ||
|
|
360
|
+
errorMessage.includes('鉴权失败')) {
|
|
361
|
+
return this.invalidApiKey('both');
|
|
362
|
+
}
|
|
363
|
+
// 权限相关错误
|
|
364
|
+
if (errorMessage.includes('permission') ||
|
|
365
|
+
errorMessage.includes('权限')) {
|
|
366
|
+
return this.permissionDenied('location');
|
|
367
|
+
}
|
|
368
|
+
// 定位相关错误
|
|
369
|
+
if (errorMessage.includes('location') ||
|
|
370
|
+
errorMessage.includes('定位')) {
|
|
371
|
+
return this.locationFailed(errorMessage);
|
|
372
|
+
}
|
|
373
|
+
// 通用错误
|
|
374
|
+
return new GaodeMapError({
|
|
375
|
+
type: ErrorType.INVALID_PARAMETER,
|
|
376
|
+
message: `${context} 失败`,
|
|
377
|
+
solution: `原始错误信息:${errorMessage}
|
|
378
|
+
|
|
379
|
+
如果问题持续,请:
|
|
380
|
+
1. 查看完整的错误堆栈
|
|
381
|
+
2. 检查 API 调用参数
|
|
382
|
+
3. 提交 Issue:https://github.com/TomWq/expo-gaode-map/issues`,
|
|
383
|
+
originalError: error instanceof Error ? error : undefined,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
exports.ErrorHandler = ErrorHandler;
|
|
388
|
+
ErrorHandler.docBaseUrl = 'https://TomWq.github.io/expo-gaode-map';
|
|
389
|
+
/**
|
|
390
|
+
* 错误日志工具
|
|
391
|
+
*/
|
|
392
|
+
class ErrorLogger {
|
|
393
|
+
/**
|
|
394
|
+
* 启用/禁用错误日志
|
|
395
|
+
*/
|
|
396
|
+
static setEnabled(enabled) {
|
|
397
|
+
this.isEnabled = enabled;
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* 记录错误
|
|
401
|
+
*/
|
|
402
|
+
static log(error) {
|
|
403
|
+
if (!this.isEnabled)
|
|
404
|
+
return;
|
|
405
|
+
console.error(error.message);
|
|
406
|
+
if (error.originalError) {
|
|
407
|
+
console.error('原始错误:', error.originalError);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* 记录警告
|
|
412
|
+
*/
|
|
413
|
+
static warn(message, details) {
|
|
414
|
+
if (!this.isEnabled)
|
|
415
|
+
return;
|
|
416
|
+
console.warn(`⚠️ expo-gaode-map: ${message}`, details || '');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
exports.ErrorLogger = ErrorLogger;
|
|
420
|
+
// 兼容不同环境:Bun/Jest/Node
|
|
421
|
+
ErrorLogger.isEnabled = typeof __DEV__ !== 'undefined' ? __DEV__ : true;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LatLng, LatLngPoint } from '../types/common.types';
|
|
2
|
+
/**
|
|
3
|
+
* 将坐标点归一化为对象格式
|
|
4
|
+
* 支持 [longitude, latitude] 数组或 { latitude, longitude } 对象
|
|
5
|
+
* 注意:数组格式遵循 GeoJSON 标准,即 [经度, 纬度]
|
|
6
|
+
*
|
|
7
|
+
* @param point 坐标点
|
|
8
|
+
* @returns { latitude, longitude } 对象
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeLatLng(point: LatLngPoint): LatLng;
|
|
11
|
+
/**
|
|
12
|
+
* 将坐标点数组归一化为对象数组
|
|
13
|
+
* 支持一维数组 [p1, p2, ...] 或二维嵌套数组 [[p1, p2, ...], [p3, p4, ...]]
|
|
14
|
+
*
|
|
15
|
+
* @param points 坐标点数组或嵌套数组
|
|
16
|
+
* @returns 归一化后的坐标数组
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeLatLngList(points: LatLngPoint[]): LatLng[];
|
|
19
|
+
export declare function normalizeLatLngList(points: LatLngPoint[][]): LatLng[][];
|
|
20
|
+
export declare function normalizeLatLngList(points: LatLngPoint[] | LatLngPoint[][]): LatLng[] | LatLng[][];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeLatLng = normalizeLatLng;
|
|
4
|
+
exports.normalizeLatLngList = normalizeLatLngList;
|
|
5
|
+
/**
|
|
6
|
+
* 将坐标点归一化为对象格式
|
|
7
|
+
* 支持 [longitude, latitude] 数组或 { latitude, longitude } 对象
|
|
8
|
+
* 注意:数组格式遵循 GeoJSON 标准,即 [经度, 纬度]
|
|
9
|
+
*
|
|
10
|
+
* @param point 坐标点
|
|
11
|
+
* @returns { latitude, longitude } 对象
|
|
12
|
+
*/
|
|
13
|
+
function normalizeLatLng(point) {
|
|
14
|
+
if (Array.isArray(point)) {
|
|
15
|
+
let longitude = point[0];
|
|
16
|
+
let latitude = point[1];
|
|
17
|
+
// 智能纠错:如果纬度超出范围 [-90, 90] 且交换后在范围内,则认为是用户传反了
|
|
18
|
+
if (Math.abs(latitude) > 90 && Math.abs(longitude) <= 90) {
|
|
19
|
+
console.warn(`[expo-gaode-map] 检测到坐标数组格式可能为 [latitude, longitude] (${point}),已自动纠正为 [longitude, latitude]。建议显式使用 [经度, 纬度] 格式以遵循 GeoJSON 标准。`);
|
|
20
|
+
return {
|
|
21
|
+
latitude: longitude,
|
|
22
|
+
longitude: latitude
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
longitude,
|
|
27
|
+
latitude,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// 对象格式直接返回
|
|
31
|
+
return point;
|
|
32
|
+
}
|
|
33
|
+
function normalizeLatLngList(points) {
|
|
34
|
+
if (!points || points.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
// 检查是否为嵌套数组 (检查第一项是否也是数组或对象,且不符合 LatLngPoint 的基本判断)
|
|
37
|
+
// 如果第一项是数组且长度 > 2,或者第一项的第一个元素也是数组/对象,则认为是嵌套数组
|
|
38
|
+
const firstItem = points[0];
|
|
39
|
+
if (Array.isArray(firstItem)) {
|
|
40
|
+
// 如果第一项是 [number, number],则这可能是一个一维坐标点数组 (LatLngPoint[])
|
|
41
|
+
// 除非所有元素都是数组且至少有一个子数组长度不等于2,或者我们明确知道这是嵌套的
|
|
42
|
+
// 为了支持 Polygon 的嵌套格式,我们需要递归处理
|
|
43
|
+
// 启发式判断:如果第一项是数组且它的第一个元素也是数组或对象,那么它一定是嵌套的
|
|
44
|
+
if (Array.isArray(firstItem[0]) || (typeof firstItem[0] === 'object' && firstItem[0] !== null && 'latitude' in firstItem[0])) {
|
|
45
|
+
return points.map(ring => ring.map(normalizeLatLng));
|
|
46
|
+
}
|
|
47
|
+
// 另一种情况:用户传入的是 [[lng, lat], [lng, lat]],这既可以看作 LatLngPoint[],
|
|
48
|
+
// 也可以看作 LatLngPoint[][] (只有一个外轮廓)。
|
|
49
|
+
// 在 Polygon 组件中,我们希望统一处理。
|
|
50
|
+
// 如果是 Polygon 传入的,我们希望保留嵌套结构。
|
|
51
|
+
// 但 normalizeLatLngList 是通用的。
|
|
52
|
+
// 改进逻辑:如果 data[0] 是一个点,我们把它当作一维数组处理。
|
|
53
|
+
// 如果 data[0] 不是一个点(即它是点的集合),我们当作二维处理。
|
|
54
|
+
if (isPoint(firstItem)) {
|
|
55
|
+
return points.map(normalizeLatLng);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return points.map(ring => ring.map(normalizeLatLng));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return points.map(normalizeLatLng);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 判断一个对象是否为坐标点 (LatLngPoint)
|
|
65
|
+
*/
|
|
66
|
+
function isPoint(item) {
|
|
67
|
+
if (!item || typeof item !== 'object')
|
|
68
|
+
return false;
|
|
69
|
+
// { latitude, longitude } 格式
|
|
70
|
+
if ('latitude' in item && 'longitude' in item)
|
|
71
|
+
return true;
|
|
72
|
+
// [longitude, latitude] 格式
|
|
73
|
+
if (Array.isArray(item) && item.length >= 2 && typeof item[0] === 'number' && typeof item[1] === 'number')
|
|
74
|
+
return true;
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 离线地图便捷 API
|
|
3
|
+
* 提供更友好的 API 接口和事件监听
|
|
4
|
+
*/
|
|
5
|
+
import type { OfflineMapInfo, OfflineMapDownloadConfig, OfflineMapDownloadEvent, OfflineMapCompleteEvent, OfflineMapErrorEvent, OfflineMapPausedEvent, OfflineMapCancelledEvent, OfflineMapStorageInfo } from '../types/offline.types';
|
|
6
|
+
/**
|
|
7
|
+
* 离线地图管理类
|
|
8
|
+
*/
|
|
9
|
+
export declare class OfflineMapManager {
|
|
10
|
+
/**
|
|
11
|
+
* 获取所有可下载的城市列表
|
|
12
|
+
*/
|
|
13
|
+
static getAvailableCities(): Promise<OfflineMapInfo[]>;
|
|
14
|
+
/**
|
|
15
|
+
* 获取所有省份列表
|
|
16
|
+
*/
|
|
17
|
+
static getAvailableProvinces(): Promise<OfflineMapInfo[]>;
|
|
18
|
+
/**
|
|
19
|
+
* 根据省份代码获取城市列表
|
|
20
|
+
*/
|
|
21
|
+
static getCitiesByProvince(provinceCode: string): Promise<OfflineMapInfo[]>;
|
|
22
|
+
/**
|
|
23
|
+
* 获取已下载的地图列表
|
|
24
|
+
*/
|
|
25
|
+
static getDownloadedMaps(): Promise<OfflineMapInfo[]>;
|
|
26
|
+
/**
|
|
27
|
+
* 开始下载离线地图
|
|
28
|
+
*/
|
|
29
|
+
static startDownload(config: OfflineMapDownloadConfig): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* 暂停下载
|
|
32
|
+
*/
|
|
33
|
+
static pauseDownload(cityCode: string): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 恢复下载
|
|
36
|
+
*/
|
|
37
|
+
static resumeDownload(cityCode: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* 取消下载
|
|
40
|
+
*/
|
|
41
|
+
static cancelDownload(cityCode: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* 删除离线地图
|
|
44
|
+
*/
|
|
45
|
+
static deleteMap(cityCode: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* 更新离线地图
|
|
48
|
+
*/
|
|
49
|
+
static updateMap(cityCode: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* 检查是否有可用更新
|
|
52
|
+
*/
|
|
53
|
+
static checkUpdate(cityCode: string): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* 检查地图是否已下载
|
|
56
|
+
*/
|
|
57
|
+
static isMapDownloaded(cityCode: string): Promise<boolean>;
|
|
58
|
+
/**
|
|
59
|
+
* 获取地图下载状态
|
|
60
|
+
*/
|
|
61
|
+
static getMapStatus(cityCode: string): Promise<OfflineMapInfo>;
|
|
62
|
+
/**
|
|
63
|
+
* 获取所有下载任务的总进度
|
|
64
|
+
*/
|
|
65
|
+
static getTotalProgress(): Promise<number>;
|
|
66
|
+
/**
|
|
67
|
+
* 获取当前正在下载的城市列表
|
|
68
|
+
*/
|
|
69
|
+
static getDownloadingCities(): Promise<string[]>;
|
|
70
|
+
/**
|
|
71
|
+
* 获取离线地图占用的存储空间(字节)
|
|
72
|
+
*/
|
|
73
|
+
static getStorageSize(): Promise<number>;
|
|
74
|
+
/**
|
|
75
|
+
* 获取详细的存储信息
|
|
76
|
+
*/
|
|
77
|
+
static getStorageInfo(): Promise<OfflineMapStorageInfo>;
|
|
78
|
+
/**
|
|
79
|
+
* 清理所有离线地图
|
|
80
|
+
*/
|
|
81
|
+
static clearAllMaps(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* 设置离线地图存储路径
|
|
84
|
+
*/
|
|
85
|
+
static setStoragePath(path: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* 获取离线地图存储路径
|
|
88
|
+
*/
|
|
89
|
+
static getStoragePath(): Promise<string>;
|
|
90
|
+
/**
|
|
91
|
+
* 批量下载地图
|
|
92
|
+
*/
|
|
93
|
+
static batchDownload(cityCodes: string[], allowCellular?: boolean): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* 批量删除地图
|
|
96
|
+
*/
|
|
97
|
+
static batchDelete(cityCodes: string[]): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* 批量更新地图
|
|
100
|
+
*/
|
|
101
|
+
static batchUpdate(cityCodes: string[]): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* 暂停所有下载任务
|
|
104
|
+
*/
|
|
105
|
+
static pauseAllDownloads(): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* 恢复所有下载任务
|
|
108
|
+
*/
|
|
109
|
+
static resumeAllDownloads(): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* 监听下载进度事件
|
|
112
|
+
*/
|
|
113
|
+
static addDownloadProgressListener(listener: (event: OfflineMapDownloadEvent) => void): {
|
|
114
|
+
remove: () => void;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* 监听下载完成事件
|
|
118
|
+
*/
|
|
119
|
+
static addDownloadCompleteListener(listener: (event: OfflineMapCompleteEvent) => void): {
|
|
120
|
+
remove: () => void;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* 监听下载错误事件
|
|
124
|
+
*/
|
|
125
|
+
static addDownloadErrorListener(listener: (event: OfflineMapErrorEvent) => void): {
|
|
126
|
+
remove: () => void;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* 监听下载暂停事件
|
|
130
|
+
*/
|
|
131
|
+
static addDownloadPausedListener(listener: (event: OfflineMapPausedEvent) => void): {
|
|
132
|
+
remove: () => void;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* 监听下载取消事件
|
|
136
|
+
*/
|
|
137
|
+
static addDownloadCancelledListener(listener: (event: OfflineMapCancelledEvent) => void): {
|
|
138
|
+
remove: () => void;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* 移除所有监听器
|
|
142
|
+
*/
|
|
143
|
+
static removeAllListeners(): void;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 默认导出管理类
|
|
147
|
+
*/
|
|
148
|
+
export default OfflineMapManager;
|