Android 百度离线地图及存储权限申请
前言
项目需要在无网络环境下访问百度地图,于是想到了使用百度的离线地图,特将使用过程中遇到的问题记录下来。安卓设备为华为平板,版本Android12.0 API31.
离线地图的使用
参考官方的离线地图使用说明,主要使用MKOfflineMap 进行离线地图的下载及维护,首先初始化离线地图,注意init函数中需要传入listener方法,需要自定义实现MKOfflineMapListener,我是在MainActivity声明时直接implements MKOfflineMapListener了,所以填this就行。
MKOfflineMap mkOfflineMap = new MKOfflineMap();
mkOfflineMap.init(this);
根据城市编码调用MKOfflineMap的start方法下载离线地图,可以通过MKOfflineMap类的searchCity方法根据城市名查找cityId,如下所示,我是在下载该城市地图前,判断了下是否已下载过该城市地图
ArrayList<MKOLUpdateElement> localMapList = mkOfflineMap.getAllUpdateInfo(); //存储已下载的离线地图列表
if (localMapList != null)
{
String[] hasDownLoad = new String[localMapList.size()];
for (int i = 0; i < localMapList.size(); i++)
{
hasDownLoad[i] = localMapList.get(i).cityName;
}
for (int j = 0; j < cityNames.length; j++)
{
if (containsCity(hasDownLoad, cityNames[j]))
Log.i("OfflineMap", cityNames[j]);
else
{
ArrayList<MKOLSearchRecord> records = mkOfflineMap.searchCity(cityNames[j]);
if (records != null && records.size() == 1) {
cityId = records.get(0).cityID;
}
mkOfflineMap.start(cityId);
Toast.makeText(this, "开始下载离线地图. cityid: " + cityId, Toast.LENGTH_SHORT).show();
}
}
}
可以通过onGetOfflineMapState的回调信息,查看更新进度、新离线地图安装、版本更新提示,在implements MKOfflineMapListener后,该函数会自动生成,可以在相应的case下编写自己的代码。
@Override
public void onGetOfflineMapState(int type, int state) {
switch (type) {
case MKOfflineMap.TYPE_DOWNLOAD_UPDATE:
MKOLUpdateElement update = mkOfflineMap.getUpdateInfo(state);
// 处理下载进度更新提示
if (update != null) {
Log.i("offlineDownLoad", String.format("%s : %d%%", update.cityName, update.ratio));
}
break;
case MKOfflineMap.TYPE_NEW_OFFLINE:
// 有新离线地图安装
Log.d("OfflineDemo", String.format("add offlinemap num:%d", state));
break;
case MKOfflineMap.TYPE_VER_UPDATE:
// 版本更新提示
// MKOLUpdateElement e = mOffline.getUpdateInfo(state);
break;
default:
break;
}
}
至此已完成了离线地图的下载,但是在测试过程中发现离线地图并没被加载,同时回调函数中也没有下载进度的更新提示,一开始是怀疑自己的离线地图加载有问题,怀疑并不是自动加载的,而是需要调用什么set之类的函数才能加载离线地图,后来找了半天,也没发现什么解决方法,而且官方文档上的说明是在有离线地图的情况下,地图SDK会优先加载离线地图,于是换了个思路,突然想到是不是离线地图根本没下载成功,这也是回调函数中没有提示的原因,运行过程中APP有网络连接,所以可能是存储访问权限的问题,于是检查自己的存储权限申请,尝试随便在外部存储中创建个文件夹,显示not permit,果然问题出现在这了。
存储权限的申请
之前不知道在哪看的是要申请MANAGE_EXTERNAL_STORAGE权限,但是没申请成功,不过我在在应用管理上手动打开了所有权限,就以为授权OK了,其实不然,对于Android12应该按照如下申请存储的权限:
1、在 AndroidManifest.xml 文件中添加存储权限声明:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2、在Activity中检查是否已获得存储权限,若未获得则进行申请。注意下方的MY_PERMISSIONS_REQUEST_STORAGE请替换为自己的request code,以方便在回调函数中进行区分处理。
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSIONS_REQUEST_STORAGE);
}
3、在请求权限之前,也可以使用 ActivityCompat.shouldShowRequestPermissionRationale() 方法检查是否需要向用户解释为什么需要该权限。如果需要解释,可以向用户显示一个对话框或提示,以便说明权限的用途。我这里就不需要了。
4、在Activity中重写onRequestPermissionsResult方法,以接收权限请求的结果:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == requestCode) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限已授予,执行访问存储的操作
} else {
// 权限被拒绝
}
}
}
在正确请求存储权限后,离线地图得以正常显示了,这里也额外说明下MANAGE_EXTERNAL_STORAGE权限:MANAGE_EXTERNAL_STORAGE 权限是一项特殊权限,需要在应用的 AndroidManifest.xml 文件中声明,并且还需要进行特殊的审核和授予过程,通常适用于需要管理存储空间的系统级应用程序。对于大多数常规应用程序来说,并不需要直接申请 MANAGE_EXTERNAL_STORAGE 权限。如果只需要在应用中访问应用专属目录、公共存储目录或使用 Android 官方 API 访问存储,通常只需申请 WRITE_EXTERNAL_STORAGE 权限即可。