expo-gaode-map-navigation 1.1.5 → 1.1.6

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 (146) hide show
  1. package/README.md +213 -73
  2. package/android/build.gradle +10 -0
  3. package/android/src/main/cpp/CMakeLists.txt +24 -0
  4. package/android/src/main/cpp/cluster_jni.cpp +848 -0
  5. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapModule.kt +616 -92
  6. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapOfflineModule.kt +493 -0
  7. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapView.kt +230 -14
  8. package/android/src/main/java/expo/modules/gaodemap/map/ExpoGaodeMapViewModule.kt +37 -27
  9. package/android/src/main/java/expo/modules/gaodemap/map/MapPreloadManager.kt +494 -0
  10. package/android/src/main/java/expo/modules/gaodemap/map/companion/BitmapDescriptorCache.kt +30 -0
  11. package/android/src/main/java/expo/modules/gaodemap/map/companion/IconBitmapCache.kt +37 -0
  12. package/android/src/main/java/expo/modules/gaodemap/map/managers/UIManager.kt +76 -0
  13. package/android/src/main/java/expo/modules/gaodemap/map/modules/LocationManager.kt +15 -3
  14. package/android/src/main/java/expo/modules/gaodemap/map/modules/SDKInitializer.kt +4 -59
  15. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleView.kt +9 -12
  16. package/android/src/main/java/expo/modules/gaodemap/map/overlays/CircleViewModule.kt +5 -6
  17. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterView.kt +539 -66
  18. package/android/src/main/java/expo/modules/gaodemap/map/overlays/ClusterViewModule.kt +17 -1
  19. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapView.kt +165 -33
  20. package/android/src/main/java/expo/modules/gaodemap/map/overlays/HeatMapViewModule.kt +15 -3
  21. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerView.kt +1249 -672
  22. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MarkerViewModule.kt +40 -17
  23. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointView.kt +177 -22
  24. package/android/src/main/java/expo/modules/gaodemap/map/overlays/MultiPointViewModule.kt +11 -3
  25. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonView.kt +57 -14
  26. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolygonViewModule.kt +9 -5
  27. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineView.kt +90 -63
  28. package/android/src/main/java/expo/modules/gaodemap/map/overlays/PolylineViewModule.kt +7 -3
  29. package/android/src/main/java/expo/modules/gaodemap/map/services/LocationForegroundService.kt +3 -2
  30. package/android/src/main/java/expo/modules/gaodemap/map/utils/BitmapDescriptorCache.kt +20 -0
  31. package/android/src/main/java/expo/modules/gaodemap/map/utils/ClusterNative.kt +13 -0
  32. package/android/src/main/java/expo/modules/gaodemap/map/utils/ColorParser.kt +20 -0
  33. package/android/src/main/java/expo/modules/gaodemap/map/utils/GeometryUtils.kt +515 -0
  34. package/android/src/main/java/expo/modules/gaodemap/map/utils/LatLngParser.kt +91 -0
  35. package/android/src/main/java/expo/modules/gaodemap/map/utils/PermissionHelper.kt +248 -0
  36. package/build/ExpoGaodeMapNaviView.d.ts +7 -7
  37. package/build/ExpoGaodeMapNaviView.js +10 -11
  38. package/build/ExpoGaodeMapNavigationModule.d.ts +2 -1
  39. package/build/index.d.ts +35 -33
  40. package/build/index.js +70 -106
  41. package/build/map/ExpoGaodeMapModule.d.ts +2 -201
  42. package/build/map/ExpoGaodeMapModule.js +586 -18
  43. package/build/map/ExpoGaodeMapOfflineModule.d.ts +139 -0
  44. package/build/map/ExpoGaodeMapOfflineModule.js +8 -0
  45. package/build/map/ExpoGaodeMapView.js +66 -58
  46. package/build/map/components/FoldableMapView.d.ts +38 -0
  47. package/build/map/components/FoldableMapView.js +209 -0
  48. package/build/map/components/MapContext.d.ts +12 -0
  49. package/build/map/components/MapContext.js +54 -0
  50. package/build/map/components/MapUI.d.ts +18 -0
  51. package/build/map/components/MapUI.js +29 -0
  52. package/build/map/components/overlays/Circle.js +34 -3
  53. package/build/map/components/overlays/Cluster.d.ts +3 -1
  54. package/build/map/components/overlays/Cluster.js +31 -2
  55. package/build/map/components/overlays/HeatMap.d.ts +3 -1
  56. package/build/map/components/overlays/HeatMap.js +33 -3
  57. package/build/map/components/overlays/Marker.d.ts +1 -1
  58. package/build/map/components/overlays/Marker.js +37 -32
  59. package/build/map/components/overlays/MultiPoint.js +1 -1
  60. package/build/map/components/overlays/Polygon.js +30 -3
  61. package/build/map/components/overlays/Polyline.js +36 -3
  62. package/build/map/index.d.ts +25 -5
  63. package/build/map/index.js +59 -18
  64. package/build/map/types/common.types.d.ts +40 -0
  65. package/build/map/types/common.types.js +0 -4
  66. package/build/map/types/index.d.ts +3 -2
  67. package/build/map/types/map-view.types.d.ts +108 -3
  68. package/build/map/types/native-module.types.d.ts +363 -0
  69. package/build/map/types/native-module.types.js +5 -0
  70. package/build/map/types/offline.types.d.ts +132 -0
  71. package/build/map/types/offline.types.js +5 -0
  72. package/build/map/types/overlays.types.d.ts +137 -24
  73. package/build/map/utils/ErrorHandler.d.ts +110 -0
  74. package/build/map/utils/ErrorHandler.js +421 -0
  75. package/build/map/utils/GeoUtils.d.ts +20 -0
  76. package/build/map/utils/GeoUtils.js +76 -0
  77. package/build/map/utils/OfflineMapManager.d.ts +148 -0
  78. package/build/map/utils/OfflineMapManager.js +217 -0
  79. package/build/map/utils/PermissionUtils.d.ts +91 -0
  80. package/build/map/utils/PermissionUtils.js +255 -0
  81. package/build/map/utils/PlatformDetector.d.ts +102 -0
  82. package/build/map/utils/PlatformDetector.js +186 -0
  83. package/build/types/index.d.ts +1 -0
  84. package/build/types/index.js +1 -0
  85. package/build/types/native-module.types.d.ts +69 -0
  86. package/build/types/native-module.types.js +2 -0
  87. package/build/types/naviview.types.d.ts +1 -1
  88. package/expo-module.config.json +12 -10
  89. package/ios/ExpoGaodeMapNavigation.podspec +9 -0
  90. package/ios/map/ExpoGaodeMapModule.swift +485 -75
  91. package/ios/map/ExpoGaodeMapOfflineModule.swift +479 -0
  92. package/ios/map/ExpoGaodeMapView.swift +611 -62
  93. package/ios/map/ExpoGaodeMapViewModule.swift +48 -26
  94. package/ios/map/MapPreloadManager.swift +348 -0
  95. package/ios/map/cpp/ClusterEngine.cpp +110 -0
  96. package/ios/map/cpp/ClusterEngine.hpp +20 -0
  97. package/ios/map/cpp/ColorParser.cpp +135 -0
  98. package/ios/map/cpp/ColorParser.hpp +14 -0
  99. package/ios/map/cpp/GeometryEngine.cpp +574 -0
  100. package/ios/map/cpp/GeometryEngine.hpp +159 -0
  101. package/ios/map/cpp/QuadTree.cpp +92 -0
  102. package/ios/map/cpp/QuadTree.hpp +42 -0
  103. package/ios/map/cpp/README.md +55 -0
  104. package/ios/map/managers/UIManager.swift +72 -1
  105. package/ios/map/modules/LocationManager.swift +123 -166
  106. package/ios/map/overlays/CircleView.swift +16 -32
  107. package/ios/map/overlays/CircleViewModule.swift +12 -12
  108. package/ios/map/overlays/ClusterAnnotation.swift +32 -0
  109. package/ios/map/overlays/ClusterView.swift +331 -45
  110. package/ios/map/overlays/ClusterViewModule.swift +20 -6
  111. package/ios/map/overlays/HeatMapView.swift +135 -32
  112. package/ios/map/overlays/HeatMapViewModule.swift +20 -8
  113. package/ios/map/overlays/MarkerView.swift +613 -130
  114. package/ios/map/overlays/MarkerViewModule.swift +38 -18
  115. package/ios/map/overlays/MultiPointView.swift +168 -10
  116. package/ios/map/overlays/MultiPointViewModule.swift +27 -5
  117. package/ios/map/overlays/PolygonView.swift +62 -23
  118. package/ios/map/overlays/PolygonViewModule.swift +18 -12
  119. package/ios/map/overlays/PolylineView.swift +21 -13
  120. package/ios/map/overlays/PolylineViewModule.swift +18 -12
  121. package/ios/map/utils/ClusterNative.h +96 -0
  122. package/ios/map/utils/ClusterNative.mm +377 -0
  123. package/ios/map/utils/ColorParser.swift +12 -1
  124. package/ios/map/utils/CppBridging.mm +13 -0
  125. package/ios/map/utils/GeometryUtils.swift +34 -0
  126. package/ios/map/utils/LatLngParser.swift +87 -0
  127. package/ios/map/utils/PermissionManager.swift +135 -6
  128. package/package.json +3 -2
  129. package/shared/cpp/ClusterEngine.cpp +110 -0
  130. package/shared/cpp/ClusterEngine.hpp +20 -0
  131. package/shared/cpp/ColorParser.cpp +135 -0
  132. package/shared/cpp/ColorParser.hpp +14 -0
  133. package/shared/cpp/GeometryEngine.cpp +574 -0
  134. package/shared/cpp/GeometryEngine.hpp +159 -0
  135. package/shared/cpp/QuadTree.cpp +92 -0
  136. package/shared/cpp/QuadTree.hpp +42 -0
  137. package/shared/cpp/README.md +55 -0
  138. package/shared/cpp/tests/benchmark_js.js +41 -0
  139. package/shared/cpp/tests/run.sh +17 -0
  140. package/shared/cpp/tests/test_main.cpp +276 -0
  141. package/build/map/ExpoGaodeMap.types.d.ts +0 -41
  142. package/build/map/ExpoGaodeMap.types.js +0 -24
  143. package/build/map/utils/EventManager.d.ts +0 -10
  144. package/build/map/utils/EventManager.js +0 -26
  145. package/build/map/utils/ModuleLoader.d.ts +0 -73
  146. package/build/map/utils/ModuleLoader.js +0 -112
