权限
配置¶
repositories {
mavenCentral()
}
dependencies {
implementation "com.google.accompanist:accompanist-permissions:<version>"
}
单个权限¶
例如,我们需要获取相机权限,通过rememberPermissionState(Manifest.permission.CAMERA)
获取到 PermissionState
,然在布局时使用PermissionRequired
可以很方便的进行布局,同时在权限被拒绝、永久拒绝或者允许时都有对应的lambda,通过调用permissionState.launchPermissionRequest()
来申请权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="icu.bughub.app.basicssample">
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 其他配置 -->
</manifest>
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionSample() {
val permissionState = rememberPermissionState(
permission = Manifest.permission.CAMERA
)
Scaffold(topBar = {
TopAppBar(title = { Text("Permission Demo") })
}) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
when (permissionState.status) {
PermissionStatus.Granted -> {
Text("已经同意了相机权限")
}
//权限拒绝
is PermissionStatus.Denied -> {
Column {
val text = if (permissionState.status.shouldShowRationale) {
//已经点击获取权限,此时拒绝
"相机权限已拒绝,点击按钮再次请求"
} else {
//默认情况下的拒绝
"相机权限已被禁止"
}
Text(text = text)
Button(onClick = {
permissionState.launchPermissionRequest()
}) {
Text("点击获取权限")
}
}
}
}
}
}
}
Result
可以看到有些许区别
- 在Pixel2上,权限弹窗有3个操作:仅使用期间允许、仅限这一次、拒绝
- 在Pixel2上,第一次拒绝后,状态变为
Not Granted
再次拒绝后才会变为Not Available
,而某国产手机只有一次机会
多个权限¶
例如,我们想同时获取相机和录音权限,通过val permissionsState = rememberMultiplePermissionsState(permissions = listOf(Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO))
获取到 PermissionsState
, 通过调用permissionsState.launchMultiplePermissionRequest()
来请求权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="icu.bughub.app.basicssample">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- 其他配置 -->
</manifest>
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionSample1() {
val permissionsState = rememberMultiplePermissionsState(
permissions =
listOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
)
Scaffold(topBar = {
TopAppBar(title = { Text("Permissions Demo") })
}) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
permissionsState.permissions.forEach { permissionState ->
when (permissionState.permission) {
Manifest.permission.CAMERA -> {
when (permissionState.status) {
PermissionStatus.Granted -> {
Text("已经同意了相机权限")
}
//权限拒绝
is PermissionStatus.Denied -> {
Column {
val text = if (permissionState.status.shouldShowRationale) {
//已经点击获取权限,此时拒绝
"相机权限已拒绝,点击按钮再次请求"
} else {
//默认情况下的拒绝
"相机权限已被禁止"
}
Text(text = text)
}
}
}
}
Manifest.permission.RECORD_AUDIO -> {
when (permissionState.status) {
PermissionStatus.Granted -> {
Text("已经同意了录音权限")
}
//权限拒绝
is PermissionStatus.Denied -> {
Column {
val text = if (permissionState.status.shouldShowRationale) {
//已经点击获取权限,此时拒绝
"录音权限已拒绝,点击按钮再次请求"
} else {
//默认情况下的拒绝
"录音权限已被禁止"
}
Text(text = text)
}
}
}
}
}
}
Button(onClick = {
permissionsState.launchMultiplePermissionRequest()
}) {
Text("点击获取权限")
}
}
}
}
Result
你一定发现了多个和单个权限写法的不同,其实多个权限系统也提供了PermissionsRequired
,但这个只能判断所有权限的状态是否允许或拒绝。
后台权限¶
例如,定位权限在 Android 10 以后就被拆分为前台权限Manifest.permission.ACCESS_FINE_LOCATION
和后台权限Manifest.permission.ACCESS_BACKGROUND_LOCATION
,且在 Android 11 后两个权限不能同时申请,建议增量式申请,也就是说要先请求前台权限之后才能申请后台权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="icu.bughub.app.basicssample">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<!-- 基本配置 -->
</manifest>
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionSample2() {
val permissionState =
rememberPermissionState(permission = Manifest.permission.ACCESS_FINE_LOCATION)
val backgroundPermissionState =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
rememberPermissionState(permission = Manifest.permission.ACCESS_BACKGROUND_LOCATION)
} else {
TODO("VERSION.SDK_INT < Q")
}
Scaffold(topBar = {
TopAppBar(title = { Text("Permissions Demo") })
}) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
when (permissionState.status) {
PermissionStatus.Granted -> {
Button(onClick = {
backgroundPermissionState.launchPermissionRequest()
}) {
Text("前台定位权限已同意,点击获取后台定位权限")
}
}
//权限拒绝
is PermissionStatus.Denied -> {
Column {
val text = if (permissionState.status.shouldShowRationale) {
//已经点击获取权限,此时拒绝
"前台定位权限已拒绝,点击按钮再次请求"
} else {
//默认情况下的拒绝
"前台定位权限已被禁止"
}
Text(text = text)
}
}
}
when(backgroundPermissionState.status){
PermissionStatus.Granted ->{
Text(text = "后台定位权限已同意")
}
//权限拒绝
is PermissionStatus.Denied -> {
Column {
val text = if (permissionState.status.shouldShowRationale) {
//已经点击获取权限,此时拒绝
"后台定位权限已拒绝,点击按钮再次请求"
} else {
//默认情况下的拒绝
"后台定位权限已被禁止"
}
Text(text = text)
}
}
}
Button(onClick = {
permissionState.launchPermissionRequest()
}) {
Text("点击获取权限")
}
}
}
}
如果两个权限同时申请,在 Android 11+ 上就会报错:
Error
Apps targeting 30 must have foreground permission before requesting background and must request background on its own.