本来是准备第二篇直接写AndroidQ的存储权限等方面的修改和适配的,但是可能是由于我学艺不精,在实践中发现AndroidQ表现的跟Google官方文档描述出入较大,所以目前还在摸索中,那么第二篇文章就先写AndroidQ关于定位权限的修改了。本文分为2个部分,改动解决方案和实践代码。
AndroidQ新引入了后台定位权限,是危险权限需要代码动态申请
这个权限必须配合下面两个权限使用,单独写没有任何效果
Google加入这个权限,意在将App是否能定位的权利分为前台和后台分别交给用户决定,减少App在后台静默定位的可能性,减少用户的个人信息的泄露。
此项改动将会针对所有版本编译的App生效,所以你无法通过修改targetSdkVersion来回避这个问题,由于老版本sdk没有对应的后台定位权限,如果不对AndroidQ进行适配,那么反而会造成无法正常运行的问题。
1、权限申请
首先根据自己app的实际需求设置对应的权限,如果不是地图导航软件,运动计步软件这种需要持续进行定位的情况,其实大多数应用根本就不用申请后台定位这个权限,请工程师不要滥用权限。
首先要在AndroidManifest.xml文件中写入对应的权限。
在申请后台定位权限以前,用户必须先同意定位权限,否则后台定位权限将会被自动拒绝,所以如果你是一条一条申请权限的逻辑的话,需要先申请定位权限。
//android.permission.ACCESS_FINE_LOCATION或android.permission.ACCESS_COARSE_LOCATION
//任选其一申请定位权限
ActivityCompat.requestPermissions(this,
new String[] {Manifest.permission.ACCESS_COARSE_LOCATION},
your-permission-request-code);
你会看到这样的申请界面
在确保用户同意了此权限以后,再申请后台权限
//申请后台权限
ActivityCompat.requestPermissions(this,
new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION},
your-permission-request-code);
你会看到后台请求的说明
得到这两个权限以后,既可以像老版本一样完成完全得到定位相关的权限了
当然你可以直接申请多个权限,AndroidQ对多个相同的权限组申请会合并成一个申请,所以我们也可以这么写
//同时申请所有定位权限,顺序不分先后
ActivityCompat.requestPermissions(this,
new String[] {Manifest.permission.ACCESS_BACKGROUND_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION},
your-permission-request-code);
这样就会得到3个选项的权限请求
这里需要注意的是,如果是老版本的app,点击仅在使用该应用期间允许,系统会认为你拥有全部定位权限,回调会提示得到所有权限,但是事实上你并不能后台定位,也不可以再次申请这个权限。
如果是AndroidQ适配以后,点击仅在使用该应用期间允许,系统会认为你允许了前台定位权限,但是拒绝了后台定位权限,所以这次请求回调会提示失败,有权限未通过。下次再执行这个申请时,系统会只申请后台定位权限。
到这一步适配权限就全部讲完了,那么下一步咱们就来浅谈一下具体的情景适配方法
1、前台定位,不需要后台定位权限
2、后台定位,需要对应权限
总体来说跟以前的方法是一样的,所以这里只讨论由于后台定位权限的加入,引发的一种新的应用场景----没有后台定位权限,依然进行类后台定位。
看了上文,肯定有同学有疑问,就是如果我没有申请后台定位权限,是不是我就真的无法做到关掉界面得到定位信息呢?事实是,依然可以。或者我把这个需求换个说法,就是用户选择拒绝我的App后台定位权限,我如何来继续完成诸如导航,计步这种需要关掉界面后依然在持续定位的需求呢。答案显而易见:foregroundService(前台服务)
前台服务就算你把app放到后台了,当前没有Activity可见,系统依然可以认为你是在前台状态,所以不需要申请后台定位权限,也可以继续进行定位。具体做法改动如下
...
首先在AndroidManifest.xml里注册service,AndroidQ新加入了foregroundServiceType这个属性,请选择"location"
在启动前台服务之前,请确保您的应用仍可访问用户的位置信息:
boolean permissionAccessCoarseLocationApproved =
ActivityCompat.checkSelfPermission(this,
permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED;
if (permissionAccessCoarseLocationApproved) {
// App有前台定位权限. 启动你的有"location"的前台服务
} else {
// 没有权限,发起前台定位权限申请
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION},
your-permission-request-code);
}
打开对应的Service后,进行对应的定位操作就可以了。
后台定位的场景代码这里也翻译一下贴出来给大家,
boolean permissionAccessCoarseLocationApproved =
ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (permissionAccessCoarseLocationApproved) {
boolean backgroundLocationPermissionApproved =
ActivityCompat.checkSelfPermission(this,
permission.ACCESS_BACKGROUND_LOCATION)
== PackageManager.PERMISSION_GRANTED;
if (backgroundLocationPermissionApproved) {
// App可以访问前台和后台定位权限
// 启动后台Service或者带“location”的前台Service
} else {
// App只能使用前台定位,显示一个Dialog提醒用户,你的App需要后台定位权限。
// 然后申请后台定位权限
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_BACKGROUND_LOCATION},
your-permission-request-code);
}
} else {
// App没有任何定位权限,重新申请全部定位相关权限
ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
},
your-permission-request-code);
}
原本是准备做一套比较全的代码发上来,可以自动根据权限,开启对应服务这么一套代码,包括AndroidQ的权限申请和Service启动逻辑。但是后来由于没有真实的设备来给我测试,我不敢说我写的东西一定工作正常,所以目前暂时决定这个系列不加入我个人封装的AndroidQ相关的代码,以后再说。第三期大概率讲一讲android.permission.READ_PHONE_STATE,相关的改动,毕竟这个比较容易一些,这期就到这里。
如果看不懂或者我写的有问题的地方,欢迎在评论中指出,大家一切探究讨论!