@@ -0,0 +1,159 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+ #include <string>
5
+
6
+ namespace gaodemap {
7
+
8
+ struct GeoPoint {
9
+ double lat;
10
+ double lon;
11
+ };
12
+
13
+ double calculateDistance(double lat1, double lon1, double lat2, double lon2);
14
+ bool isPointInCircle(double pointLat, double pointLon, double centerLat, double centerLon, double radiusMeters);
15
+ bool isPointInPolygon(double pointLat, double pointLon, const std::vector<GeoPoint>& polygon);
16
+ double calculatePolygonArea(const std::vector<GeoPoint>& polygon);
17
+ double calculateRectangleArea(double swLat, double swLon, double neLat, double neLon);
18
+
19
+ /**
20
+ * Ramer-Douglas-Peucker 轨迹抽稀算法
21
+ * @param points 原始轨迹点
22
+ * @param toleranceMeters 允许的误差(米),值越大点越少
23
+ * @return 简化后的轨迹点
24
+ */
25
+ std::vector<GeoPoint> simplifyPolyline(const std::vector<GeoPoint>& points, double toleranceMeters);
26
+
27
+ /**
28
+ * 计算路径总长度(米)
29
+ */
30
+ double calculatePathLength(const std::vector<GeoPoint>& points);
31
+
32
+ /**
33
+ * 获取路径上指定距离的点和方向
34
+ * @param points 路径点
35
+ * @param distanceMeters 距离起点的米数
36
+ * @param outLat 输出纬度
37
+ * @param outLon 输出经度
38
+ * @param outAngle 输出方向角度 (0-360)
39
+ * @return 是否成功找到点
40
+ */
41
+ bool getPointAtDistance(const std::vector<GeoPoint>& points, double distanceMeters, double* outLat, double* outLon, double* outAngle);
42
+
43
+ // Result structure for nearest point calculation
44
+ struct NearestPointResult {
45
+ double latitude;
46
+ double longitude;
47
+ int index; // Index of the point in the path that starts the segment (or the point itself)
48
+ double distanceMeters;
49
+ };
50
+
51
+ // Find the nearest point on the path to a target point
52
+ // Returns the nearest point on the polyline segments
53
+ NearestPointResult getNearestPointOnPath(const std::vector<GeoPoint>& path, const GeoPoint& target);
54
+
55
+ /**
56
+ * 计算多边形的质心
57
+ * @param polygon 多边形点集
58
+ * @return 质心坐标
59
+ */
60
+ GeoPoint calculateCentroid(const std::vector<GeoPoint>& polygon);
61
+
62
+ /**
63
+ * GeoHash 编码
64
+ * @param lat 纬度
65
+ * @param lon 经度
66
+ * @param precision 精度 (1-12)
67
+ * @return GeoHash 字符串
68
+ */
69
+ std::string encodeGeoHash(double lat, double lon, int precision);
70
+
71
+ /**
72
+ * 解析高德地图 API 返回的 Polyline 字符串
73
+ * 格式: "lng,lat;lng,lat;..."
74
+ * @param polylineStr 高德原始 polyline 字符串
75
+ * @return 解析后的点集
76
+ */
77
+ std::vector<GeoPoint> parsePolyline(const std::string& polylineStr);
78
+
79
+ struct PathBounds {
80
+ double north;
81
+ double south;
82
+ double east;
83
+ double west;
84
+ double centerLat;
85
+ double centerLon;
86
+ };
87
+
88
+ /**
89
+ * 计算路径的边界和中心点
90
+ * @param points 路径点
91
+ * @return 边界信息
92
+ */
93
+ PathBounds calculatePathBounds(const std::vector<GeoPoint>& points);
94
+
95
+ // --- 瓦片与坐标转换 ---
96
+
97
+ struct TileResult {
98
+ int x;
99
+ int y;
100
+ int z;
101
+ };
102
+
103
+ struct PixelResult {
104
+ double x;
105
+ double y;
106
+ };
107
+
108
+ /**
109
+ * 经纬度转瓦片坐标
110
+ */
111
+ TileResult latLngToTile(double lat, double lon, int zoom);
112
+
113
+ /**
114
+ * 瓦片坐标转经纬度
115
+ */
116
+ GeoPoint tileToLatLng(int x, int y, int zoom);
117
+
118
+ /**
119
+ * 经纬度转像素坐标
120
+ */
121
+ PixelResult latLngToPixel(double lat, double lon, int zoom);
122
+
123
+ /**
124
+ * 像素坐标转经纬度
125
+ */
126
+ GeoPoint pixelToLatLng(double x, double y, int zoom);
127
+
128
+ // --- 批量地理围栏与热力图 ---
129
+
130
+ /**
131
+ * 批量判断点是否在多个多边形内 (优化版)
132
+ * @param pointLat 点纬度
133
+ * @param pointLon 点经度
134
+ * @param polygons 多个多边形的集合
135
+ * @return 所在的第一个多边形的索引,若不在任何多边形内返回 -1
136
+ */
137
+ int findPointInPolygons(double pointLat, double pointLon, const std::vector<std::vector<GeoPoint>>& polygons);
138
+
139
+ struct HeatmapPoint {
140
+ double lat;
141
+ double lon;
142
+ double weight;
143
+ };
144
+
145
+ struct HeatmapGridCell {
146
+ double lat;
147
+ double lon;
148
+ double intensity;
149
+ };
150
+
151
+ /**
152
+ * 生成热力图网格数据
153
+ * @param points 原始点集
154
+ * @param gridSizeMeters 网格大小(米)
155
+ * @return 网格中心点及其强度
156
+ */
157
+ std::vector<HeatmapGridCell> generateHeatmapGrid(const std::vector<HeatmapPoint>& points, double gridSizeMeters);
158
+
159
+ } // namespace gaodemap
@@ -0,0 +1,92 @@
1
+ #include "QuadTree.hpp"
2
+
3
+ namespace gaodemap {
4
+
5
+ bool BoundingBox::contains(double lat, double lon) const {
6
+ return lat >= minLat && lat <= maxLat && lon >= minLon && lon <= maxLon;
7
+ }
8
+
9
+ bool BoundingBox::intersects(const BoundingBox& other) const {
10
+ return !(other.minLat > maxLat || other.maxLat < minLat ||
11
+ other.minLon > maxLon || other.maxLon < minLon);
12
+ }
13
+
14
+ QuadTree::QuadTree(const BoundingBox& bounds, int capacity)
15
+ : bounds(bounds), capacity(capacity) {}
16
+
17
+ bool QuadTree::insert(const ClusterPoint& point) {
18
+ if (!bounds.contains(point.lat, point.lon)) {
19
+ return false;
20
+ }
21
+
22
+ if (points.size() < capacity && !subdivided) {
23
+ points.push_back(point);
24
+ return true;
25
+ }
26
+
27
+ if (!subdivided) {
28
+ subdivide();
29
+ }
30
+
31
+ if (northWest->insert(point)) return true;
32
+ if (northEast->insert(point)) return true;
33
+ if (southWest->insert(point)) return true;
34
+ if (southEast->insert(point)) return true;
35
+
36
+ // Point might be exactly on the boundary of the QuadTree but not accepted by children?
37
+ // In our logic, children cover the full range of the parent.
38
+ // However, floating point precision might be tricky.
39
+ // As a fallback, if we are subdivided but children didn't take it (rare),
40
+ // we can keep it here or force insert.
41
+ // Given the subdivision logic, it should cover all space.
42
+ return false;
43
+ }
44
+
45
+ void QuadTree::subdivide() {
46
+ double midLat = (bounds.minLat + bounds.maxLat) / 2.0;
47
+ double midLon = (bounds.minLon + bounds.maxLon) / 2.0;
48
+
49
+ northWest = std::make_unique<QuadTree>(BoundingBox{midLat, bounds.minLon, bounds.maxLat, midLon}, capacity);
50
+ northEast = std::make_unique<QuadTree>(BoundingBox{midLat, midLon, bounds.maxLat, bounds.maxLon}, capacity);
51
+ southWest = std::make_unique<QuadTree>(BoundingBox{bounds.minLat, bounds.minLon, midLat, midLon}, capacity);
52
+ southEast = std::make_unique<QuadTree>(BoundingBox{bounds.minLat, midLon, midLat, bounds.maxLon}, capacity);
53
+
54
+ subdivided = true;
55
+
56
+ // Redistribute existing points
57
+ for (const auto& p : points) {
58
+ northWest->insert(p) || northEast->insert(p) ||
59
+ southWest->insert(p) || southEast->insert(p);
60
+ }
61
+ points.clear();
62
+ }
63
+
64
+ void QuadTree::query(const BoundingBox& range, std::vector<ClusterPoint>& found) const {
65
+ if (!bounds.intersects(range)) {
66
+ return;
67
+ }
68
+
69
+ for (const auto& p : points) {
70
+ if (range.contains(p.lat, p.lon)) {
71
+ found.push_back(p);
72
+ }
73
+ }
74
+
75
+ if (subdivided) {
76
+ northWest->query(range, found);
77
+ northEast->query(range, found);
78
+ southWest->query(range, found);
79
+ southEast->query(range, found);
80
+ }
81
+ }
82
+
83
+ void QuadTree::clear() {
84
+ points.clear();
85
+ northWest.reset();
86
+ northEast.reset();
87
+ southWest.reset();
88
+ southEast.reset();
89
+ subdivided = false;
90
+ }
91
+
92
+ }
@@ -0,0 +1,42 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+ #include <memory>
5
+ #include "ClusterEngine.hpp"
6
+
7
+ namespace gaodemap {
8
+
9
+ struct BoundingBox {
10
+ double minLat;
11
+ double minLon;
12
+ double maxLat;
13
+ double maxLon;
14
+
15
+ bool contains(double lat, double lon) const;
16
+ bool intersects(const BoundingBox& other) const;
17
+ };
18
+
19
+ class QuadTree {
20
+ public:
21
+ QuadTree(const BoundingBox& bounds, int capacity = 20);
22
+ ~QuadTree() = default;
23
+
24
+ bool insert(const ClusterPoint& point);
25
+ void query(const BoundingBox& range, std::vector<ClusterPoint>& found) const;
26
+ void clear();
27
+
28
+ private:
29
+ BoundingBox bounds;
30
+ int capacity;
31
+ std::vector<ClusterPoint> points;
32
+ bool subdivided = false;
33
+
34
+ std::unique_ptr<QuadTree> northWest;
35
+ std::unique_ptr<QuadTree> northEast;
36
+ std::unique_ptr<QuadTree> southWest;
37
+ std::unique_ptr<QuadTree> southEast;
38
+
39
+ void subdivide();
40
+ };
41
+
42
+ }
@@ -0,0 +1,55 @@
1
+ # C++ 共享核心库 (Shared Core)
2
+
3
+ 该目录包含了 `expo-gaode-map` 跨平台核心逻辑的 C++ 实现。这些代码被 Android 和 iOS 平台共享,以确保计算逻辑的一致性并提升高性能计算场景(如点聚合、几何计算)的处理速度。
4
+
5
+ ## 模块说明
6
+
7
+ ### 1. GeometryEngine (几何引擎)
8
+ [GeometryEngine.hpp](file:///Users/wangqiang/Desktop/expo-gaode-map/packages/core/shared/cpp/GeometryEngine.hpp)
9
+ 提供地理空间相关的数学计算:
10
+ - **距离计算**: 基于 Haversine 公式计算经纬度点之间的球面距离。
11
+ - **点位判断**: 判断点是否在多边形 (Point-in-Polygon) 或圆形内。
12
+ - **面积计算**: 计算多边形或矩形的地理面积。
13
+ - **轨迹处理**:
14
+ - **抽稀算法**: 实现 Ramer-Douglas-Peucker 算法,用于简化复杂的折线轨迹。
15
+ - **路径长度**: 计算折线段的总长度。
16
+ - **路径插值**: 获取路径上指定距离的点坐标及其切线方向。
17
+ - **GeoHash**: 支持经纬度到 GeoHash 字符串的编码。
18
+ - **质心计算**: 计算多边形的几何质心。
19
+
20
+ ### 2. ClusterEngine (点聚合引擎)
21
+ [ClusterEngine.hpp](file:///Users/wangqiang/Desktop/expo-gaode-map/packages/core/shared/cpp/ClusterEngine.hpp)
22
+ 负责大规模地图标记点的聚合计算:
23
+ - 使用 **QuadTree** 进行空间索引优化。
24
+ - 支持基于半径的聚合逻辑。
25
+ - 高性能处理,适用于数千甚至数万个点的实时聚合。
26
+
27
+ ### 3. QuadTree (四叉树)
28
+ [QuadTree.hpp](file:///Users/wangqiang/Desktop/expo-gaode-map/packages/core/shared/cpp/QuadTree.hpp)
29
+ 为地理坐标提供高效的空间索引结构:
30
+ - **空间分割**: 自动将空间划分为四个象限。
31
+ - **范围查询**: 快速检索指定矩形区域内的所有点位。
32
+ - 被 `ClusterEngine` 用于加速近邻点搜索。
33
+
34
+ ### 4. ColorParser (颜色解析器)
35
+ [ColorParser.hpp](file:///Users/wangqiang/Desktop/expo-gaode-map/packages/core/shared/cpp/ColorParser.hpp)
36
+ 跨平台的颜色字符串解析工具:
37
+ - 支持 **Hex** 格式 (如 `#RRGGBB`, `#AARRGGBB`, `#RGB`)。
38
+ - 支持 **RGB/RGBA** 函数格式 (如 `rgba(255, 0, 0, 0.5)`)。
39
+ - 支持 **命名颜色** (如 `red`, `blue`, `transparent`)。
40
+ - 统一输出为 `0xAARRGGBB` 格式的 32 位整数。
41
+
42
+ ## 测试
43
+
44
+ 测试用例位于 `tests/` 目录。
45
+
46
+ ### 运行测试
47
+ 在 macOS/Linux 环境下,可以通过以下命令运行 C++ 单元测试:
48
+
49
+ ```bash
50
+ cd tests
51
+ chmod +x run.sh
52
+ ./run.sh
53
+ ```
54
+
55
+ 该脚本会使用 `clang++` 编译源代码并运行生成的测试二进制文件,验证各核心模块的逻辑准确性。
@@ -17,6 +17,9 @@ class UIManager: NSObject, MAMapViewDelegate {
17
17
  /// 定位变化回调
18
18
  var onLocationChanged: ((_ latitude: Double, _ longitude: Double, _ accuracy: Double) -> Void)?
19
19
 
20
+ /// 缓存的自定义样式配置
21
+ private var cachedCustomStyleOptions: MAMapCustomStyleOptions?
22
+
20
23
  init(mapView: MAMapView) {
21
24
  self.mapView = mapView
22
25
  super.init()
@@ -36,6 +39,13 @@ class UIManager: NSObject, MAMapViewDelegate {
36
39
  case 3: mapView.mapType = .navi
37
40
  default: mapView.mapType = .standard
38
41
  }
42
+
43
+ // 🔑 关键修复:切换地图类型后重新应用自定义样式
44
+ // 某些地图类型切换可能会重置样式设置
45
+ if let cachedOptions = cachedCustomStyleOptions {
46
+ mapView.setCustomMapStyleOptions(cachedOptions)
47
+ mapView.customMapStyleEnabled = true
48
+ }
39
49
  }
40
50
 
41
51
  // MARK: - 控件显示
@@ -109,7 +119,8 @@ class UIManager: NSObject, MAMapViewDelegate {
109
119
  }
110
120
  mapView.showsUserLocation = true
111
121
  if followUser {
112
- mapView.userTrackingMode = .follow
122
+ // 🔑 使用 followWithHeading 模式以支持方向指示器
123
+ mapView.userTrackingMode = .followWithHeading
113
124
  } else {
114
125
  mapView.userTrackingMode = .none
115
126
  }
@@ -146,6 +157,12 @@ class UIManager: NSObject, MAMapViewDelegate {
146
157
  guard let mapView = mapView else { return }
147
158
  let representation = MAUserLocationRepresentation()
148
159
 
160
+ // 是否显示定位蓝点 (showMyLocation) - 对应 Android 的 showMyLocation
161
+ // iOS 通过 mapView.showsUserLocation 控制,这里提供统一的 API
162
+ if let showMyLocation = config["showMyLocation"] as? Bool {
163
+ mapView.showsUserLocation = showMyLocation
164
+ }
165
+
149
166
  // 精度圈是否显示
150
167
  if let showsAccuracyRing = config["showsAccuracyRing"] as? Bool {
151
168
  representation.showsAccuracyRing = showsAccuracyRing
@@ -265,4 +282,58 @@ class UIManager: NSObject, MAMapViewDelegate {
265
282
  func setShowsIndoorMap(_ show: Bool) {
266
283
  mapView?.isShowsIndoorMap = show
267
284
  }
285
+
286
+ // MARK: - 自定义地图样式
287
+
288
+ /**
289
+ * 设置自定义地图样式
290
+ * @param styleData 样式数据,支持以下格式:
291
+ * - styleId: String - 在线样式ID(从高德开放平台获取)
292
+ * - styleDataPath: String - 本地样式文件路径
293
+ * - extraStyleDataPath: String - 额外样式文件路径(可选)
294
+ */
295
+ func setCustomMapStyle(_ styleData: [String: Any]) {
296
+ guard let mapView = mapView else { return }
297
+
298
+ // 在线样式 ID
299
+ if let styleId = styleData["styleId"] as? String, !styleId.isEmpty {
300
+ let customStyle = MAMapCustomStyleOptions()
301
+ customStyle.styleId = styleId
302
+
303
+ // 🔑 缓存样式配置
304
+ cachedCustomStyleOptions = customStyle
305
+
306
+ mapView.setCustomMapStyleOptions(customStyle)
307
+ mapView.customMapStyleEnabled = true
308
+ return
309
+ }
310
+
311
+ // 本地样式文件
312
+ if let styleDataPath = styleData["styleDataPath"] as? String, !styleDataPath.isEmpty {
313
+ // 读取样式文件数据
314
+ if let stylePath = Bundle.main.path(forResource: styleDataPath, ofType: nil),
315
+ let styleFileData = try? Data(contentsOf: URL(fileURLWithPath: stylePath)) {
316
+ let customStyle = MAMapCustomStyleOptions()
317
+ customStyle.styleData = styleFileData
318
+
319
+ // 额外样式文件(可选)
320
+ if let extraPath = styleData["extraStyleDataPath"] as? String, !extraPath.isEmpty,
321
+ let extraFilePath = Bundle.main.path(forResource: extraPath, ofType: nil),
322
+ let extraFileData = try? Data(contentsOf: URL(fileURLWithPath: extraFilePath)) {
323
+ customStyle.styleExtraData = extraFileData
324
+ }
325
+
326
+ // 🔑 缓存样式配置
327
+ cachedCustomStyleOptions = customStyle
328
+
329
+ mapView.setCustomMapStyleOptions(customStyle)
330
+ mapView.customMapStyleEnabled = true
331
+ return
332
+ }
333
+ }
334
+
335
+ // 如果没有提供任何样式,禁用自定义样式并清除缓存
336
+ cachedCustomStyleOptions = nil
337
+ mapView.customMapStyleEnabled = false
338
+ }
268
339
  }