# AMap Flutter Search - 高德地图搜索插件 ## 模块概述 `amap_flutter_search` 是 OneApp 中基于高德地图 SDK 的搜索服务插件,提供了全面的地理信息搜索功能,包括 POI 搜索、路线规划、地址解析等服务。该插件为车辆导航、位置查找、路径规划等功能提供了强大的搜索能力支持。 ## 核心功能 ### 1. POI 搜索 - **关键词搜索**:基于关键词的兴趣点搜索 - **周边搜索**:指定位置周边的 POI 搜索 - **分类搜索**:按类别筛选的 POI 搜索 - **详情查询**:获取 POI 的详细信息 ### 2. 路线规划 - **驾车路线**:多种驾车路径规划策略 - **步行路线**:行人路径规划 - **骑行路线**:骑行路径规划 - **公交路线**:公共交通路径规划 - **货车路线**:货车专用路径规划 ### 3. 地址解析 - **地理编码**:地址转换为坐标 - **逆地理编码**:坐标转换为地址 - **输入提示**:地址输入智能提示 - **行政区查询**:行政区域信息查询 ### 4. 距离计算 - **直线距离**:两点间直线距离计算 - **驾车距离**:实际驾车距离和时间 - **步行距离**:步行距离和时间 - **批量计算**:批量距离矩阵计算 ## 技术架构 ### 架构设计 ``` ┌─────────────────────────────────────┐ │ 应用层 │ │ (app_navigation, app_car) │ ├─────────────────────────────────────┤ │ AMap Flutter Search │ │ ┌──────────┬──────────┬──────────┐ │ │ │ POI搜索 │ 路线规划 │ 地址解析 │ │ │ ├──────────┼──────────┼──────────┤ │ │ │ 距离计算 │ 缓存管理 │ 数据处理 │ │ │ └──────────┴──────────┴──────────┘ │ ├─────────────────────────────────────┤ │ 高德地图 Search SDK │ │ ┌──────────┬──────────┬──────────┐ │ │ │ Android │ iOS │ 搜索引擎 │ │ │ └──────────┴──────────┴──────────┘ │ ├─────────────────────────────────────┤ │ 网络服务层 │ │ (REST API, WebService) │ └─────────────────────────────────────┘ ``` ### 核心组件 #### 1. POI 搜索管理器 (PoiSearchManager) ```dart class AMapPoiSearchManager { // 关键词搜索 Future searchByKeyword(PoiKeywordSearchOption option); // 周边搜索 Future searchNearby(PoiNearbySearchOption option); // ID 搜索 Future searchById(String poiId); // 分类搜索 Future searchByCategory(PoiCategorySearchOption option); } ``` #### 2. 路线规划管理器 (RouteSearchManager) ```dart class AMapRouteSearchManager { // 驾车路线规划 Future calculateDriveRoute(DriveRouteQuery query); // 步行路线规划 Future calculateWalkRoute(WalkRouteQuery query); // 骑行路线规划 Future calculateRideRoute(RideRouteQuery query); // 公交路线规划 Future calculateBusRoute(BusRouteQuery query); // 货车路线规划 Future calculateTruckRoute(TruckRouteQuery query); } ``` #### 3. 地理编码管理器 (GeocodeManager) ```dart class AMapGeocodeManager { // 地理编码 Future geocode(GeocodeQuery query); // 逆地理编码 Future reverseGeocode(RegeocodeQuery query); // 输入提示 Future> inputTips(InputTipsQuery query); // 行政区查询 Future searchDistrict(DistrictQuery query); } ``` #### 4. 距离计算器 (DistanceCalculator) ```dart class AMapDistanceCalculator { // 计算两点距离 Future calculateDistance(DistanceQuery query); // 批量距离计算 Future> calculateDistances(List queries); // 路径距离计算 Future calculateRouteDistance(RouteDistanceQuery query); } ``` ## 数据模型 ### POI 模型 ```dart class PoiItem { final String poiId; // POI ID final String title; // POI 名称 final String snippet; // POI 描述 final LatLng latLng; // POI 坐标 final String distance; // 距离 final String tel; // 电话 final String postcode; // 邮编 final String website; // 网站 final String email; // 邮箱 final String province; // 省份 final String city; // 城市 final String district; // 区县 final String address; // 地址 final String direction; // 方向 final String businessArea; // 商圈 final String typeCode; // 类型编码 final String typeDes; // 类型描述 final List photos; // 照片列表 final List shopID; // 商铺ID final IndoorData indoorData; // 室内数据 } class PoiResult { final List pois; final int pageCount; final int totalCount; final SearchBound searchBound; final PoiQuery query; } ``` ### 路线模型 ```dart class DriveRouteResult { final List paths; final RouteQuery startPos; final RouteQuery targetPos; final List viaPoints; final int taxiCost; } class DrivePath { final String strategy; // 策略 final int distance; // 距离(米) final int duration; // 时长(秒) final String tolls; // 过路费 final String tollDistance; // 收费距离 final String totalTrafficLights; // 红绿灯数 final List steps; // 路径段 final List tmcs; // 路况信息 } class DriveStep { final String instruction; // 行驶指示 final String orientation; // 方向 final String road; // 道路名称 final int distance; // 距离 final int duration; // 时长 final List polyline; // 路径坐标 final String action; // 导航动作 final String assistantAction; // 辅助动作 } ``` ### 地址模型 ```dart class RegeocodeResult { final RegeocodeAddress regeocodeAddress; final List pois; final List roads; final List roadInters; final List aois; } class RegeocodeAddress { final String formattedAddress; // 格式化地址 final String country; // 国家 final String province; // 省份 final String city; // 城市 final String district; // 区县 final String township; // 乡镇 final String neighborhood; // 社区 final String building; // 建筑 final String adcode; // 区域编码 final String citycode; // 城市编码 final List streetNumbers; // 门牌信息 } ``` ## API 接口 ### POI 搜索接口 ```dart abstract class PoiSearchService { // 关键词搜索 Future> searchByKeyword(PoiKeywordSearchRequest request); // 周边搜索 Future> searchNearby(PoiNearbySearchRequest request); // 多边形搜索 Future> searchInPolygon(PoiPolygonSearchRequest request); // POI 详情 Future> getPoiDetail(String poiId); } ``` ### 路线规划接口 ```dart abstract class RouteSearchService { // 驾车路线规划 Future> planDriveRoute(DriveRouteRequest request); // 步行路线规划 Future> planWalkRoute(WalkRouteRequest request); // 骑行路线规划 Future> planRideRoute(RideRouteRequest request); // 公交路线规划 Future> planBusRoute(BusRouteRequest request); } ``` ### 地理编码接口 ```dart abstract class GeocodeService { // 地理编码 Future> geocode(GeocodeRequest request); // 逆地理编码 Future> reverseGeocode(RegeocodeRequest request); // 输入提示 Future>> getInputTips(InputTipsRequest request); // 行政区搜索 Future> searchDistrict(DistrictRequest request); } ``` ## 配置管理 ### 搜索配置 ```dart class SearchConfig { final String apiKey; // API 密钥 final int timeoutMs; // 超时时间 final int maxRetries; // 最大重试次数 final bool enableCache; // 是否启用缓存 final int cacheExpireTime; // 缓存过期时间 final String language; // 语言设置 final String region; // 区域设置 static const SearchConfig defaultConfig = SearchConfig( apiKey: '', timeoutMs: 30000, maxRetries: 3, enableCache: true, cacheExpireTime: 3600, language: 'zh-CN', region: 'CN', ); } ``` ### POI 搜索配置 ```dart class PoiSearchConfig { final int pageSize; // 每页结果数 final int maxPage; // 最大页数 final String city; // 搜索城市 final String types; // 搜索类型 final bool extensions; // 是否返回扩展信息 final String sortrule; // 排序规则 static const PoiSearchConfig defaultConfig = PoiSearchConfig( pageSize: 20, maxPage: 100, city: '', types: '', extensions: false, sortrule: 'distance', ); } ``` ## 使用示例 ### POI 搜索示例 ```dart // 关键词搜索 final searchOption = PoiKeywordSearchOption( keyword: '加油站', city: '北京', pageSize: 20, pageNum: 1, extensions: true, ); final poiResult = await AMapPoiSearchManager.instance.searchByKeyword(searchOption); for (final poi in poiResult.pois) { print('POI 名称: ${poi.title}'); print('POI 地址: ${poi.address}'); print('POI 距离: ${poi.distance}'); print('POI 坐标: ${poi.latLng.latitude}, ${poi.latLng.longitude}'); } ``` ### 周边搜索示例 ```dart // 周边搜索 final nearbyOption = PoiNearbySearchOption( keyword: '餐厅', center: LatLng(39.9042, 116.4074), // 搜索中心点 radius: 1000, // 搜索半径 1000 米 pageSize: 10, pageNum: 1, ); final nearbyResult = await AMapPoiSearchManager.instance.searchNearby(nearbyOption); print('附近餐厅数量: ${nearbyResult.pois.length}'); for (final restaurant in nearbyResult.pois) { print('餐厅: ${restaurant.title} - ${restaurant.distance}'); } ``` ### 路线规划示例 ```dart // 驾车路线规划 final driveQuery = DriveRouteQuery( fromPoint: RouteQuery(39.9042, 116.4074), // 起点 toPoint: RouteQuery(39.9015, 116.3974), // 终点 mode: DriveMode.fastest, // 最快路线 avoidhighspeed: false, // 不避开高速 avoidtolls: false, // 不避开收费 avoidtrafficjam: true, // 避开拥堵 ); final driveResult = await AMapRouteSearchManager.instance.calculateDriveRoute(driveQuery); if (driveResult.paths.isNotEmpty) { final path = driveResult.paths.first; print('驾车距离: ${path.distance} 米'); print('预计时间: ${path.duration} 秒'); print('过路费: ${path.tolls} 元'); for (final step in path.steps) { print('导航指示: ${step.instruction}'); print('道路: ${step.road}'); print('距离: ${step.distance} 米'); } } ``` ### 地理编码示例 ```dart // 地址转坐标 final geocodeQuery = GeocodeQuery( locationName: '北京市朝阳区望京SOHO', city: '北京', ); final geocodeResult = await AMapGeocodeManager.instance.geocode(geocodeQuery); if (geocodeResult.geocodeAddressList.isNotEmpty) { final address = geocodeResult.geocodeAddressList.first; print('地址坐标: ${address.latLonPoint.latitude}, ${address.latLonPoint.longitude}'); } // 坐标转地址 final regeocodeQuery = RegeocodeQuery( latLonPoint: LatLng(39.9915, 116.4684), radius: 200.0, extensions: 'all', ); final regeocodeResult = await AMapGeocodeManager.instance.reverseGeocode(regeocodeQuery); print('格式化地址: ${regeocodeResult.regeocodeAddress.formattedAddress}'); ``` ### 输入提示示例 ```dart // 地址输入提示 final tipsQuery = InputTipsQuery( keyword: '王府井', city: '北京', datatype: 'all', ); final tipsList = await AMapGeocodeManager.instance.inputTips(tipsQuery); for (final tip in tipsList) { print('提示: ${tip.name}'); print('地址: ${tip.address}'); if (tip.point != null) { print('坐标: ${tip.point!.latitude}, ${tip.point!.longitude}'); } } ``` ## 测试策略 ### 单元测试 ```dart group('AMapSearch Tests', () { test('should search POI by keyword', () async { // Given final searchOption = PoiKeywordSearchOption( keyword: '测试POI', city: '北京', ); // When final result = await AMapPoiSearchManager.instance.searchByKeyword(searchOption); // Then expect(result.pois, isNotEmpty); expect(result.pois.first.title, contains('测试POI')); }); test('should calculate drive route', () async { // Given final query = DriveRouteQuery( fromPoint: RouteQuery(39.9042, 116.4074), toPoint: RouteQuery(39.9015, 116.3974), ); // When final result = await AMapRouteSearchManager.instance.calculateDriveRoute(query); // Then expect(result.paths, isNotEmpty); expect(result.paths.first.distance, greaterThan(0)); }); }); ``` ### 集成测试 ```dart group('Search Integration Tests', () { testWidgets('complete search flow', (tester) async { // 1. 搜索 POI final pois = await searchNearbyPois('加油站', currentLocation); // 2. 选择目标 POI final targetPoi = pois.first; // 3. 规划路线 final route = await planRouteToDestination(currentLocation, targetPoi.latLng); // 4. 验证结果 expect(route.paths, isNotEmpty); expect(route.paths.first.steps, isNotEmpty); }); }); ``` ## 性能优化 ### 搜索优化 - **搜索缓存**:缓存常用搜索结果 - **预测搜索**:基于历史预测用户搜索 - **分页加载**:大结果集分页加载 - **搜索建议**:智能搜索建议减少请求 ### 路线优化 - **路线缓存**:缓存常用路线规划结果 - **增量更新**:只更新路线变化部分 - **压缩传输**:压缩路线数据减少传输量 - **多线程处理**:并行处理多个路线请求 ## 错误处理 ### 搜索错误类型 ```dart enum SearchErrorType { networkError, // 网络错误 apiKeyInvalid, // API Key 无效 quotaExceeded, // 配额超限 invalidParameter, // 参数无效 noResult, // 无搜索结果 serverError, // 服务器错误 timeout // 请求超时 } class SearchException implements Exception { final SearchErrorType type; final String message; final int? errorCode; const SearchException(this.type, this.message, [this.errorCode]); } ``` ### 错误处理示例 ```dart try { final result = await AMapPoiSearchManager.instance.searchByKeyword(searchOption); // 处理搜索结果 } on SearchException catch (e) { switch (e.type) { case SearchErrorType.networkError: showErrorDialog('网络连接失败,请检查网络设置'); break; case SearchErrorType.noResult: showInfoDialog('未找到相关结果,请尝试其他关键词'); break; case SearchErrorType.quotaExceeded: showErrorDialog('搜索次数已达上限,请稍后再试'); break; default: showErrorDialog('搜索失败: ${e.message}'); } } catch (e) { showErrorDialog('未知错误: $e'); } ``` ## 缓存策略 ### 搜索结果缓存 ```dart class SearchCache { static const int maxCacheSize = 1000; static const Duration cacheExpiration = Duration(hours: 1); // 缓存 POI 搜索结果 static Future cachePoiResult(String key, PoiResult result); // 获取缓存的 POI 结果 static Future getCachedPoiResult(String key); // 缓存路线规划结果 static Future cacheRouteResult(String key, DriveRouteResult result); // 获取缓存的路线结果 static Future getCachedRouteResult(String key); // 清理过期缓存 static Future cleanExpiredCache(); } ``` ## 配额管理 ### API 配额监控 ```dart class QuotaManager { // 获取当前配额使用情况 static Future getCurrentQuota(); // 检查是否可以发起请求 static Future canMakeRequest(RequestType type); // 记录请求使用 static Future recordRequest(RequestType type); // 获取配额重置时间 static Future getQuotaResetTime(); } class QuotaInfo { final int dailyLimit; // 日限额 final int dailyUsed; // 日使用量 final int monthlyLimit; // 月限额 final int monthlyUsed; // 月使用量 final DateTime resetTime; // 重置时间 } ``` ## 版本历史 ### v3.1.22+1 (当前版本) - 支持最新的高德地图 API - 新增货车路线规划功能 - 优化搜索性能和准确性 - 修复路线规划稳定性问题 ### v3.1.21 - 支持室内 POI 搜索 - 新增批量距离计算 - 优化内存使用 - 改进错误处理机制 ## 依赖关系 ### 内部依赖 - `amap_flutter_base`: 高德地图基础库 - `basic_network`: 网络请求服务 - `basic_storage`: 本地存储服务 ### 外部依赖 - `dio`: HTTP 客户端 - `cached_network_image`: 图片缓存 - `sqflite`: 本地数据库 ## 总结 `amap_flutter_search` 作为高德地图搜索服务的 Flutter 插件,为 OneApp 提供了全面的地理信息搜索能力。通过集成 POI 搜索、路线规划、地理编码、距离计算等功能,该插件能够满足车辆导航、位置服务、路径规划等多种业务需求。 插件在设计上充分考虑了性能优化、缓存管理、错误处理、配额控制等关键因素,确保在提供高质量搜索服务的同时,保持良好的用户体验和系统稳定性。这为 OneApp 的车联网和导航服务提供了强大的技术支撑。