expo-gaode-map-search 1.2.0-beta.0 → 1.3.0
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/android/build/intermediates/aar_main_jar/debug/syncDebugLibJars/classes.jar +0 -0
- package/android/build/intermediates/annotations_typedef_file/debug/extractDebugAnnotations/typedefs.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug-mergeJavaRes/merge-state +0 -0
- package/android/build/intermediates/merged_java_res/debug/mergeDebugJavaResource/feature-expo-gaode-map-search.jar +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +1 -1
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/aar/expo-gaode-map-search-debug.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +9 -9
- package/android/build.gradle +4 -3
- package/android/src/main/java/expo/modules/gaodemap/search/ExpoGaodeMapSearchModule.kt +354 -0
- package/build/ExpoGaodeMapSearchModule.js +33 -0
- package/ios/ExpoGaodeMapSearchModule.swift +415 -0
- package/package.json +16 -9
- package/src/ExpoGaodeMapSearch.types.ts +179 -0
- package/src/ExpoGaodeMapSearchModule.ts +46 -0
- package/src/index.ts +170 -0
- package/.eslintrc.js +0 -2
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/package.json.backup +0 -54
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import AMapSearchKit
|
|
3
|
+
import AMapFoundationKit
|
|
4
|
+
|
|
5
|
+
public class ExpoGaodeMapSearchModule: Module {
|
|
6
|
+
private var searchAPI: AMapSearchAPI!
|
|
7
|
+
private var searchDelegate: SearchDelegate!
|
|
8
|
+
|
|
9
|
+
public func definition() -> ModuleDefinition {
|
|
10
|
+
Name("ExpoGaodeMapSearch")
|
|
11
|
+
|
|
12
|
+
// 不在 OnCreate 中初始化,改为延迟初始化
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 手动初始化搜索模块(可选)
|
|
16
|
+
* 如果 API Key 已经设置,则直接初始化
|
|
17
|
+
* 如果未设置,会尝试从 Info.plist 读取
|
|
18
|
+
*/
|
|
19
|
+
Function("initSearch") {
|
|
20
|
+
self.initSearchAPI()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* POI 搜索
|
|
25
|
+
*/
|
|
26
|
+
AsyncFunction("searchPOI") { (options: [String: Any], promise: Promise) in
|
|
27
|
+
// 延迟初始化:在首次使用时才初始化
|
|
28
|
+
self.initSearchAPI()
|
|
29
|
+
|
|
30
|
+
guard let keyword = options["keyword"] as? String else {
|
|
31
|
+
promise.reject("SEARCH_ERROR", "keyword is required")
|
|
32
|
+
return
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let city = options["city"] as? String ?? ""
|
|
36
|
+
let types = options["types"] as? String ?? ""
|
|
37
|
+
let pageSize = options["pageSize"] as? Int ?? 20
|
|
38
|
+
let pageNum = options["pageNum"] as? Int ?? 1
|
|
39
|
+
|
|
40
|
+
let request = AMapPOIKeywordsSearchRequest()
|
|
41
|
+
request.keywords = keyword
|
|
42
|
+
request.city = city
|
|
43
|
+
request.types = types
|
|
44
|
+
request.page = pageNum
|
|
45
|
+
request.offset = pageSize
|
|
46
|
+
|
|
47
|
+
self.searchDelegate.currentPromise = promise
|
|
48
|
+
self.searchAPI.aMapPOIKeywordsSearch(request)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 周边搜索
|
|
53
|
+
*/
|
|
54
|
+
AsyncFunction("searchNearby") { (options: [String: Any], promise: Promise) in
|
|
55
|
+
self.initSearchAPI()
|
|
56
|
+
|
|
57
|
+
guard let keyword = options["keyword"] as? String else {
|
|
58
|
+
promise.reject("SEARCH_ERROR", "keyword is required")
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
guard let center = options["center"] as? [String: Any],
|
|
63
|
+
let latitude = center["latitude"] as? Double,
|
|
64
|
+
let longitude = center["longitude"] as? Double else {
|
|
65
|
+
promise.reject("SEARCH_ERROR", "center is required")
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let radius = options["radius"] as? Int ?? 1000
|
|
70
|
+
let types = options["types"] as? String ?? ""
|
|
71
|
+
let pageSize = options["pageSize"] as? Int ?? 20
|
|
72
|
+
let pageNum = options["pageNum"] as? Int ?? 1
|
|
73
|
+
|
|
74
|
+
let request = AMapPOIAroundSearchRequest()
|
|
75
|
+
request.keywords = keyword
|
|
76
|
+
request.location = AMapGeoPoint.location(
|
|
77
|
+
withLatitude: CGFloat(latitude),
|
|
78
|
+
longitude: CGFloat(longitude)
|
|
79
|
+
)
|
|
80
|
+
request.radius = radius
|
|
81
|
+
request.types = types
|
|
82
|
+
request.page = pageNum
|
|
83
|
+
request.offset = pageSize
|
|
84
|
+
|
|
85
|
+
self.searchDelegate.currentPromise = promise
|
|
86
|
+
self.searchAPI.aMapPOIAroundSearch(request)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 沿途搜索
|
|
91
|
+
* iOS SDK 支持的沿途搜索类型:加油站、ATM、汽修、厕所
|
|
92
|
+
*/
|
|
93
|
+
AsyncFunction("searchAlong") { (options: [String: Any], promise: Promise) in
|
|
94
|
+
self.initSearchAPI()
|
|
95
|
+
|
|
96
|
+
guard let keyword = options["keyword"] as? String else {
|
|
97
|
+
promise.reject("SEARCH_ERROR", "keyword is required")
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
guard let polyline = options["polyline"] as? [[String: Any]] else {
|
|
102
|
+
promise.reject("SEARCH_ERROR", "polyline is required")
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
guard polyline.count >= 2 else {
|
|
107
|
+
promise.reject("SEARCH_ERROR", "polyline must have at least 2 points")
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 转换路线点
|
|
112
|
+
var points: [AMapGeoPoint] = []
|
|
113
|
+
for point in polyline {
|
|
114
|
+
if let lat = point["latitude"] as? Double,
|
|
115
|
+
let lng = point["longitude"] as? Double {
|
|
116
|
+
points.append(AMapGeoPoint.location(
|
|
117
|
+
withLatitude: CGFloat(lat),
|
|
118
|
+
longitude: CGFloat(lng)
|
|
119
|
+
))
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
guard let startPoint = points.first,
|
|
124
|
+
let endPoint = points.last else {
|
|
125
|
+
promise.reject("SEARCH_ERROR", "Invalid polyline points")
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 根据关键词确定搜索类型
|
|
130
|
+
let lowercaseKeyword = keyword.lowercased()
|
|
131
|
+
var searchType: AMapRoutePOISearchType = .gasStation
|
|
132
|
+
if lowercaseKeyword.contains("加油") || lowercaseKeyword == "加油站" {
|
|
133
|
+
searchType = .gasStation
|
|
134
|
+
} else if lowercaseKeyword.contains("atm") || lowercaseKeyword.contains("银行") {
|
|
135
|
+
searchType = .ATM
|
|
136
|
+
} else if lowercaseKeyword.contains("汽修") || lowercaseKeyword.contains("维修") {
|
|
137
|
+
searchType = .maintenanceStation
|
|
138
|
+
} else if lowercaseKeyword.contains("厕所") || lowercaseKeyword.contains("卫生间") {
|
|
139
|
+
searchType = .toilet
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let request = AMapRoutePOISearchRequest()
|
|
143
|
+
request.origin = startPoint
|
|
144
|
+
request.destination = endPoint
|
|
145
|
+
request.searchType = searchType
|
|
146
|
+
request.range = 250
|
|
147
|
+
request.strategy = 0
|
|
148
|
+
|
|
149
|
+
self.searchDelegate.currentPromise = promise
|
|
150
|
+
self.searchAPI.aMapRoutePOISearch(request)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 多边形搜索
|
|
155
|
+
*/
|
|
156
|
+
AsyncFunction("searchPolygon") { (options: [String: Any], promise: Promise) in
|
|
157
|
+
self.initSearchAPI()
|
|
158
|
+
|
|
159
|
+
guard let keyword = options["keyword"] as? String else {
|
|
160
|
+
promise.reject("SEARCH_ERROR", "keyword is required")
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
guard let polygon = options["polygon"] as? [[String: Any]] else {
|
|
165
|
+
promise.reject("SEARCH_ERROR", "polygon is required")
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let types = options["types"] as? String ?? ""
|
|
170
|
+
let pageSize = options["pageSize"] as? Int ?? 20
|
|
171
|
+
let pageNum = options["pageNum"] as? Int ?? 1
|
|
172
|
+
|
|
173
|
+
var points: [AMapGeoPoint] = []
|
|
174
|
+
for point in polygon {
|
|
175
|
+
if let lat = point["latitude"] as? Double,
|
|
176
|
+
let lng = point["longitude"] as? Double {
|
|
177
|
+
points.append(AMapGeoPoint.location(
|
|
178
|
+
withLatitude: CGFloat(lat),
|
|
179
|
+
longitude: CGFloat(lng)
|
|
180
|
+
))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let request = AMapPOIPolygonSearchRequest()
|
|
185
|
+
request.keywords = keyword
|
|
186
|
+
request.polygon = AMapGeoPolygon(points: points)
|
|
187
|
+
request.types = types
|
|
188
|
+
request.page = pageNum
|
|
189
|
+
request.offset = pageSize
|
|
190
|
+
|
|
191
|
+
self.searchDelegate.currentPromise = promise
|
|
192
|
+
self.searchAPI.aMapPOIPolygonSearch(request)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 输入提示
|
|
197
|
+
*/
|
|
198
|
+
AsyncFunction("getInputTips") { (options: [String: Any], promise: Promise) in
|
|
199
|
+
self.initSearchAPI()
|
|
200
|
+
|
|
201
|
+
guard let keyword = options["keyword"] as? String else {
|
|
202
|
+
promise.reject("TIPS_ERROR", "keyword is required")
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let city = options["city"] as? String ?? ""
|
|
207
|
+
let types = options["types"] as? String ?? ""
|
|
208
|
+
|
|
209
|
+
let request = AMapInputTipsSearchRequest()
|
|
210
|
+
request.keywords = keyword
|
|
211
|
+
request.city = city
|
|
212
|
+
request.types = types
|
|
213
|
+
|
|
214
|
+
self.searchDelegate.currentPromise = promise
|
|
215
|
+
self.searchAPI.aMapInputTipsSearch(request)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// MARK: - Private Methods
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* 初始化搜索 API(延迟初始化)
|
|
223
|
+
*/
|
|
224
|
+
private func initSearchAPI() {
|
|
225
|
+
if searchAPI == nil {
|
|
226
|
+
// 确保 API Key 已设置
|
|
227
|
+
self.ensureAPIKeyIsSet()
|
|
228
|
+
|
|
229
|
+
searchDelegate = SearchDelegate()
|
|
230
|
+
searchAPI = AMapSearchAPI()
|
|
231
|
+
searchAPI.delegate = searchDelegate
|
|
232
|
+
|
|
233
|
+
let apiKey = AMapServices.shared().apiKey
|
|
234
|
+
print("[ExpoGaodeMapSearch] 搜索 API 已初始化,API Key: \(apiKey ?? "未设置")")
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 确保 API Key 已设置
|
|
240
|
+
* 优先级:已设置 > Info.plist > 提示错误
|
|
241
|
+
*/
|
|
242
|
+
private func ensureAPIKeyIsSet() {
|
|
243
|
+
// 1. 检查是否已经设置(通过 initSDK 或 AppDelegate)
|
|
244
|
+
if let existingKey = AMapServices.shared().apiKey, !existingKey.isEmpty {
|
|
245
|
+
print("[ExpoGaodeMapSearch] ✓ API Key 已设置")
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 2. 尝试从 Info.plist 读取(Config Plugin 会写入)
|
|
250
|
+
if let apiKey = Bundle.main.object(forInfoDictionaryKey: "AMapApiKey") as? String, !apiKey.isEmpty {
|
|
251
|
+
AMapServices.shared().apiKey = apiKey
|
|
252
|
+
AMapServices.shared().enableHTTPS = true
|
|
253
|
+
print("[ExpoGaodeMapSearch] ✓ 从 Info.plist 读取并设置 API Key")
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 3. 都没有,提示错误
|
|
258
|
+
print("[ExpoGaodeMapSearch] ✗ 错误: API Key 未设置!")
|
|
259
|
+
print("[ExpoGaodeMapSearch] 请通过以下任一方式设置:")
|
|
260
|
+
print("[ExpoGaodeMapSearch] 1. 在 app.json 的 plugins 中配置 iosApiKey(推荐)")
|
|
261
|
+
print("[ExpoGaodeMapSearch] 2. 调用 ExpoGaodeMap.initSDK({ iosKey: 'your-key' })")
|
|
262
|
+
print("[ExpoGaodeMapSearch] 3. 在 AppDelegate 中调用 [AMapServices sharedServices].apiKey = @\"your-key\"")
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// MARK: - Search Delegate
|
|
267
|
+
class SearchDelegate: NSObject, AMapSearchDelegate {
|
|
268
|
+
var currentPromise: Promise?
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* POI 搜索回调
|
|
272
|
+
*/
|
|
273
|
+
func onPOISearchDone(_ request: AMapPOISearchBaseRequest!, response: AMapPOISearchResponse!) {
|
|
274
|
+
guard let promise = currentPromise else { return }
|
|
275
|
+
|
|
276
|
+
if let response = response {
|
|
277
|
+
promise.resolve(convertPOISearchResponse(response))
|
|
278
|
+
} else {
|
|
279
|
+
promise.reject("SEARCH_ERROR", "Search failed")
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
currentPromise = nil
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 沿途搜索回调
|
|
287
|
+
*/
|
|
288
|
+
func onRoutePOISearchDone(_ request: AMapRoutePOISearchRequest!, response: AMapRoutePOISearchResponse!) {
|
|
289
|
+
guard let promise = currentPromise else { return }
|
|
290
|
+
|
|
291
|
+
if let response = response {
|
|
292
|
+
promise.resolve(convertRoutePOISearchResponse(response))
|
|
293
|
+
} else {
|
|
294
|
+
promise.reject("SEARCH_ERROR", "Route search failed")
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
currentPromise = nil
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 输入提示回调
|
|
302
|
+
*/
|
|
303
|
+
func onInputTipsSearchDone(_ request: AMapInputTipsSearchRequest!, response: AMapInputTipsSearchResponse!) {
|
|
304
|
+
guard let promise = currentPromise else { return }
|
|
305
|
+
|
|
306
|
+
if let response = response {
|
|
307
|
+
promise.resolve(convertInputTipsResponse(response))
|
|
308
|
+
} else {
|
|
309
|
+
promise.reject("TIPS_ERROR", "Input tips failed")
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
currentPromise = nil
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 搜索失败回调
|
|
317
|
+
*/
|
|
318
|
+
func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) {
|
|
319
|
+
guard let promise = currentPromise else { return }
|
|
320
|
+
|
|
321
|
+
let errorMessage = error?.localizedDescription ?? "Unknown error"
|
|
322
|
+
promise.reject("SEARCH_ERROR", errorMessage)
|
|
323
|
+
currentPromise = nil
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// MARK: - 转换方法
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* 转换 POI 搜索结果
|
|
330
|
+
*/
|
|
331
|
+
private func convertPOISearchResponse(_ response: AMapPOISearchResponse) -> [String: Any] {
|
|
332
|
+
let pois = response.pois?.map { poi -> [String: Any] in
|
|
333
|
+
var result: [String: Any] = [
|
|
334
|
+
"id": poi.uid ?? "",
|
|
335
|
+
"name": poi.name ?? "",
|
|
336
|
+
"address": poi.address ?? "",
|
|
337
|
+
"location": [
|
|
338
|
+
"latitude": poi.location?.latitude ?? 0,
|
|
339
|
+
"longitude": poi.location?.longitude ?? 0
|
|
340
|
+
],
|
|
341
|
+
"typeCode": poi.typecode ?? "",
|
|
342
|
+
"typeDes": poi.type ?? "",
|
|
343
|
+
"tel": poi.tel ?? "",
|
|
344
|
+
"distance": poi.distance,
|
|
345
|
+
"cityName": poi.city ?? "",
|
|
346
|
+
"provinceName": poi.province ?? "",
|
|
347
|
+
"adName": poi.district ?? "",
|
|
348
|
+
"adCode": poi.adcode ?? ""
|
|
349
|
+
]
|
|
350
|
+
return result
|
|
351
|
+
} ?? []
|
|
352
|
+
|
|
353
|
+
return [
|
|
354
|
+
"pois": pois,
|
|
355
|
+
"total": response.count,
|
|
356
|
+
"pageNum": response.pois?.first?.uid != nil ? 1 : 0,
|
|
357
|
+
"pageSize": response.pois?.count ?? 0,
|
|
358
|
+
"pageCount": (response.count + 19) / 20
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 转换输入提示结果
|
|
364
|
+
*/
|
|
365
|
+
private func convertInputTipsResponse(_ response: AMapInputTipsSearchResponse) -> [String: Any] {
|
|
366
|
+
let tips = response.tips?.map { tip -> [String: Any] in
|
|
367
|
+
var result: [String: Any] = [
|
|
368
|
+
"id": tip.uid ?? "",
|
|
369
|
+
"name": tip.name ?? "",
|
|
370
|
+
"address": tip.address ?? "",
|
|
371
|
+
"typeCode": tip.typecode ?? "",
|
|
372
|
+
"cityName": tip.district ?? "",
|
|
373
|
+
"adName": tip.district ?? ""
|
|
374
|
+
]
|
|
375
|
+
|
|
376
|
+
if let location = tip.location {
|
|
377
|
+
result["location"] = [
|
|
378
|
+
"latitude": location.latitude,
|
|
379
|
+
"longitude": location.longitude
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
return result
|
|
384
|
+
} ?? []
|
|
385
|
+
|
|
386
|
+
return ["tips": tips]
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* 转换沿途 POI 搜索结果
|
|
391
|
+
*/
|
|
392
|
+
private func convertRoutePOISearchResponse(_ response: AMapRoutePOISearchResponse) -> [String: Any] {
|
|
393
|
+
let pois = response.pois?.map { poi -> [String: Any] in
|
|
394
|
+
var result: [String: Any] = [
|
|
395
|
+
"id": poi.uid ?? "",
|
|
396
|
+
"name": poi.name ?? "",
|
|
397
|
+
"address": "",
|
|
398
|
+
"location": [
|
|
399
|
+
"latitude": poi.location?.latitude ?? 0,
|
|
400
|
+
"longitude": poi.location?.longitude ?? 0
|
|
401
|
+
],
|
|
402
|
+
"distance": poi.distance
|
|
403
|
+
]
|
|
404
|
+
return result
|
|
405
|
+
} ?? []
|
|
406
|
+
|
|
407
|
+
return [
|
|
408
|
+
"pois": pois,
|
|
409
|
+
"total": pois.count,
|
|
410
|
+
"pageNum": 1,
|
|
411
|
+
"pageSize": pois.count,
|
|
412
|
+
"pageCount": 1
|
|
413
|
+
]
|
|
414
|
+
}
|
|
415
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-gaode-map-search",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "高德地图搜索功能模块 - POI搜索、关键词搜索、周边搜索,需先安装expo-gaode-map",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -21,8 +21,17 @@
|
|
|
21
21
|
"author": "尚博信_王强 <wangqiang03@sunboxsoft.com> (https://github.com/TomWq)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"homepage": "https://github.com/TomWq/expo-gaode-map#readme",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"files": [
|
|
25
|
+
"build/**/*",
|
|
26
|
+
"src/**/*",
|
|
27
|
+
"android/**/*",
|
|
28
|
+
"ios/**/*",
|
|
29
|
+
"expo-module.config.json",
|
|
30
|
+
"README.md",
|
|
31
|
+
"package.json"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
26
35
|
},
|
|
27
36
|
"devDependencies": {
|
|
28
37
|
"@types/react": "~19.1.0",
|
|
@@ -33,20 +42,18 @@
|
|
|
33
42
|
},
|
|
34
43
|
"peerDependencies": {
|
|
35
44
|
"expo": "*",
|
|
36
|
-
"expo-gaode-map": ">=2.0.0",
|
|
37
45
|
"react": "*",
|
|
38
46
|
"react-native": "*"
|
|
39
47
|
},
|
|
40
|
-
"
|
|
41
|
-
"expo-gaode-map":
|
|
42
|
-
"optional": false
|
|
43
|
-
}
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"expo-gaode-map": "^2.2.0"
|
|
44
50
|
},
|
|
45
51
|
"scripts": {
|
|
46
52
|
"build": "expo-module build",
|
|
47
53
|
"clean": "expo-module clean",
|
|
48
54
|
"lint": "expo-module lint",
|
|
49
55
|
"test": "expo-module test",
|
|
50
|
-
"expo-module": "expo-module"
|
|
56
|
+
"expo-module": "expo-module",
|
|
57
|
+
"postinstall": "node -e \"try{require.resolve('expo-gaode-map');process.exit(0)}catch(e1){try{require.resolve('expo-gaode-map-navigation');process.exit(0)}catch(e2){console.error('[expo-gaode-map-search] 需要安装基础地图组件:expo-gaode-map 或 expo-gaode-map-navigation 中的任意一个。\\n请执行:pnpm add expo-gaode-map 或 pnpm add expo-gaode-map-navigation');process.exit(1)}}\""
|
|
51
58
|
}
|
|
52
59
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 搜索类型
|
|
3
|
+
*/
|
|
4
|
+
export enum SearchType {
|
|
5
|
+
/** POI 搜索 */
|
|
6
|
+
POI = 'poi',
|
|
7
|
+
/** 周边搜索 */
|
|
8
|
+
NEARBY = 'nearby',
|
|
9
|
+
/** 沿途搜索 */
|
|
10
|
+
ALONG = 'along',
|
|
11
|
+
/** 多边形搜索 */
|
|
12
|
+
POLYGON = 'polygon',
|
|
13
|
+
/** 输入提示 */
|
|
14
|
+
INPUT_TIPS = 'inputTips',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 坐标点
|
|
19
|
+
*/
|
|
20
|
+
export interface Coordinates {
|
|
21
|
+
latitude: number;
|
|
22
|
+
longitude: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* POI 信息
|
|
27
|
+
*/
|
|
28
|
+
export interface POI {
|
|
29
|
+
/** POI ID */
|
|
30
|
+
id: string;
|
|
31
|
+
/** 名称 */
|
|
32
|
+
name: string;
|
|
33
|
+
/** 地址 */
|
|
34
|
+
address: string;
|
|
35
|
+
/** 坐标 */
|
|
36
|
+
location: Coordinates;
|
|
37
|
+
/** 类型编码 */
|
|
38
|
+
typeCode: string;
|
|
39
|
+
/** 类型描述 */
|
|
40
|
+
typeDes: string;
|
|
41
|
+
/** 电话 */
|
|
42
|
+
tel?: string;
|
|
43
|
+
/** 距离(米),仅周边搜索返回 */
|
|
44
|
+
distance?: number;
|
|
45
|
+
/** 城市名称 */
|
|
46
|
+
cityName?: string;
|
|
47
|
+
/** 城市编码 */
|
|
48
|
+
cityCode?: string;
|
|
49
|
+
/** 省份名称 */
|
|
50
|
+
provinceName?: string;
|
|
51
|
+
/** 区域名称 */
|
|
52
|
+
adName?: string;
|
|
53
|
+
/** 区域编码 */
|
|
54
|
+
adCode?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* POI 搜索选项
|
|
59
|
+
*/
|
|
60
|
+
export interface POISearchOptions {
|
|
61
|
+
/** 搜索关键词 */
|
|
62
|
+
keyword: string;
|
|
63
|
+
/** 城市名称或城市编码(可选) */
|
|
64
|
+
city?: string;
|
|
65
|
+
/** POI 类型(可选),多个类型用 | 分隔 */
|
|
66
|
+
types?: string;
|
|
67
|
+
/** 每页记录数,默认 20,最大 50 */
|
|
68
|
+
pageSize?: number;
|
|
69
|
+
/** 当前页码,从 1 开始,默认 1 */
|
|
70
|
+
pageNum?: number;
|
|
71
|
+
/** 是否按照距离排序,需要设置中心点 */
|
|
72
|
+
sortByDistance?: boolean;
|
|
73
|
+
/** 中心点坐标,用于距离排序或周边搜索 */
|
|
74
|
+
center?: Coordinates;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 周边搜索选项
|
|
79
|
+
*/
|
|
80
|
+
export interface NearbySearchOptions {
|
|
81
|
+
/** 搜索关键词 */
|
|
82
|
+
keyword: string;
|
|
83
|
+
/** 中心点坐标 */
|
|
84
|
+
center: Coordinates;
|
|
85
|
+
/** 搜索半径,单位:米,默认 1000,最大 50000 */
|
|
86
|
+
radius?: number;
|
|
87
|
+
/** POI 类型(可选),多个类型用 | 分隔 */
|
|
88
|
+
types?: string;
|
|
89
|
+
/** 每页记录数,默认 20,最大 50 */
|
|
90
|
+
pageSize?: number;
|
|
91
|
+
/** 当前页码,从 1 开始,默认 1 */
|
|
92
|
+
pageNum?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 沿途搜索选项
|
|
97
|
+
*/
|
|
98
|
+
export interface AlongSearchOptions {
|
|
99
|
+
/** 搜索关键词 */
|
|
100
|
+
keyword: string;
|
|
101
|
+
/** 路线坐标点数组 */
|
|
102
|
+
polyline: Coordinates[];
|
|
103
|
+
/** 搜索范围,单位:米,默认 500,最大 1000 */
|
|
104
|
+
range?: number;
|
|
105
|
+
/** POI 类型(可选),多个类型用 | 分隔 */
|
|
106
|
+
types?: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 多边形搜索选项
|
|
111
|
+
*/
|
|
112
|
+
export interface PolygonSearchOptions {
|
|
113
|
+
/** 搜索关键词 */
|
|
114
|
+
keyword: string;
|
|
115
|
+
/** 多边形顶点坐标数组 */
|
|
116
|
+
polygon: Coordinates[];
|
|
117
|
+
/** POI 类型(可选),多个类型用 | 分隔 */
|
|
118
|
+
types?: string;
|
|
119
|
+
/** 每页记录数,默认 20,最大 50 */
|
|
120
|
+
pageSize?: number;
|
|
121
|
+
/** 当前页码,从 1 开始,默认 1 */
|
|
122
|
+
pageNum?: number;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 输入提示选项
|
|
127
|
+
*/
|
|
128
|
+
export interface InputTipsOptions {
|
|
129
|
+
/** 关键词 */
|
|
130
|
+
keyword: string;
|
|
131
|
+
/** 城市名称或城市编码(可选) */
|
|
132
|
+
city?: string;
|
|
133
|
+
/** POI 类型(可选),多个类型用 | 分隔 */
|
|
134
|
+
types?: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 输入提示结果
|
|
139
|
+
*/
|
|
140
|
+
export interface InputTip {
|
|
141
|
+
/** 提示 ID */
|
|
142
|
+
id: string;
|
|
143
|
+
/** 名称 */
|
|
144
|
+
name: string;
|
|
145
|
+
/** 地址 */
|
|
146
|
+
address: string;
|
|
147
|
+
/** 坐标(可能为空) */
|
|
148
|
+
location?: Coordinates;
|
|
149
|
+
/** 类型编码 */
|
|
150
|
+
typeCode?: string;
|
|
151
|
+
/** 城市名称 */
|
|
152
|
+
cityName?: string;
|
|
153
|
+
/** 区域名称 */
|
|
154
|
+
adName?: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 搜索结果
|
|
159
|
+
*/
|
|
160
|
+
export interface SearchResult {
|
|
161
|
+
/** POI 列表 */
|
|
162
|
+
pois: POI[];
|
|
163
|
+
/** 总记录数 */
|
|
164
|
+
total: number;
|
|
165
|
+
/** 当前页码 */
|
|
166
|
+
pageNum: number;
|
|
167
|
+
/** 每页记录数 */
|
|
168
|
+
pageSize: number;
|
|
169
|
+
/** 总页数 */
|
|
170
|
+
pageCount: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 输入提示结果
|
|
175
|
+
*/
|
|
176
|
+
export interface InputTipsResult {
|
|
177
|
+
/** 提示列表 */
|
|
178
|
+
tips: InputTip[];
|
|
179
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
import { requireNativeModule } from 'expo-modules-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 在加载原生搜索模块前,强制校验基础地图组件是否已安装。
|
|
6
|
+
* 支持两种“基础地图提供者”:expo-gaode-map 或 expo-gaode-map-navigation(导航内置地图)。
|
|
7
|
+
* 这样可避免导航与核心包的 SDK 冲突时无法使用搜索模块的问题。
|
|
8
|
+
*/
|
|
9
|
+
function ensureBaseInstalled() {
|
|
10
|
+
let installed = false;
|
|
11
|
+
try {
|
|
12
|
+
// 优先检测核心地图包
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
14
|
+
require('expo-gaode-map');
|
|
15
|
+
installed = true;
|
|
16
|
+
} catch (_) {
|
|
17
|
+
// 再尝试导航包(内置地图能力)
|
|
18
|
+
try {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20
|
+
require('expo-gaode-map-navigation');
|
|
21
|
+
installed = true;
|
|
22
|
+
} catch (_) {
|
|
23
|
+
installed = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!installed) {
|
|
28
|
+
const msg =
|
|
29
|
+
'[expo-gaode-map-search] 需要先安装基础地图组件,支持以下任一包:\n' +
|
|
30
|
+
' - expo-gaode-map(核心地图包),或\n' +
|
|
31
|
+
' - expo-gaode-map-navigation(导航包,内置地图能力)\n' +
|
|
32
|
+
'请先安装并完成原生配置后再重试。';
|
|
33
|
+
throw new Error(msg);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ensureBaseInstalled();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 高德地图搜索模块
|
|
41
|
+
*
|
|
42
|
+
* 提供 POI 搜索、周边搜索、沿途搜索、多边形搜索和输入提示功能
|
|
43
|
+
*/
|
|
44
|
+
const ExpoGaodeMapSearchModule = requireNativeModule('ExpoGaodeMapSearch');
|
|
45
|
+
|
|
46
|
+
export default ExpoGaodeMapSearchModule;
|