
别的不说高德地图这套 Android SDK前前后后我踩了不少坑。标题加粗写着“3D地图、定位、搜索、虚拟定位”我第一反应就是会不会又是某个需要“钉钉打卡”的项目后来想想虚拟定位这个能力在开发调试里确实太常用了尤其是做移动端巡检、LBS 社交、位置围栏测试的时候真要一台一台拿着设备到处跑开发效率就全毁了。所以我把这套东西完整摸了一遍从申请 Key 到地图显示、定位、POI 搜索再到模拟定位的调试方案串成一条龙写了这篇文章。这次我不打算只贴一堆 API 调用的截图而是把“为什么这样选型”“踩过哪些隐蔽的坑”“坐标偏差怎么回事”“虚拟定位到底是怎么实现的”这些东西一次性讲透。如果你正准备在 Android 项目里接入高德地图或者正在为“虚拟定位在地图 App 里不可用”而发愁那这篇文章正好适合你。内容偏向工程实操适合有 Android 基础、想快速落地地图功能的开发者阅读。1. 项目整体设计与实现思路先把这个项目到底在解决什么问题说清楚。标题表面上是“地图展示 定位 搜索 虚拟定位”但实际上可以拆成四层地图渲染层高德 3D 地图 SDK 负责把地图底图、标记点、缩放级别渲染出来。定位数据层高德定位 SDK 获取当前地理位置回传经纬度。POI 搜索层通过高德搜索 API 完成关键词检索、周边检索在地图上展示结果。调试测试层虚拟定位功能为开发者提供一套可注入定位数据的机制方便在不移动的情况下模拟位置变化。这四层之间是相互依赖的。地图渲染层需要坐标体系定位数据层提供坐标来源搜索层解决“想去哪”的问题而虚拟定位则直接影响定位数据层的可信度和可测性。把这四层放在一起就是一套完整的 LBS 基础设施。开发这套东西时我一直在想一个问题为什么是高德而不是百度或者腾讯这里有三点现实原因高德地图 SDK 的 3D 渲染效果很好它内置了 OpenGL 渲染引擎楼层、建筑轮廓、道路毛细血管的显示都比 2D 瓦片颗粒细腻。定位 SDK 和地图 SDK 配合度高都是同一家提供的坐标系内部一致不用像百度地图那样做 BD09 坐标转换。搜索能力完善高德的 POI 搜索覆盖率高城市检索、周边检索、输入提示都可以直接用。当然选高德也要接受它的技术债SDK 体积不小、部分接口命名混乱、文档更新不勤。这些问题后面我都会讲到。2. 高德地图 SDK 集成的完整流程集成高德地图之前先把账算清楚。高德开放平台提供了两个必须用到的 SDK地图 SDK3D版和定位 SDK另外项目里还需要用到搜索 SDK。这三个 SDK 分工明确必须全部下载打包时需要一起引入。2.1 注册开发者账号与申请 Key这个步骤虽然是基础中的基础但绝大多数定位问题都跟 Key 配置错误有关。在开始写任何代码之前请先登录 高德开放平台 完成以下操作注册并登录开发者账号实名认证。创建一个“应用”填好应用名称、应用类型。在应用详情里添加 Key选择“Android 平台”。填写发布版安全码 SHA1和调试版安全码 SHA1以及包名Package Name。申请完成后复制这个 Key 保存好。关于 SHA1我用个大多数人都经历过的场景来讲开发手机和发布签名是两回事。如果你在 Android Studio 里有多个签名配置debug.keystore 和 release.keystoreSHA1 必须区分对待。调试阶段用 debug 签名发布阶段用 release 签名如果没有把两个 SHA1 都加进高德后台定位、地图加载都容易报鉴权失败。怎么查看当前签名对应的 SHA1在 Android Studio 的 Terminal 里执行keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android如果你用的是自定义签名文件keytool -list -v -keystore your_release.jks -alias your_alias -storepass your_password把输出中的SHA1依次填入高德平台的“安全码 SHA1”字段这个步骤做好了后面几乎不会出现INVALID_USER_SCODE这类错误。2.2 Gradle 依赖配置高德 SDK 是从官网下载 jar 包/so 库的不是从 Maven Central 拉依赖。这一点和很多第三方库差距很大也是新手最容易卡住的地方。3D 地图 SDK 的下载包解压后包含一个AMap3DMap_xxx.jar和若干so目录armeabi-v7a、arm64-v8a、x86 等需要手动放进libs和jniLibs。在 Android Studio 里最干净的做法是把 jar 放进libsso 文件放进src/main/jniLibs/对应的 ABI 目录下然后在 module 的build.gradle里这样写android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { ndk { abiFilters arm64-v8a, armeabi-v7a } } } dependencies { implementation files(libs/AMap3DMap_xxx.jar) implementation files(libs/AMapLocation_xxx.jar) implementation files(libs/AMapSearch_xxx.jar) }高德官方文档里还有一句提示3D 地图 SDK 需要OpenGL ES 2.0以上所以最低 minSdkVersion 建议设置在 21 以上。如果你的项目还在用很低版本的 minSdk建议重新考虑一下。注意abiFilters可以显著减少 APK 体积也可以避免部分机型上 x86 模拟器崩溃的问题。但如果你要给模拟器调试用最好把 x86 也加进去或用 arm64 镜像的模拟器。在AndroidManifest.xml中要在application节点里配置 Key 和权限。权限方面除了网络权限还有几个容易漏uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.ACCESS_WIFI_STATE / uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE / uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE /Key 的配置很关键长这样meta-data android:namecom.amap.api.v2.apikey android:value你申请的Key /注意这个meta-data必须放在application内并且android:name千万不能拼错拼错就会找不到 Key后续定位、地图直接白屏。2.3 坐标系这个老生常谈的问题写高德地图不讲坐标系就是耍流氓。高德地图使用的是GCJ-02 火星坐标系也就是国家测绘局加密后的坐标而 GPS 原始坐标是WGS-84坐标系。两者之间最大可能偏移几百米。在 Android 里如果直接用LocationManager拿到的 GPS 经纬度传给高德会发现地图上的蓝点停在了大街上或者另外一条路旁。原因就是因为没有把 WGS-84 坐标转成 GCJ-02。高德的定位 SDK 拿到的是直接可用的坐标但虚拟定位如果注入的是原始 GPS 坐标就得自己做转换。转换逻辑可以参考业内的“坐标纠偏”实现本质是按照偏移公式计算偏移量。实际项目中我用的是比较成熟的方案public static double[] wgs84ToGcj02(double lat, double lon) { if (outOfChina(lat, lon)) { return new double[]{lat, lon}; } double dLat transformLat(lon - 105.0, lat - 35.0); double dLon transformLon(lon - 105.0, lat - 35.0); double radLat lat / 180.0 * Math.PI; double magic Math.sin(radLat); magic 1 - 0.00669342162296594323 * magic * magic; double sqrtMagic Math.sqrt(magic); dLat (dLat * 180.0) / ((6378245.0 * (1 - 0.00669342162296594323)) / (magic * sqrtMagic) * Math.PI); dLon (dLon * 180.0) / (6378245.0 / sqrtMagic * Math.cos(radLat) * Math.PI); return new double[]{lat dLat, lon dLon}; }这段代码你拿过去就能用。实际测试下来在室内定位时偏移明显室外空旷地方转换后基本能对上道路。3. 3D 地图、定位与搜索的核心实现这一部分是项目的主体。我按“地图先亮起来 → 定位点出现 → 搜索能用”这个顺序来讲这样你每完成一步都有可见的反馈排错也更方便。3.1 3D 地图的初始化与常见布局高德 3D 地图的显示组件有MapView和TextureMapView两种。区别在于TextureMapView是基于TextureView实现的可以嵌入到 ScrollView、RecyclerView 等场景中而MapView基于SurfaceView在 Android 7.0 以上系统上如果直接嵌入滚动容器容易出现黑屏或画面撕裂。我这里方案的推荐是如果是普通全屏地图用MapView如果是页面中嵌一块地图区域强烈建议用TextureMapView。在 XML 布局文件里的写法com.amap.api.maps.TextureMapView android:idid/map_view android:layout_widthmatch_parent android:layout_heightmatch_parent /Activity 中初始化public class MapActivity extends AppCompatActivity { private TextureMapView mapView; private AMap aMap; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map); mapView findViewById(R.id.map_view); mapView.onCreate(savedInstanceState); if (aMap null) { aMap mapView.getMap(); aMap.getUiSettings().setZoomControlsEnabled(false); aMap.getUiSettings().setCompassEnabled(true); aMap.moveCamera(CameraUpdateFactory.zoomTo(16f)); } } Override protected void onResume() { super.onResume(); mapView.onResume(); } Override protected void onPause() { super.onPause(); mapView.onPause(); } Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); } }这里有个重要细节mapView的生命周期方法必须和 Activity/Fragment 一一对应漏掉任何一个都会导致内存泄漏或地图异常。特别是onDestroy()不调用的话地图渲染线程不会释放。地图初始化完成后建议再设置一下AMap的属性setTrafficEnabled(boolean)实时路况开关看需求。setMapType(int)标准地图MAP_TYPE_NORMAL还是卫星图MAP_TYPE_SATELLITE。setMyLocationStyle自定义蓝点样式后面讲定位时会用到。3.2 定位功能的实现与参数调优高德定位 SDK 的使用方式很直接核心类是AMapLocationClient。但真正决定定位体验好坏的是它的AMapLocationClientOption参数。定位客户端初始化AMapLocationClient locationClient new AMapLocationClient(context); AMapLocationClientOption option new AMapLocationClientOption(); option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy); option.setInterval(2000); option.setOnceLocation(false); option.setNeedAddress(true); locationClient.setLocationOption(option); locationClient.setLocationListener(location - { if (location ! null) { if (location.getErrorCode() 0) { double lat location.getLatitude(); double lon location.getLongitude(); String address location.getAddress(); // 把定位结果展示到地图上 } else { Log.e(定位失败, error code: location.getErrorCode() , msg: location.getErrorInfo()); } } }); locationClient.startLocation();关于定位模式我实际测试下来有几点感受Hight_Accuracy模式优先 GPS 网络 基站综合定位冷启动可能 3 秒左右才出结果Battery_Saving模式以网络定位为主功耗低但精度差。如果你只是“点一下定位”建议设置setOnceLocation(true)能节约不少电量如果需要连续轨迹上报才设置setInterval(2000)这种短周期的轮询。定位结果里的getAddress()是高德自动反地理编码出来的如果你同时用搜索 SDK就不要额外再调一次反地理编码接口避免浪费流量。另外地图上的蓝点不要单独用 Marker 去画。高德地图提供了一个内置的“我的位置”图层把定位结果回填给 AMap 就能显示aMap.setMyLocationEnabled(true); aMap.setMyLocationStyle( new MyLocationStyle() .myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE) .interval(5000) );这里的LOCATION_TYPE_LOCATION_ROTATE表示蓝点会跟随设备方向旋转适合步行导航、车辆定位场景。如果只是展示固定点用LOCATION_TYPE_LOCATE更简洁。3.3 搜索功能的实现与结果展示高德的搜索 SDK一般用GeocodeSearch地理编码和PoiSearchPOI 搜索。标题里说的是“搜索”我更推荐直接用PoiSearch完成关键字搜索和周边搜索。POI 搜索的完整链路是设置查询参数 → 发起异步搜索 → 回调中处理结果 → 地图上添加 Marker。PoiSearch.Query query new PoiSearch.Query(keyword, , city); query.setPageSize(20); query.setPageNum(0); PoiSearch poiSearch new PoiSearch(context, query); poiSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() { Override public void onPoiSearched(PoiResult poiResult, int rCode) { if (rCode 1000 poiResult ! null) { ListPoiItem pois poiResult.getPois(); for (PoiItem poi : pois) { LatLng latLng new LatLng(poi.getLatLonPoint().getLatitude(), poi.getLatLonPoint().getLongitude()); MarkerOptions markerOptions new MarkerOptions() .position(latLng) .title(poi.getTitle()) .snippet(poi.getSnippet()); aMap.addMarker(markerOptions); } } } Override public void onPoiItemSearched(PoiItem poiItem, int i) { } }); poiSearch.searchPOIAsyn();这里面有几个容易踩的坑单独拎出来说PoiSearch.Query的city字段如果传null默认在全国范围搜索会导致结果不精确如果传一个城市名搜索范围会小很多。rCode 1000代表成功但如果你传入的 Key 无效或没有开通搜索服务它会返回1001或1004直接打印日志就能看出问题。搜索结果批量添加 Marker 时注意设置setAnchor()和setIcon()否则所有 Marker 都用默认红点视觉上很难区分。周边搜索POI 周边是另一个高频场景适合“搜附近加油站”“找附近停车场”。实现时需要传入中心坐标点PoiSearch.SearchBound bound new PoiSearch.SearchBound( new LatLng(centerLat, centerLon), 3000, true ); query.setBound(bound);这里的第三参数true表示“是否按距离排序”默认是综合排序。如果做“距离最近”类功能建议设为true。对于搜索结果的点击响应我一般给每个 Marker 设置AMap.OnMarkerClickListener点击时弹出详情或者跳到导航。初级开发者容易漏掉marker.setObject(poi)这个操作导致点击时拿不到对应的 POI 数据。aMap.setOnMarkerClickListener(marker - { PoiItem poi (PoiItem) marker.getObject(); if (poi ! null) { Toast.makeText(context, poi.getTitle(), Toast.LENGTH_SHORT).show(); } return false; });4. 虚拟定位模拟定位的实现原理与调试工具虚拟定位是个敏感又实用的功能。先说结论它在地图 SDK 层面并不难真正难的是让系统和高德定位 SDK 都“认账”。理解了定位数据流你就能自由控制这个功能。4.1 虚拟定位的本质是注入坐标数据高德定位 SDK 获取位置的底层来源包括 GPS 芯片、Wi-Fi 扫描、基站信息。虚拟定位要做的事情就是欺骗这些来源或者直接在高德拿到“位置”后把它替换掉。在 Android 系统层面常见的虚拟定位方案有三种开发者选项里开启“允许模拟位置”然后使用 Xposed/调试辅助工具注入位置。这类工具通过LocationManager.addTestProvider()和setTestProviderLocation()模拟 GPS 卫星数据系统级的 App如地图类拿到的就是模拟出来的经纬度。在 App 内直接集成模拟定位代码通过设置高德定位客户端的setMockEnable(true)来接收模拟位置。Hook 定位 SDK 的位置回调在拿到真实定位结果后替换经纬度再交给上层逻辑。对于开发人员来说最推荐在调试阶段使用“允许模拟位置 测试 Provider”这套正统方案。在 Android 的开发者选项中找到“选择模拟位置信息应用”把你自己写的模拟工具选上然后用下面的代码注入模拟位置LocationManager locationManager (LocationManager) getSystemService(LOCATION_SERVICE); locationManager.addTestProvider( LocationManager.GPS_PROVIDER, false, false, false, false, true, true, true, 0, 5 ); locationManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true); Location mockLocation new Location(LocationManager.GPS_PROVIDER); mockLocation.setLatitude(latitude); mockLocation.setLongitude(longitude); mockLocation.setAccuracy(5.0f); mockLocation.setTime(System.currentTimeMillis()); mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); locationManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, mockLocation);在代码里写完这个之后aMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(latitude, longitude)))就能把地图中心挪到模拟坐标上。此时只要高德定位 SDK 读取的是系统 GPS Provider 的数据它就会认为你就在这个地方。不过这里有一个非常隐蔽的问题高德定位 SDK 的Hight_Accuracy模式在室内或者信号差的地方不一定会优先使用GPS_PROVIDER它可能走的是网络定位通道。所以模拟位置必须同时影响网络定位和 GPS 定位或者在代码里直接把定位模式切成GPS_Only。4.2 虚拟定位的应用边界和合规提醒虽然标题里带“虚拟定位”但我必须把话说清楚这个能力最合理的用途是开发调试和自动化测试。比如测试围栏告警人不用真的走到某地就能验证位置触发逻辑。测试轨迹上传模拟一条路线验证轨迹平滑算法。测试高德地图在异地显示不同层级楼块、地标时表现是否正常。如果是把虚拟定位用于打卡、抢券、外勤签到等作弊场景属于违反各平台使用协议的行为轻则封号、冻结数据重则会有法律风险。我这边不建议在正式发布的 App 里内置这种功能更不建议开发专门的作弊工具。做技术的人应该明白边界在哪里。如果你确实需要在生产环境里做“伪定位”比如让员工在家完成外勤打卡验证请提前与业务方、法务方确认合规性并且在 App 内展示“本次位置为模拟位置”的显著提示。能让人一眼看出来的模拟比藏着掖着要稳妥得多。4.3 调试虚拟定位的实用建议虚拟定位功能在真机上调试时要注意以下几点模拟的精度不要设置成 0.0建议setAccuracy(5.0f)否则一些定位 SDK 会放弃该 Provider 的数据认为是无效信号。模拟坐标尽量选在真实存在的道路上。高德地图有地图围栏校验如果你把坐标放在太平洋中间定位 SDK 可能直接不回调或者返回错误码。模拟位置变化时要连续多次调用setTestProviderLocation每次间隔建议 500ms 以上太密集会让部分设备直接丢弃 Provider。高德 SDK 内部有自己的反作弊逻辑如果检测到位置状态异常比如从北京瞬间跳到上海即使调用了setMockEnable(true)回调也可能被标记为mockLocation。用高德定位 SDK 接收模拟位置需要在AMapLocationClientOption里显式开启option.setMockEnable(true);开了这个开关后系统传来的模拟位置通常会携带isFromMockProvider标记。高德定位结果里也有对应的标记字段可以判断。在调试阶段你可以把这个标记打在界面上用来确认“当前定位是否来自模拟器/模拟应用”。这在排查定位问题时非常好用。5. 常见问题排查与避坑经验汇总写高德地图最大的特点就是“编译能过运行炸裂”。各种问题在运行时才暴露。我把自己真实的踩坑记录整理成了表格方便你按症状去排查。5.1 Key 鉴权与地图白屏问题症状地图区域一片空白什么都没有。高德地图白屏99% 是 Key 或者权限的问题。按以下顺序排查确认 AndroidManifest 里的meta-data名称是com.amap.api.v2.apikey别写错。确认 Key 对应的包名和你运行 App 的包名一致。特别是多渠道打包时不同渠道包名不同Key 要分别配置。确认 SHA1 是否包含当前签名文件的 SHA1。你用 debug 包测试却只配了 release 的 SHA1必然白屏。检查网络权限。高德地图渲染需要动态下载瓦片如果应用禁网地图区域不会显示底图只有网格线。我自己遇到最头大的一个情况自定义了一个Application类在onCreate()里提前初始化了地图 SDK导致 Key 校验顺序错乱。高德的 SDK 初始化最好放在MainActivity或依赖注入框架中不要在冷启动阶段抢生命周期。5.2 定位失败或定位不准的问题定位不准的原因很多最普遍的还是坐标系问题。高德地图返回的经纬度可以直接用但如果你把经纬度转给百度或系统 API 用必须有坐标系转换。反之亦然。定位失败getErrorCode()不等于 0则常见于以下几种情况错误码含义解决建议12缺少定位权限检查运行时权限是否申请Android 6.0 要动态申请14定位失败尝试到室外空旷处检查是否开启了“模拟位置”但无模拟数据15网络定位失败确认设备能正常访问网络20Key 鉴权失败检查 SHA1、包名、Key 是否匹配30定位服务不可用检查高德定位 service 是否被系统杀掉了另外如果你把setInterval(2000)设得很短而手机息屏或者 App 在后台运行时高德定位可能导致功耗飙升。实测下来连续定位模式下一小时的耗电量大约在 5% 左右用setOnceLocation(true)可以省很多电。5.3 3D 地图卡顿与崩溃问题如果你发现地图旋转、放大时有明显卡顿先检查你是不是在 UI 线程里频繁添加了大量 Marker。地图 SDK 的渲染线程虽然是独立的但 Marker 数据同步是主线程操作。几千个 Marker 一次性塞进去卡是必然的。对策是用MarkerOptions分批添加或者改用Overlay聚合方案。聚合方案对于大量点位的展示特别有效高德官方提供的ClusterOverlay可以直接用前提是额外引入高德地图工具 jar。崩溃问题通常出现在 so 库加载失败时。比较典型的报错是java.lang.UnsatisfiedLinkError: dlopen failed: library libamapv303.so not found原因是 ABI 不匹配。你只放入了 arm64-v8a 的 so却在 x86 模拟器上运行自然找不到库。解决方式是使用abiFilters声明并且确保jniLibs目录下的 so 文件夹名称严格是armeabi-v7a、arm64-v8a、x86这些标准名称。高德官方文档建议不要用arm64这种缩写名称。5.4 混淆导致的编译失败问题如果你的项目开启了代码混淆记住给高德 SDK 添加 keep 规则。不添加的话运行时会莫名出现类找不到、字段为空等诡异问题。-keep class com.amap.api.**{*;} -keep class com.autonavi.**{*;} -keep class com.loc.**{*;} -keep class com.amap.api.services.**{*;} -dontwarn com.amap.api.**高德官方提供的混淆规则基本就是这几行。需要注意的是com.autonavi和com.loc这两个包是 SDK 内部的底层包很多人会漏掉com.loc导致定位导航功能在 release 包时突然失效。5.5 关于高德渠道号的补充说明热词里出现“高德地图渠道号 c04030322001”这个渠道号其实是高德 SDK 上报时用于标记应用来源的信息。正常情况下你不用手动去配这个渠道号它由 SDK 根据应用构建时的高德 Key 自动生成。如果你在日志里看到类似channel: c04030322001的信息那是 SDK 自己的上报行为和业务逻辑无关。有些定制系统会误报为“异常应用外联”那是因为设备系统扫描到了地图 SDK 的网络上报行为不用太担心。如果你需要关闭高德地图 SDK 的日志显示避免泄露敏感信息可以在初始化时设置AMap.setLogEnable(false);这个建议在 release 包中一定要做否则日志中会输出完整的请求参数包括经纬度。6. 项目扩展与后续优化建议这套地图能力已经能支撑大部分业务场景了但它不是终点。我实际使用下来有下面几个后续可以扩展的方向。路线规划与导航高德搜索不只是 POI 搜索还有路径规划接口支持驾车、步行、公交。标题里没提但“定位 搜索”天然适合接路径规划比如用户搜到目的地后直接给出导航路线。公交路线规划在通勤类产品里非常有用返回的步行路段还能在地图上画折线。多地图源轮换高德地图瓦片虽然加载快但国内地图厂商对“瓦片数据二次加工”有一堆限制如果你要把地图数据用于科研分析可以研究一下如何在 QGIS 里导入高德瓦片作为底图。这个我在副业里试过用瓦片加载插件就能做到但要注意只能在本地研究中用不能公开传播脱敏后的地形数据。自定义离线地图高德地图 SDK 支持离线地图下载管理。对信号弱或者海外使用的场景可以集成离线地图包避免地图区域空白。动态加载 Marker 管理搜索页面如果开设了“附近交友”“附近店铺”功能会有大量实时变动的 Marker建议引入 LBS marker 聚合框架否则地图会很卡。我个人在项目里最受益的一个优化是把高德地图的实例AMap封装成了单例管理器地图生命周期和业务页面解耦。这样所有页面共享同一个AMap既有定位、又有搜索、还支持虚拟定位开关不会在页面切换时反复创建地图引擎。这种做法在做小程序内嵌地图时也能复用思路。最后聊一个容易忽略的点高德地图 SDK 的体积。3D 地图 SDK 定位 SDK 搜索 SDKrelease 包在小项上会增加大约 10 MB。如果在乎包体积建议使用abiFilters裁剪如果工程对包体积很敏感也可以考虑用高德的“轻量版”地图2D 渲染体积更小代价是 3D 楼层效果和动效就没有了。我自己的观点是做 LBS 产品3D 地图是加分项但如果核心功能是“看一眼位置”2D 轻量版反而更快更稳。如果你也正在做这种“地图 定位 搜索 模拟”组合的功能欢迎在实践中按我的思路去搭应该能少走不少弯路。我踩过的坑你都看得到剩下的路就顺畅多了。