ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Android Studio集成百度地图SDK:从AK申请到生命周期管理的避坑指南

Android Studio集成百度地图SDK:从AK申请到生命周期管理的避坑指南 简介面向Android开发者的百度地图SDK集成学习包以Android Studio项目为背景完整覆盖依赖库引入、API密钥申请、Manifest权限配置、MapView初始化、定位服务开启、地图事件监听、标记绘制和Activity生命周期资源释放等关键步骤并补充了白屏排查、定位不生效等常见问题的处理思路适合刚接触地图功能或需要快速搭建地图模块的移动端开发者。压缩包共759个文件以xml配置与布局、flat编译资源、so动态库、jar依赖和json数据为主要类型整体大小约232.89MB解压后保留了可参考的工程结构、Gradle构建配置、示例代码与地图相关资源便于对照说明逐步实践也可作为项目模板快速复用。截至目前已有1151人学习下载能够帮助开发者在短时间内完成从环境配置、地图展示到基础交互的完整集成流程。1. Android Studio 集成百度地图 SDK为什么地图显示是最容易的一步做 Android 地图开发最难的不是把地图显示出来而是处理好 Key 校验、包名匹配和依赖冲突这三件事。很多人在 Android Studio 里集成百度地图 SDK折腾半天只看到一个灰色网格或者 Authentication Error 的弹窗问题往往不在代码而在配置。这篇笔记用一个最小可运行的项目把「申请 AK → 配置工程 → 显示地图 → 排查问题」整条链路走通适合刚接触地图开发、或者已经在官方文档里绕晕了的从业者。看完你能回答三个问题AK 到底怎么配才不会鉴权失败、为什么有人改个包名就崩、地图显示出来之后生命周期的坑在哪。2. 准备工作AK 申请与 SDK 获取这是鉴权的地基2.1 百度地图开放平台的 AK 申请流程与 SHA1 的获取方法集成百度地图 SDK 的第一步不是写代码而是去百度地图开放平台创建一个应用拿到 Access Token简称 AK。这个 AK 是客户端请求地图服务的凭证申请页面会让你填应用名称、应用类型Android SDK、包名和 SHA1 签名指纹。这里有个很容易翻车的细节包名和 SHA1 必须和你最终打包签名用的证书严格一致否则地图加载时会直接鉴权失败。SHA1 的获取分两种情况。如果你只是在 Android Studio 里跑 debug 包用的是默认的 debug keystore命令是keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android如果你打的是 release 包得用你自己的签名证书keytool -list -v -keystore your_release_keystore.jks -alias your_alias执行后会输出一大段证书信息找到 SHA1 那一行形如SHA1: 9B:7C:0D:...把冒号去掉再填入开放平台。注意开放平台里的包名是应用的 applicationId不是 namespace也不是代码里的 package 关键字这个我后面在避坑章节还要再强调。申请完成后你会得到一个类似xxxxx-xxxxx-xxxxx格式的 AK把它复制到项目配置文件里。这里要特别提醒AK 是明文写在客户端里的任何人都能通过反编译拿到所以百度地图 SDK 的鉴权只保证地图服务不被随意调用但它无法防止别人拿到你的 AK 去请求配额。上线前可以到开放平台设置 IP 白名单或者开启服务端鉴权免费版配额烧完之前就要意识到这个问题。2.2 两种接入方式的选型传统 jar/so 与 Maven 依赖的取舍百度地图 SDK 的接入方式有两种一种是从开放平台下载 zip 包里面包含 BaiduLBS_AndroidSDK_Lib 的 jar 和若干 .so 文件手动拷进工程的 libs 目录另一种是在 Gradle 里声明 Maven 依赖。从维护成本来看我一般会推荐新手直接走 Maven 依赖原因有三个不用手动管 .so 的 ABI 目录结构、版本升级只改一个版本号、不容易漏掉 so 文件导致 UnsatisfiedLinkError。Maven 方式的核心配置就一段// 在项目根 build.gradle 的 allprojects.repositories 里加 maven { url https://mapapi.bdstatic.com/maven } // 在 app/build.gradle 的 dependencies 里加 implementation com.baidu.lbs:BaiduLBS_Android:7.5.9这段配置里仓库地址固定指向百度的 Maven 服务器千万别漏掉这一步否则 Gradle 会报 Could not find com.baidu.lbs:。版本号7.5.9是我写这篇文章时的版本不等同于最新版建议你集成前在开放平台看下当前 release 版本号并把 minSdkVersion 至少设到 21。如果你要做的是轻量地图展示基础版 SDK 就够了不需要引入检索、导航这些模块减少包体积和权限声明。如果你的项目里已经有老版本的手动集成方式想切成 Maven记得先删掉 libs 下的 BaiduLBS_Android 相关 jar 和 jniLibs 里对应的 .so 目录否则会出现类重复定义构建直接报错。两种方式共存是集成阶段最常见的依赖冲突来源后面避坑章节会单独说。3. 工程配置Gradle 依赖、权限声明与 AndroidManifest 的完整配置3.1 Gradle 依赖引入与 buildConfigField 配置 AK依赖声明只是第一步关键是把 AK 写进 AndroidManifest 的meta-data标签里。顺手的事情在 build.gradle 里用 buildConfigField 生成一个 BuildConfig.API_KEY 字段代码里就引用同一个常量而不是把字符串写死在 Java 文件里以后要换 Key 只用改一处。完整的 app/build.gradle 配置长这样android { defaultConfig { applicationId com.example.mapdemo minSdkVersion 21 targetSdkVersion 34 // 生成 BuildConfig.API_KEY 常量值从 gradle.properties 读取 buildConfigField String, API_KEY, \${BAIDU_MAP_AK}\ } buildTypes { debug { // 如果 debug 和 release 用了同一个 key这里可以不配 } release { minifyEnabled false // 这里配你的 release 签名 } } }上面的配置里BAIDU_MAP_AK要在项目根目录的 gradle.properties 里定义BAIDU_MAP_AK你的AK值这么做的好处是避免把 AK 提交到 GitHub泄漏之后被爬虫扫到拿去刷你的配额。注意buildConfigField只能读到 String 类型所以写法是双引号包字符串字面量如果你用的是 AGP 8.0 以上版本还要在 defaultConfig 里显式开启buildFeatures { buildConfig true }否则 BuildConfig 类不会生成编译直接报找不到符号。3.2 AndroidManifest 的权限声明与 meta-data 的坑在 AndroidManifest.xml 里需要声明三类东西SDK 运行必需的权限、AK 的 meta-data 标签、以及 SDK 组件所需的 service。直接贴配置逐行说明!-- 网络访问与定位权限地图加载必需 -- uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION / uses-permission android:nameandroid.permission.ACCESS_FINE_LOCATION / application !-- 子标签必须在 application 内部且写在 activity 之前或之后都不影响 -- meta-data android:namecom.baidu.lbsapi.API_KEY android:value${MAP_AK} / !-- SDK 内部定位服务不声明会崩溃 -- service android:namecom.baidu.location.f android:enabledtrue android:process:remote / /application这段里的meta-data是鉴权的核心。它的android:name必须是com.baidu.lbsapi.API_KEY一个字符都不能错android:value我用了${MAP_AK}这种占位符写法对应的需要在 app/build.gradle 的 defaultConfig 或者 manifestPlaceholders 里指定defaultConfig { manifestPlaceholders [MAP_AK: ${BAIDU_MAP_AK}] }用占位符的好处是 debug 和 release 可以切不同的 AK。但这里要注意一个顺序问题如果 gradle.properties 里没有定义BAIDU_MAP_AKGradle 的占位符解析期就会报错报错信息是Manifest placeholder substitution failed而不是运行期鉴权失败。所以配好工程后先构建一次确认能通过再写 Java 代码。3.3 动态权限申请Android 6.0 以上必须处理运行时权限ACCESS_FINE_LOCATION和ACCESS_COARSE_LOCATION属于危险权限光写在 Manifest 里不够必须在代码里动态申请。常见做法是在 Activity 的 onCreate 里检查并申请权限不申请的话后续调用BDLocationClient.start()会直接抛 SecurityException。我一般用同一段模板处理if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) ! PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION); }有从业者会问如果只是显示地图不做定位是不是可以不申请定位权限答案是可以不申请ACCESS_FINE_LOCATION但强烈建议保留ACCESS_NETWORK_STATE和INTERNET。因为百度地图在加载瓦片时需要联网没有网络权限会显示空白地图。至于定位权限后续如果引入百度定位 SDK就需要ACCESS_FINE_LOCATION没有动态申请会直接闪退。4. 最小代码跑通MapView 控件与 SDK 初始化的完整写法4.1 Application 初始化与 setAgreePrivacy 的调用时机百度地图 7.5 以上的版本加入了隐私合规接口不调用setAgreePrivacy就初始化 SDK会弹一个Privacy error的异常提示。这个接口必须在初始化前调用顺序错了直接初始化失败。我一般在 Application 的 onCreate 里处理这两件事public class MapApplication extends Application { Override public void onCreate() { super.onCreate(); // 同意隐私政策需要在 SDKInitializer.initialize 之前调用 com.baidu.mapapi.CoordType.setType(com.baidu.mapapi.CoordType.BD09LL); MapSDKLocation.setAgreePrivacy(true); SDKInitializer.setAgreePrivacy(getApplicationContext(), true); SDKInitializer.initialize(this); } }这段代码里有三个方法值得细说。CoordType.setType(BD09LL)是设置坐标类型大多数场景用 BD09LL即百度经纬度坐标系如果你接的是真实 GPS 定位数据后续还需要用CoordinateConverter做坐标转换。SDKInitializer.setAgreePrivacy是隐私授权接口需要在initialize之前调用否则初始化失败或地图无法显示。SDKInitializer.initialize内部会异步初始化一些全局资源它只返回一个void或抛出异常具体表现取决于版本。初始化代码写在 Application 里可以保证 Activity 创建 MapView 时 SDK 已经就绪避免首次打开地图时黑屏等资源加载问题。这是官方文档一直强调的写法也是我实际开发中踩过坑之后固定下来的习惯。注意Application 必须注册到 Manifest 里漏掉注册的话MapApplication不会执行运行期会直接出现ClassNotFoundException或者初始化失败。4.2 XML 布局与 Activity 中 MapView 的生命周期闭环地图控件的使用方式有两种XML 引入和代码动态创建。我推荐 XML 方式因为布局清晰好维护。layout 的写法如下RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent com.baidu.mapapi.map.MapView android:idid/bmapView android:layout_widthmatch_parent android:layout_heightmatch_parent android:clickabletrue / /RelativeLayout对应的 Activity 里关键代码是生命周期绑定。地图控件比普通 View 多一套内存管理机制Activity 的 onResume、onPause、onDestroy 三个方法必须都转发给 MapView否则轻则地图停止刷新重则内存泄漏甚至崩溃public class MainActivity extends AppCompatActivity { private MapView mMapView; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mMapView findViewById(R.id.bmapView); // 获取地图控制器用来设置中心点和缩放级别 BaiduMap baiduMap mMapView.getMap(); MapStatusUpdate status MapStatusUpdateFactory.newLatLngZoom( new LatLng(39.914846, 116.403881), 16); baiduMap.animateMapStatus(status); } Override protected void onResume() { super.onResume(); mMapView.onResume(); } Override protected void onPause() { super.onPause(); mMapView.onPause(); } Override protected void onDestroy() { super.onDestroy(); mMapView.onDestroy(); mMapView null; } }newLatLngZoom的两个参数第一个是经纬度第二个是缩放级别官方范围是 3 到 21。16 级在城市道路场景下能清晰看到街道和建筑名称如果你只需要省市级别设 10 或 11 就够了。这里有个新手常犯的错误只写了 onCreate 里的初始化忘了 onResume 和 onPause 的转发表现为切到后台再回前台地图瓦片不再加载或者直接出现黑屏。还有人在 onDestroy 里没有置空mMapView导致 Activity 销毁时内存无法回收反复横跳页面后内存溢出。4.3 显示效果的参数调节Build 模式与现有地图类型选择BaiduMap 本身提供了多种地图模式最常见的地图类型有普通地图MapType.NORMAL、卫星地图MapType.SATELLITE和空白地图MapType.NONE。以实时路况展示为例可以通过下面的代码切换baiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE); // 开启交通流量图 baiduMap.setTrafficEnabled(true); // 开启热力图人口密度可视化 baiduMap.setBaiduHeatMapEnabled(false);这几个开关按需开启。setTrafficEnabled(true)会请求路况瓦片密密麻麻的彩色线条叠在地图上setBaiduHeatMapEnabled(true)开启热力图后需要加载个性化瓦片打开后帧率会明显下降。如果只是做车辆轨迹展示没必要同时开热力图和路况二选一即可。缩放级别也可以用MapStatusUpdateFactory.zoomTo(float)动态调整它和newLatLngZoom的区别是前者只改缩放级别不改中心点。5. 避坑指南鉴权失败、包名变更、构建冲突的 5 个典型现场5.1 现象「Authentication Error」弹窗地图灰屏这个现象几乎每个集成百度地图的开发者都见过。弹窗提示鉴权失败原因分三种AK 不存在、包名不一致、SHA1 不一致。排查顺序我建议倒着来先确认代码里的 AK 和开放平台一致再看 AndroidManifest 的 meta-data 的 key 名是否拼写正确最后核对包名和 SHA1。其中一个容易忽略的细节就是 release 包的签名问题debug 模式调试得好好的一打 release 包就弹鉴权错误原因是 release 用的签名证书和开放平台填的 SHA1 不是同一个。解决方案是在开放平台同时填 debug 和 release 两个 SHA1或者把 release 签名配置到 build.gradle 的统一管理。5.2 现象改包名后鉴权失败明明 AK 没变这个情况在应用改名或换 applicationId 时非常常见。开放平台的应用信息是绑定包名的你改了applicationId但开放平台里的包名还是旧的所以鉴权失败。先在 app/build.gradle 里确认当前的applicationId再登录开放平台把对应应用的包名改成一致。注意开放平台修改包名不一定立即生效有的情况需要等待几分钟所以改完不要马上去测等两分钟再重新构建安装。构建前记得Build - Clean Project避免旧的 build 缓存带着老包名进 APK。5.3 现象so 文件缺失导致的 UnsatisfiedLinkError如果你选择手动集成 jar/so 包最容易遇到java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader多数情况是 .so 文件的 ABI 目录和设备的 CPU 架构不匹配。解决方式有三种一是把 zip 包里的 arm64-v8a、armeabi-v7a、x86 三个目录全量拷入 src/main/jniLibs保证大多数设备能跑二是在 build.gradle 里配置 abiFilters 只保留 arm64-v8a 和 armeabi-v7a减小包体积三是改用 Maven 依赖避开手动拷 so 的步骤。这里我建议优先换 Maven 方式因为百度地图的 so 文件更新频繁手动替换很容易漏掉新增的 ABI 目录。5.4 现象构建时报类重复定义或 ConstraintLayout 相关类冲突com.baidu.mapapi报 Duplicate class 有好几种情况。常见的是你已经通过 Maven 引入了 BaiduLBS_Android又手动在 libs 里放了同一个版本的 jar还有的是项目里两个 SDK 都捆绑了百度地图比如某些推送 SDK 和地图 SDK 打包在一起导致类重复。先看 Gradle 依赖报告定位来源命令是./gradlew :app:dependencies找到 com.baidu.lbs 或 BaiduLBS 出现的位置然后删掉冗余的那个。如果是手动和 Maven 混用把 libs 下的 jar 和 jniLibs 里的 so 全部删掉只保留 Maven 依赖。5.5 现象模拟器上地图白屏代码没有报错这个问题坑了不少人。百度地图 SDK 对模拟器的兼容性一直不算好尤其是 ARM 转 x86 的模拟器会出现网络正常但瓦片加载不出来的情况。具体表现就是 Logcat 没有任何异常定位失效地图区域灰白一片。排查方法是先换个真机测试如果真机正常那就是模拟器问题。建议不要在 Genymotion 或 Android Studio 自带模拟器里验证地图功能实在要用模拟器推荐用带 Play Store 镜像的 ARM64 模拟器兼容性会好一些但仍不保证瓦片渲染完全正常。6. 进阶调优把地图生命周期管好再做个性化显示地图显示跑通之后还有两个值得投入的方向生命周期管理的健壮性以及地图样式和数据的个性化。生命周期方面除了之前提到的 onResume/onPause/onDestroy 三件套如果你的 Activity 可能被系统回收还要在 onSaveInstanceState 里保存地图状态。常见做法如下Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (mMapView ! null) { // 保存当前地图状态避免旋转屏幕或进程重建时回到默认中心点 outState.putBundle(map_status, mMapView.getMapState()); } }地图状态的保存与恢复在车载或平板这类横竖屏切换频繁的场景下尤其重要不处理的话用户一旋转屏幕地图就跳回北京默认中心点体验很差。另一个实用技巧是设置地图加载完成的监听器用来隐藏加载中的占位动画baiduMap.setOnMapLoadedCallback(new BaiduMap.OnMapLoadedCallback() { Override public void onMapLoaded() { // 地图瓦片加载完成后做标记点展示或隐藏 loading 动画 } });onMapLoaded回调对从业者的价值很大因为很多开发者在地图未加载完成时就添加 Marker导致 Marker 位置偏了或者看不到。等到这个回调触发后再添加覆盖物能保证 Marker 的经纬度正确投影到屏幕坐标上。最后说一下个性化地图的入口。百度地图支持自定义瓦片样式到开放平台申请个性化样式服务下载一个 JSON 文件放在 assets 目录然后调用MapCustomStyleManager加载。代码只做两件事读入 JSON 内容再调用切换方法。这个能力适合有品牌定制需求的 App能让地图颜色和企业视觉统一。但要注意开启个性化样式后某些地图元素会变化底图上的文字、道路颜色和默认风格差异较大最好先在小范围灰度验证再全量放开。从我自己的经验看地图 SDK 集成不是一锤子买卖灰度发布前先跑通 debug 和 release 双签名、把生命周期回调写全、把模拟器和真机差异记在团队文档里后期维护会省很多力气。希望这些思路对你集成百度地图 SDK 有实际帮助。本文还有配套的精品资源点击获取
返回列表