expo-gaode-map 2.2.24-next.1 → 2.2.24
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 +37 -0
- package/android/build.gradle +25 -1
- package/android/src/main/cpp/cluster_jni.cpp +178 -0
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapModule.kt +118 -0
- package/android/src/main/java/expo/modules/gaodemap/ExpoGaodeMapOfflineModule.kt +46 -4
- package/android/src/main/java/expo/modules/gaodemap/utils/GeometryUtils.kt +116 -0
- package/build/ExpoGaodeMapModule.d.ts.map +1 -1
- package/build/ExpoGaodeMapModule.js +193 -60
- package/build/ExpoGaodeMapModule.js.map +1 -1
- package/build/ExpoGaodeMapView.js.map +1 -1
- package/build/components/FoldableMapView.d.ts +2 -2
- package/build/components/FoldableMapView.d.ts.map +1 -1
- package/build/components/FoldableMapView.js +12 -12
- package/build/components/FoldableMapView.js.map +1 -1
- package/build/components/MapUI.js.map +1 -1
- package/build/types/native-module.types.d.ts +65 -1
- package/build/types/native-module.types.d.ts.map +1 -1
- package/build/types/native-module.types.js.map +1 -1
- package/build/types/overlays.types.d.ts +2 -2
- package/build/types/overlays.types.d.ts.map +1 -1
- package/build/types/overlays.types.js.map +1 -1
- package/build/utils/ErrorHandler.d.ts +3 -3
- package/build/utils/ErrorHandler.d.ts.map +1 -1
- package/build/utils/ErrorHandler.js +1 -1
- package/build/utils/ErrorHandler.js.map +1 -1
- package/build/utils/GeoUtils.d.ts +3 -1
- package/build/utils/GeoUtils.d.ts.map +1 -1
- package/build/utils/GeoUtils.js +12 -12
- package/build/utils/GeoUtils.js.map +1 -1
- package/ios/ExpoGaodeMapModule.swift +90 -16
- package/ios/overlays/ClusterView.swift +1 -1
- package/ios/overlays/MarkerView.swift +5 -3
- package/ios/utils/ClusterNative.h +35 -15
- package/ios/utils/ClusterNative.mm +105 -4
- package/ios/utils/ColorParser.swift +1 -1
- package/ios/utils/GeometryUtils.swift +1 -1
- package/package.json +1 -1
- package/plugin/build/withGaodeMap.d.ts +5 -0
- package/plugin/build/withGaodeMap.js +40 -3
- package/shared/cpp/GeometryEngine.cpp +95 -0
- package/shared/cpp/GeometryEngine.hpp +65 -0
package/README.md
CHANGED
|
@@ -162,9 +162,46 @@ try {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
|
+
### 5. 地图在模拟器上显示异常(可能会出现黑屏或闪退)
|
|
166
|
+
|
|
167
|
+
建议:
|
|
168
|
+
- 确保在真机上测试,模拟器可能不支持地图功能
|
|
169
|
+
- 检查是否正确配置了 API Key
|
|
165
170
|
|
|
166
171
|
**完整错误处理指南**:[ERROR_HANDLING_GUIDE.md](./ERROR_HANDLING_GUIDE.md)
|
|
167
172
|
|
|
173
|
+
### 6. Google Play 版本支持
|
|
174
|
+
|
|
175
|
+
如果你的应用需要上架 Google Play,需要使用高德地图 Google Play 版本的 SDK(通过了 Google Play 的合规审核)。
|
|
176
|
+
|
|
177
|
+
#### 步骤 1:下载 SDK
|
|
178
|
+
前往 [高德开放平台](https://lbs.amap.com/api/android-sdk/download) 下载包含 Google Play 版本的 SDK(通常是合包,包含地图、搜索、定位功能)。
|
|
179
|
+
|
|
180
|
+
#### 步骤 2:放入项目
|
|
181
|
+
将下载的 `.aar` 或 `.jar` 文件放入你的 Expo 项目根目录下的 `libs` 文件夹中(如果没有则创建),例如 `libs/AMap_3DMap_GooglePlay.aar`。
|
|
182
|
+
|
|
183
|
+
#### 步骤 3:配置插件
|
|
184
|
+
在 `app.json` 中配置 `customMapSdkPath`:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"expo": {
|
|
189
|
+
"plugins": [
|
|
190
|
+
[
|
|
191
|
+
"expo-gaode-map",
|
|
192
|
+
{
|
|
193
|
+
"androidKey": "your-android-key",
|
|
194
|
+
"iosKey": "your-ios-key",
|
|
195
|
+
"customMapSdkPath": "./libs/AMap_3DMap_GooglePlay.aar"
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
> **注意**:Google Play 版本的 SDK 通常是合包(包含地图+搜索+定位)。如果你的项目中引入了其他高德相关依赖(如 `expo-gaode-map-search`),可能会导致类冲突。插件会自动处理大部分冲突,但如果依然遇到 `Duplicate class` 错误,请检查是否引入了多余的依赖。
|
|
204
|
+
|
|
168
205
|
支持的错误类型:
|
|
169
206
|
- `SDK_NOT_INITIALIZED` - SDK 未初始化
|
|
170
207
|
- `INVALID_API_KEY` - API Key 配置错误
|
package/android/build.gradle
CHANGED
|
@@ -54,5 +54,29 @@ android {
|
|
|
54
54
|
|
|
55
55
|
dependencies {
|
|
56
56
|
// 高德地图 3D SDK
|
|
57
|
-
|
|
57
|
+
def customSdkPath = null
|
|
58
|
+
println "ExpoGaodeMap: Checking for custom SDK property in rootProject: ${rootProject.name}"
|
|
59
|
+
if (rootProject.hasProperty("EXPO_GAODE_MAP_CUSTOM_SDK_PATH")) {
|
|
60
|
+
customSdkPath = rootProject.property("EXPO_GAODE_MAP_CUSTOM_SDK_PATH")
|
|
61
|
+
println "ExpoGaodeMap: Found custom SDK path property: ${customSdkPath}"
|
|
62
|
+
} else {
|
|
63
|
+
println "ExpoGaodeMap: No custom SDK path property found."
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (customSdkPath) {
|
|
67
|
+
def sdkFile = rootProject.file(customSdkPath)
|
|
68
|
+
if (!sdkFile.exists()) {
|
|
69
|
+
// Try to find the file relative to the project root (parent of android folder)
|
|
70
|
+
sdkFile = new File(rootProject.projectDir.parentFile, customSdkPath)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (sdkFile.exists()) {
|
|
74
|
+
println "ExpoGaodeMap: Using custom Map SDK from ${sdkFile.absolutePath}"
|
|
75
|
+
implementation files(sdkFile)
|
|
76
|
+
} else {
|
|
77
|
+
throw new FileNotFoundException("ExpoGaodeMap: Could not find custom SDK at ${customSdkPath}. Please check your customMapSdkPath configuration.")
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
implementation ('com.amap.api:3dmap:latest.integration')
|
|
81
|
+
}
|
|
58
82
|
}
|
|
@@ -11,6 +11,7 @@ typedef void* jstring;
|
|
|
11
11
|
typedef double jdouble;
|
|
12
12
|
typedef int jint;
|
|
13
13
|
typedef int jsize;
|
|
14
|
+
typedef void* jobjectArray;
|
|
14
15
|
typedef unsigned char jboolean;
|
|
15
16
|
#ifndef JNI_TRUE
|
|
16
17
|
#define JNI_TRUE 1
|
|
@@ -232,6 +233,55 @@ Java_expo_modules_gaodemap_utils_GeometryUtils_nativeIsPointInPolygon(
|
|
|
232
233
|
#endif
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
extern "C" JNIEXPORT jint JNICALL
|
|
237
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeFindPointInPolygons(
|
|
238
|
+
JNIEnv* env,
|
|
239
|
+
jclass,
|
|
240
|
+
jdouble pointLat,
|
|
241
|
+
jdouble pointLon,
|
|
242
|
+
jobjectArray polygonsLat,
|
|
243
|
+
jobjectArray polygonsLon
|
|
244
|
+
) {
|
|
245
|
+
#if GAODE_HAVE_JNI
|
|
246
|
+
if (!polygonsLat || !polygonsLon) return -1;
|
|
247
|
+
|
|
248
|
+
const jsize polygonCount = env->GetArrayLength(polygonsLat);
|
|
249
|
+
if (polygonCount == 0) return -1;
|
|
250
|
+
|
|
251
|
+
std::vector<std::vector<gaodemap::GeoPoint>> polygons;
|
|
252
|
+
polygons.reserve(static_cast<size_t>(polygonCount));
|
|
253
|
+
|
|
254
|
+
for (jsize i = 0; i < polygonCount; ++i) {
|
|
255
|
+
jdoubleArray latArray = (jdoubleArray)env->GetObjectArrayElement(polygonsLat, i);
|
|
256
|
+
jdoubleArray lonArray = (jdoubleArray)env->GetObjectArrayElement(polygonsLon, i);
|
|
257
|
+
|
|
258
|
+
if (!latArray || !lonArray) continue;
|
|
259
|
+
|
|
260
|
+
const jsize pointCount = env->GetArrayLength(latArray);
|
|
261
|
+
jdouble* latValues = env->GetDoubleArrayElements(latArray, nullptr);
|
|
262
|
+
jdouble* lonValues = env->GetDoubleArrayElements(lonArray, nullptr);
|
|
263
|
+
|
|
264
|
+
std::vector<gaodemap::GeoPoint> polygon;
|
|
265
|
+
polygon.reserve(static_cast<size_t>(pointCount));
|
|
266
|
+
for (jsize j = 0; j < pointCount; ++j) {
|
|
267
|
+
polygon.push_back({latValues[j], lonValues[j]});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
polygons.push_back(std::move(polygon));
|
|
271
|
+
|
|
272
|
+
env->ReleaseDoubleArrayElements(latArray, latValues, JNI_ABORT);
|
|
273
|
+
env->ReleaseDoubleArrayElements(lonArray, lonValues, JNI_ABORT);
|
|
274
|
+
env->DeleteLocalRef(latArray);
|
|
275
|
+
env->DeleteLocalRef(lonArray);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return gaodemap::findPointInPolygons(pointLat, pointLon, polygons);
|
|
279
|
+
#else
|
|
280
|
+
(void)env; (void)pointLat; (void)pointLon; (void)polygonsLat; (void)polygonsLon;
|
|
281
|
+
return -1;
|
|
282
|
+
#endif
|
|
283
|
+
}
|
|
284
|
+
|
|
235
285
|
extern "C" JNIEXPORT jdouble JNICALL
|
|
236
286
|
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeCalculatePolygonArea(
|
|
237
287
|
JNIEnv* env,
|
|
@@ -668,3 +718,131 @@ Java_expo_modules_gaodemap_utils_GeometryUtils_nativeParsePolyline(
|
|
|
668
718
|
return nullptr;
|
|
669
719
|
#endif
|
|
670
720
|
}
|
|
721
|
+
|
|
722
|
+
extern "C" JNIEXPORT jintArray JNICALL
|
|
723
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeLatLngToTile(
|
|
724
|
+
JNIEnv* env,
|
|
725
|
+
jclass,
|
|
726
|
+
jdouble lat,
|
|
727
|
+
jdouble lon,
|
|
728
|
+
jint zoom
|
|
729
|
+
) {
|
|
730
|
+
#if GAODE_HAVE_JNI
|
|
731
|
+
gaodemap::TileResult result = gaodemap::latLngToTile(lat, lon, zoom);
|
|
732
|
+
jintArray array = env->NewIntArray(3);
|
|
733
|
+
jint buffer[3] = {result.x, result.y, result.z};
|
|
734
|
+
env->SetIntArrayRegion(array, 0, 3, buffer);
|
|
735
|
+
return array;
|
|
736
|
+
#else
|
|
737
|
+
(void)env; (void)lat; (void)lon; (void)zoom;
|
|
738
|
+
return nullptr;
|
|
739
|
+
#endif
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
extern "C" JNIEXPORT jdoubleArray JNICALL
|
|
743
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeTileToLatLng(
|
|
744
|
+
JNIEnv* env,
|
|
745
|
+
jclass,
|
|
746
|
+
jint x,
|
|
747
|
+
jint y,
|
|
748
|
+
jint zoom
|
|
749
|
+
) {
|
|
750
|
+
#if GAODE_HAVE_JNI
|
|
751
|
+
gaodemap::GeoPoint result = gaodemap::tileToLatLng(x, y, zoom);
|
|
752
|
+
jdoubleArray array = env->NewDoubleArray(2);
|
|
753
|
+
jdouble buffer[2] = {result.lat, result.lon};
|
|
754
|
+
env->SetDoubleArrayRegion(array, 0, 2, buffer);
|
|
755
|
+
return array;
|
|
756
|
+
#else
|
|
757
|
+
(void)env; (void)x; (void)y; (void)zoom;
|
|
758
|
+
return nullptr;
|
|
759
|
+
#endif
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
extern "C" JNIEXPORT jdoubleArray JNICALL
|
|
763
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeLatLngToPixel(
|
|
764
|
+
JNIEnv* env,
|
|
765
|
+
jclass,
|
|
766
|
+
jdouble lat,
|
|
767
|
+
jdouble lon,
|
|
768
|
+
jint zoom
|
|
769
|
+
) {
|
|
770
|
+
#if GAODE_HAVE_JNI
|
|
771
|
+
gaodemap::PixelResult result = gaodemap::latLngToPixel(lat, lon, zoom);
|
|
772
|
+
jdoubleArray array = env->NewDoubleArray(2);
|
|
773
|
+
jdouble buffer[2] = {result.x, result.y};
|
|
774
|
+
env->SetDoubleArrayRegion(array, 0, 2, buffer);
|
|
775
|
+
return array;
|
|
776
|
+
#else
|
|
777
|
+
(void)env; (void)lat; (void)lon; (void)zoom;
|
|
778
|
+
return nullptr;
|
|
779
|
+
#endif
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
extern "C" JNIEXPORT jdoubleArray JNICALL
|
|
783
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativePixelToLatLng(
|
|
784
|
+
JNIEnv* env,
|
|
785
|
+
jclass,
|
|
786
|
+
jdouble x,
|
|
787
|
+
jdouble y,
|
|
788
|
+
jint zoom
|
|
789
|
+
) {
|
|
790
|
+
#if GAODE_HAVE_JNI
|
|
791
|
+
gaodemap::GeoPoint result = gaodemap::pixelToLatLng(x, y, zoom);
|
|
792
|
+
jdoubleArray array = env->NewDoubleArray(2);
|
|
793
|
+
jdouble buffer[2] = {result.lat, result.lon};
|
|
794
|
+
env->SetDoubleArrayRegion(array, 0, 2, buffer);
|
|
795
|
+
return array;
|
|
796
|
+
#else
|
|
797
|
+
(void)env; (void)x; (void)y; (void)zoom;
|
|
798
|
+
return nullptr;
|
|
799
|
+
#endif
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
extern "C" JNIEXPORT jdoubleArray JNICALL
|
|
803
|
+
Java_expo_modules_gaodemap_utils_GeometryUtils_nativeGenerateHeatmapGrid(
|
|
804
|
+
JNIEnv* env,
|
|
805
|
+
jclass,
|
|
806
|
+
jdoubleArray latitudes,
|
|
807
|
+
jdoubleArray longitudes,
|
|
808
|
+
jdoubleArray weights,
|
|
809
|
+
jdouble gridSizeMeters
|
|
810
|
+
) {
|
|
811
|
+
#if GAODE_HAVE_JNI
|
|
812
|
+
if (!latitudes || !longitudes || !weights) return nullptr;
|
|
813
|
+
const jsize count = env->GetArrayLength(latitudes);
|
|
814
|
+
if (count == 0 || count != env->GetArrayLength(longitudes) || count != env->GetArrayLength(weights)) {
|
|
815
|
+
return nullptr;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
jdouble* latVals = env->GetDoubleArrayElements(latitudes, nullptr);
|
|
819
|
+
jdouble* lonVals = env->GetDoubleArrayElements(longitudes, nullptr);
|
|
820
|
+
jdouble* weightVals = env->GetDoubleArrayElements(weights, nullptr);
|
|
821
|
+
|
|
822
|
+
std::vector<gaodemap::HeatmapPoint> points;
|
|
823
|
+
points.reserve(count);
|
|
824
|
+
for (jsize i = 0; i < count; ++i) {
|
|
825
|
+
points.push_back({latVals[i], lonVals[i], weightVals[i]});
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
env->ReleaseDoubleArrayElements(latitudes, latVals, JNI_ABORT);
|
|
829
|
+
env->ReleaseDoubleArrayElements(longitudes, lonVals, JNI_ABORT);
|
|
830
|
+
env->ReleaseDoubleArrayElements(weights, weightVals, JNI_ABORT);
|
|
831
|
+
|
|
832
|
+
auto cells = gaodemap::generateHeatmapGrid(points, gridSizeMeters);
|
|
833
|
+
|
|
834
|
+
jdoubleArray result = env->NewDoubleArray(static_cast<jsize>(cells.size() * 3));
|
|
835
|
+
std::vector<double> buffer;
|
|
836
|
+
buffer.reserve(cells.size() * 3);
|
|
837
|
+
for (const auto& c : cells) {
|
|
838
|
+
buffer.push_back(c.lat);
|
|
839
|
+
buffer.push_back(c.lon);
|
|
840
|
+
buffer.push_back(c.intensity);
|
|
841
|
+
}
|
|
842
|
+
env->SetDoubleArrayRegion(result, 0, static_cast<jsize>(buffer.size()), buffer.data());
|
|
843
|
+
return result;
|
|
844
|
+
#else
|
|
845
|
+
(void)env; (void)latitudes; (void)longitudes; (void)weights; (void)gridSizeMeters;
|
|
846
|
+
return nullptr;
|
|
847
|
+
#endif
|
|
848
|
+
}
|
|
@@ -79,6 +79,9 @@ class ExpoGaodeMapModule : Module() {
|
|
|
79
79
|
SDKInitializer.initSDK(appContext.reactContext!!, androidKey)
|
|
80
80
|
getLocationManager() // 初始化定位管理器
|
|
81
81
|
|
|
82
|
+
// 打印当前 SDK 版本信息,便于验证依赖来源
|
|
83
|
+
android.util.Log.i("ExpoGaodeMap", "✅ SDK 初始化完成 - Version: ${MapsInitializer.getVersion()}")
|
|
84
|
+
|
|
82
85
|
// 初始化成功后自动触发一次预加载
|
|
83
86
|
MapPreloadManager.startPreload(appContext.reactContext!!, poolSize = 1)
|
|
84
87
|
} catch (e: SecurityException) {
|
|
@@ -451,6 +454,121 @@ class ExpoGaodeMapModule : Module() {
|
|
|
451
454
|
}
|
|
452
455
|
}
|
|
453
456
|
|
|
457
|
+
/**
|
|
458
|
+
* 经纬度转瓦片坐标
|
|
459
|
+
* @param coordinate 坐标
|
|
460
|
+
* @param zoom 缩放级别
|
|
461
|
+
* @return 瓦片坐标 [x, y]
|
|
462
|
+
*/
|
|
463
|
+
Function("latLngToTile") { coordinate: Map<String, Any>?, zoom: Int ->
|
|
464
|
+
val latLng = LatLngParser.parseLatLng(coordinate)
|
|
465
|
+
if (latLng != null) {
|
|
466
|
+
val result = GeometryUtils.latLngToTile(latLng, zoom)
|
|
467
|
+
if (result != null && result.size >= 2) {
|
|
468
|
+
mapOf("x" to result[0], "y" to result[1])
|
|
469
|
+
} else {
|
|
470
|
+
null
|
|
471
|
+
}
|
|
472
|
+
} else {
|
|
473
|
+
null
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* 瓦片坐标转经纬度
|
|
479
|
+
* @param tile 瓦片坐标 {x, y, z}
|
|
480
|
+
* @return 坐标
|
|
481
|
+
*/
|
|
482
|
+
Function("tileToLatLng") { tile: Map<String, Any>? ->
|
|
483
|
+
val x = (tile?.get("x") as? Number)?.toInt() ?: 0
|
|
484
|
+
val y = (tile?.get("y") as? Number)?.toInt() ?: 0
|
|
485
|
+
val zoom = (tile?.get("z") as? Number)?.toInt() ?: (tile?.get("zoom") as? Number)?.toInt() ?: 0
|
|
486
|
+
val result = GeometryUtils.tileToLatLng(x, y, zoom)
|
|
487
|
+
result?.let {
|
|
488
|
+
mapOf("latitude" to it.latitude, "longitude" to it.longitude)
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 经纬度转像素坐标
|
|
494
|
+
* @param coordinate 坐标
|
|
495
|
+
* @param zoom 缩放级别
|
|
496
|
+
* @return 像素坐标 [x, y]
|
|
497
|
+
*/
|
|
498
|
+
Function("latLngToPixel") { coordinate: Map<String, Any>?, zoom: Int ->
|
|
499
|
+
val latLng = LatLngParser.parseLatLng(coordinate)
|
|
500
|
+
if (latLng != null) {
|
|
501
|
+
val result = GeometryUtils.latLngToPixel(latLng, zoom)
|
|
502
|
+
if (result != null && result.size >= 2) {
|
|
503
|
+
mapOf("x" to result[0], "y" to result[1])
|
|
504
|
+
} else {
|
|
505
|
+
null
|
|
506
|
+
}
|
|
507
|
+
} else {
|
|
508
|
+
null
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* 像素坐标转经纬度
|
|
514
|
+
* @param pixel 像素坐标 {x, y}
|
|
515
|
+
* @param zoom 缩放级别
|
|
516
|
+
* @return 坐标
|
|
517
|
+
*/
|
|
518
|
+
Function("pixelToLatLng") { pixel: Map<String, Any>?, zoom: Int ->
|
|
519
|
+
val x = (pixel?.get("x") as? Number)?.toDouble() ?: 0.0
|
|
520
|
+
val y = (pixel?.get("y") as? Number)?.toDouble() ?: 0.0
|
|
521
|
+
val result = GeometryUtils.pixelToLatLng(x, y, zoom)
|
|
522
|
+
result?.let {
|
|
523
|
+
mapOf("latitude" to it.latitude, "longitude" to it.longitude)
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* 批量判断点在哪个多边形内
|
|
529
|
+
* @param point 待判断点
|
|
530
|
+
* @param polygons 多边形列表
|
|
531
|
+
* @return 所在多边形的索引,不在任何多边形内返回 -1
|
|
532
|
+
*/
|
|
533
|
+
Function("findPointInPolygons") { point: Map<String, Any>?, polygons: List<List<Any>>? ->
|
|
534
|
+
val pt = LatLngParser.parseLatLng(point)
|
|
535
|
+
val polys = polygons?.map { LatLngParser.parseLatLngList(it) }
|
|
536
|
+
if (pt != null && polys != null) {
|
|
537
|
+
GeometryUtils.findPointInPolygons(pt, polys)
|
|
538
|
+
} else {
|
|
539
|
+
-1
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* 生成网格聚合数据 (常用于展示网格聚合图或大规模点数据处理)
|
|
545
|
+
* @param points 包含经纬度和权重的点数组
|
|
546
|
+
* @param gridSizeMeters 网格大小(米)
|
|
547
|
+
*/
|
|
548
|
+
Function("generateHeatmapGrid") { points: List<Map<String, Any>>?, gridSizeMeters: Double ->
|
|
549
|
+
if (points == null || points.isEmpty()) return@Function emptyList<Map<String, Any>>()
|
|
550
|
+
|
|
551
|
+
val count = points.size
|
|
552
|
+
val latitudes = DoubleArray(count)
|
|
553
|
+
val longitudes = DoubleArray(count)
|
|
554
|
+
val weights = DoubleArray(count)
|
|
555
|
+
|
|
556
|
+
points.forEachIndexed { index, map ->
|
|
557
|
+
latitudes[index] = (map["latitude"] as? Number)?.toDouble() ?: 0.0
|
|
558
|
+
longitudes[index] = (map["longitude"] as? Number)?.toDouble() ?: 0.0
|
|
559
|
+
weights[index] = (map["weight"] as? Number)?.toDouble() ?: 1.0
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
val result = GeometryUtils.generateHeatmapGrid(latitudes, longitudes, weights, gridSizeMeters)
|
|
563
|
+
result.map {
|
|
564
|
+
mapOf(
|
|
565
|
+
"latitude" to it.latitude,
|
|
566
|
+
"longitude" to it.longitude,
|
|
567
|
+
"intensity" to it.intensity
|
|
568
|
+
)
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
454
572
|
// ==================== 定位配置 ====================
|
|
455
573
|
|
|
456
574
|
/**
|
|
@@ -446,9 +446,9 @@ class ExpoGaodeMapOfflineModule : Module() {
|
|
|
446
446
|
putString("cityName", city.city)
|
|
447
447
|
putLong("size", city.size)
|
|
448
448
|
putString("status", status)
|
|
449
|
-
putInt("progress", city
|
|
449
|
+
putInt("progress", getDownloadProgress(city))
|
|
450
450
|
putString("version", city.version)
|
|
451
|
-
putLong("downloadedSize", (city.size * city
|
|
451
|
+
putLong("downloadedSize", (city.size * getDownloadProgress(city) / 100))
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
|
|
@@ -461,12 +461,54 @@ class ExpoGaodeMapOfflineModule : Module() {
|
|
|
461
461
|
putString("cityName", province.provinceName)
|
|
462
462
|
putLong("size", province.size)
|
|
463
463
|
putString("status", getStatusString(province.state))
|
|
464
|
-
putInt("progress", province
|
|
464
|
+
putInt("progress", getDownloadProgress(province))
|
|
465
465
|
putString("version", province.version)
|
|
466
466
|
putString("provinceName", province.provinceName)
|
|
467
467
|
putString("provinceCode", province.provinceCode)
|
|
468
468
|
}
|
|
469
469
|
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* 兼容获取 START_DOWNLOAD_FAILED 状态码
|
|
473
|
+
* 国内版拼写为 START_DOWNLOAD_FAILD,Google Play 版修正为 START_DOWNLOAD_FAILED
|
|
474
|
+
*/
|
|
475
|
+
private val startDownloadFailedCode: Int by lazy {
|
|
476
|
+
try {
|
|
477
|
+
OfflineMapStatus::class.java.getField("START_DOWNLOAD_FAILED").getInt(null)
|
|
478
|
+
} catch (e: Exception) {
|
|
479
|
+
try {
|
|
480
|
+
OfflineMapStatus::class.java.getField("START_DOWNLOAD_FAILD").getInt(null)
|
|
481
|
+
} catch (e2: Exception) {
|
|
482
|
+
-1
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* 兼容获取下载进度
|
|
489
|
+
* Google Play 版本 SDK 可能修复了 getcompleteCode 的命名或使用了不同的 API
|
|
490
|
+
*/
|
|
491
|
+
private fun getDownloadProgress(obj: Any): Int {
|
|
492
|
+
try {
|
|
493
|
+
// 尝试标准版的命名 (getcompleteCode)
|
|
494
|
+
val method = obj.javaClass.getMethod("getcompleteCode")
|
|
495
|
+
return method.invoke(obj) as Int
|
|
496
|
+
} catch (e: Exception) {
|
|
497
|
+
try {
|
|
498
|
+
// 尝试修正后的命名 (getCompleteCode) - Google Play 版本可能使用此命名
|
|
499
|
+
val method = obj.javaClass.getMethod("getCompleteCode")
|
|
500
|
+
return method.invoke(obj) as Int
|
|
501
|
+
} catch (e2: Exception) {
|
|
502
|
+
// 如果都失败了,尝试直接访问 completeCode 字段
|
|
503
|
+
try {
|
|
504
|
+
val field = obj.javaClass.getField("completeCode")
|
|
505
|
+
return field.getInt(obj)
|
|
506
|
+
} catch (e3: Exception) {
|
|
507
|
+
return 0
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
470
512
|
|
|
471
513
|
/**
|
|
472
514
|
* 获取状态字符串
|
|
@@ -484,7 +526,7 @@ class ExpoGaodeMapOfflineModule : Module() {
|
|
|
484
526
|
OfflineMapStatus.EXCEPTION_NETWORK_LOADING -> "downloading" // 网络问题,可继续
|
|
485
527
|
OfflineMapStatus.EXCEPTION_AMAP -> "failed" // 认证异常
|
|
486
528
|
OfflineMapStatus.EXCEPTION_SDCARD -> "failed" // SD卡异常
|
|
487
|
-
|
|
529
|
+
startDownloadFailedCode -> "failed" // 兼容两种拼写的开始下载失败
|
|
488
530
|
OfflineMapStatus.CHECKUPDATES -> "not_downloaded"
|
|
489
531
|
OfflineMapStatus.NEW_VERSION -> "not_downloaded"
|
|
490
532
|
else -> "not_downloaded"
|
|
@@ -89,6 +89,44 @@ object GeometryUtils {
|
|
|
89
89
|
precision: Int
|
|
90
90
|
): String
|
|
91
91
|
|
|
92
|
+
private external fun nativeLatLngToTile(
|
|
93
|
+
lat: Double,
|
|
94
|
+
lon: Double,
|
|
95
|
+
zoom: Int
|
|
96
|
+
): IntArray
|
|
97
|
+
|
|
98
|
+
private external fun nativeTileToLatLng(
|
|
99
|
+
x: Int,
|
|
100
|
+
y: Int,
|
|
101
|
+
zoom: Int
|
|
102
|
+
): DoubleArray
|
|
103
|
+
|
|
104
|
+
private external fun nativeLatLngToPixel(
|
|
105
|
+
lat: Double,
|
|
106
|
+
lon: Double,
|
|
107
|
+
zoom: Int
|
|
108
|
+
): DoubleArray
|
|
109
|
+
|
|
110
|
+
private external fun nativePixelToLatLng(
|
|
111
|
+
x: Double,
|
|
112
|
+
y: Double,
|
|
113
|
+
zoom: Int
|
|
114
|
+
): DoubleArray
|
|
115
|
+
|
|
116
|
+
private external fun nativeFindPointInPolygons(
|
|
117
|
+
pointLat: Double,
|
|
118
|
+
pointLon: Double,
|
|
119
|
+
polygons: Array<DoubleArray>,
|
|
120
|
+
polygonsLon: Array<DoubleArray>
|
|
121
|
+
): Int
|
|
122
|
+
|
|
123
|
+
private external fun nativeGenerateHeatmapGrid(
|
|
124
|
+
latitudes: DoubleArray,
|
|
125
|
+
longitudes: DoubleArray,
|
|
126
|
+
weights: DoubleArray,
|
|
127
|
+
gridSizeMeters: Double
|
|
128
|
+
): DoubleArray
|
|
129
|
+
|
|
92
130
|
/**
|
|
93
131
|
* 判断点是否在圆内
|
|
94
132
|
* @param point 要判断的点
|
|
@@ -396,4 +434,82 @@ object GeometryUtils {
|
|
|
396
434
|
private external fun nativeParsePolyline(
|
|
397
435
|
polylineStr: String
|
|
398
436
|
): DoubleArray?
|
|
437
|
+
|
|
438
|
+
fun latLngToTile(latLng: LatLng, zoom: Int): IntArray? {
|
|
439
|
+
return try {
|
|
440
|
+
nativeLatLngToTile(latLng.latitude, latLng.longitude, zoom)
|
|
441
|
+
} catch (_: Throwable) {
|
|
442
|
+
null
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
fun tileToLatLng(x: Int, y: Int, zoom: Int): LatLng? {
|
|
447
|
+
return try {
|
|
448
|
+
val result = nativeTileToLatLng(x, y, zoom)
|
|
449
|
+
if (result != null && result.size >= 2) {
|
|
450
|
+
LatLng(result[0], result[1])
|
|
451
|
+
} else {
|
|
452
|
+
null
|
|
453
|
+
}
|
|
454
|
+
} catch (_: Throwable) {
|
|
455
|
+
null
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
fun latLngToPixel(latLng: LatLng, zoom: Int): DoubleArray? {
|
|
460
|
+
return try {
|
|
461
|
+
nativeLatLngToPixel(latLng.latitude, latLng.longitude, zoom)
|
|
462
|
+
} catch (_: Throwable) {
|
|
463
|
+
null
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
fun pixelToLatLng(x: Double, y: Double, zoom: Int): LatLng? {
|
|
468
|
+
return try {
|
|
469
|
+
val result = nativePixelToLatLng(x, y, zoom)
|
|
470
|
+
if (result != null && result.size >= 2) {
|
|
471
|
+
LatLng(result[0], result[1])
|
|
472
|
+
} else {
|
|
473
|
+
null
|
|
474
|
+
}
|
|
475
|
+
} catch (_: Throwable) {
|
|
476
|
+
null
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
fun findPointInPolygons(point: LatLng, polygons: List<List<LatLng>>): Int {
|
|
481
|
+
if (polygons.isEmpty()) return -1
|
|
482
|
+
return try {
|
|
483
|
+
val polygonsLat = Array(polygons.size) { i ->
|
|
484
|
+
DoubleArray(polygons[i].size) { j -> polygons[i][j].latitude }
|
|
485
|
+
}
|
|
486
|
+
val polygonsLon = Array(polygons.size) { i ->
|
|
487
|
+
DoubleArray(polygons[i].size) { j -> polygons[i][j].longitude }
|
|
488
|
+
}
|
|
489
|
+
nativeFindPointInPolygons(point.latitude, point.longitude, polygonsLat, polygonsLon)
|
|
490
|
+
} catch (_: Throwable) {
|
|
491
|
+
-1
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
data class HeatmapGridCell(val latitude: Double, val longitude: Double, val intensity: Double)
|
|
496
|
+
|
|
497
|
+
fun generateHeatmapGrid(
|
|
498
|
+
latitudes: DoubleArray,
|
|
499
|
+
longitudes: DoubleArray,
|
|
500
|
+
weights: DoubleArray,
|
|
501
|
+
gridSizeMeters: Double
|
|
502
|
+
): List<HeatmapGridCell> {
|
|
503
|
+
if (latitudes.isEmpty() || latitudes.size != longitudes.size || latitudes.size != weights.size) return emptyList()
|
|
504
|
+
return try {
|
|
505
|
+
val result = nativeGenerateHeatmapGrid(latitudes, longitudes, weights, gridSizeMeters)
|
|
506
|
+
val cells = mutableListOf<HeatmapGridCell>()
|
|
507
|
+
for (i in result.indices step 3) {
|
|
508
|
+
cells.add(HeatmapGridCell(result[i], result[i+1], result[i+2]))
|
|
509
|
+
}
|
|
510
|
+
cells
|
|
511
|
+
} catch (_: Throwable) {
|
|
512
|
+
emptyList()
|
|
513
|
+
}
|
|
514
|
+
}
|
|
399
515
|
}
|
|
@@ -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,EAAE,SAAS,EAAoB,MAAM,sBAAsB,CAAC;
|
|
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,EAAE,SAAS,EAAoB,MAAM,sBAAsB,CAAC;AAopBnE;;EAEE;AACF,wBAAgB,YAAY,IAAI,SAAS,GAAG,IAAI,CAE/C;AAED;;EAEE;AACF,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;wBAE0D,kBAAkB;AAA7E,wBAA8E"}
|