文章

定位权限适配

定位权限适配

Android 定位权限变更

本文梳理 Android1.0~Android11 定位权限几次重大变更和适配。

版本变更

  • Android 6.0(Android 23)之前,在清单文件声明定位权限即可: ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION
  • Android 6.0 及以上,新增运行时权限,使用定位的 2 个权限,需要运行时动态申请 ![500](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/20240811102850.png)
  • Android 10.0,新增后台定位权限,弹窗多了一个选项,Allow all the time
    ![
    300](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/20240811103010.png)
  • Android 11.0 新增仅限这一次授权机制,申请普通定位权限弹窗多了一个选项:Only this time ;普通定位权限和后台定位权限需要分开申请

Android 中的三个定位权限详解

1
2
3
4
5
6
7
8
<!-- Allows an app to access approximate location.  近似定位权限,Api1,如:网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<!-- Allows an app to access precise location 精准定位权限,Api1,如:GPS定位-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<!-- Allows an app to access location in the background. 后台定位权限, Api29,Android10新增 -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

定位权限分类:

普通定位和后台定位权限

  • ACCESS_COARSE_LOCATIONACCESS_FINE_LOCATION 统称为 普通定位权限
  • ACCESS_BACKGROUND_LOCATION 称为 后台定位权限

网络、GPS 和后台定位权限

  • 网络定位权限属于:ACCESS_COARSE_LOCATION
  • GPS 定位权限属于:ACCESS_FINE_LOCATION
  • 后台定位权限:ACCESS_BACKGROUND_LOCATION

谷歌在 Android10 之后,新增的后台定位权限 ACCESS_BACKGROUND_LOCATION。后台定位权限,顾名思义,如果 APP 没有获得后台定位权限,当 APP 处在后台时,获取定位会失败。

注意点

后台定位权限针对的是 Android10 及以上系统

在 Android10 及以上的手机,即使 targetSdkVersion 小于 29,如果用户没有主动授权后台定位权限,APP 处在后台也将无法获取定位。 并且,targetSdkVersion 小于 29,申请 普通定位权限 的弹窗有所变化。

APP 的 targetSdkVersion=26,Android10 的系统。只申请 ACCESS_FINE_LOCATION 权限,弹窗也会有 Allow only while using the app 和 Allow all the time :

![300](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/20240811104054.png)

Android10 系统同时申请普通定位权限和后台定位权限

申请权限的代码:

1
2
3
4
5
6
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)
    }
}
![300](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/20240811104245.png)

如果只请求 Manifest.permission.ACCESS_FINE_LOCATION 权限,只有两个按钮。

![300](https://raw.githubusercontent.com/hacket/ObsidianOSS/master/obsidian/20240811104319.png)

Android 11 系统上,将后台定位权限又做了一次调整

targetSdkVersion=android11 时,不能同时申请普通定位权限和后台定位权限。只有成功申请了 普通定位权限,才能申请后台定位权限。

targetSdkVersion=android11,在 Activity.requestPermissions() 中,同时申请,普通定位权限和后台定位权限,将不会弹窗,直接授权失败。

1
2
3
4
5
6
7
8
// 这次将会调用失败
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // targetSdkVersion=android11,在android11手机上,将直接授权失败
     requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), 100)
    }
}

也就是说,如果你想获得后台定位权限,必须弹窗两次:

  • 第一次,申请普通定位权限的弹窗。
  • 第二次,在用户同意了普通定位权限之后,申请后台定位权限时弹窗。

这里也要千万注意,在没有拿到 普通定位权限的时候,直接申请后台定位权限,将不弹窗直接授权失败。

只有普通定位权限,如何让 APP 在后台时定位?

Android10 以上设备,只有普通定位权限,没有 Activity 在前台时,APP 还能获得定位吗?

通过定位服务

后台定位服务需要满足 3 个条件:

  1. APP 至少已获得普通定位权限
  2. Service 必须是前台服务 foregroundService
  3. androidmenifest.xml 中必须申明 foregroundServiceType,如下
1
2
3
<service
    android:name="com.xxx.notification.SportingNotificationService"
    android:foregroundServiceType="location"/>

这样我们即使没有前台 Activity,只要定位服务在后台依然可以获手机定位数据。

注意:定位 Service 有个缺陷,就是这个 Service 必现是前台 Service。也就意味着必须有通知栏。

本文由作者按照 CC BY 4.0 进行授权