转载请注明出处
Android 11权限的部分不同
单次授权
Android 11升级了隐私保护功能,部分权限用户可进行单次授权。
当用户仅授权单次访问权限,应用可在一段时间内访问相关数据。
- 当应用的 Activity 可见时,应用可以访问相关数据。
- 如果用户将应用转为后台运行,应用可以在短时间内继续访问相关数据。
- 如果您在 Activity 可见时启动了一项前台服务,并且用户随后将您的应用转到后台,那么您的应用可以继续访问相关数据,直到该前台服务停止。
- 如果用户撤消单次授权(例如在系统设置中撤消),无论您是否启动了前台服务,应用都无法访问相关数据。与任何权限一样,如果用户撤消了应用的单次授权,应用进程就会终止。
自动重置未使用的应用的权限
如果应用以 Android 11(API 级别 30)或更高版本为目标平台并且数月未使用,系统会通过自动重置用户已授予应用的运行时敏感权限来保护用户数据。此操作与用户在系统设置中查看权限并将应用的访问权限级别更改为拒绝的做法效果一样。
主要方法
Android 官方推荐的请求权限的流程
在AndroidManifest文件中加入权限声明
无论是否为危险权限,我们都应在AndroidManifest中加入权限生命,以下是Android的权限列表。
https://developer.android.com/reference/android/Manifest.permission
确定是否已获得权限
ContextCompat类
// Context
// String: The name of the permission being checked.
public static int checkSelfPermission (Context context, String permission);
PackageManager类
// String: The name of the permission you are checking for. This value cannot be null.
// String: The name of the package you are checking against. This value cannot be null.
public abstract int checkPermission (String permName, String packageName);
上诉两各类均会返回
- PERMISSION_GRANTED 0
- PERMISSION_DENIED 1
声明为何需要获得权限
ActivityCompat类
如果此方法返回 true,请向用户显示指导界面,在此界面中说明用户希望启用的功能为何需要特定权限。
// Gets whether you should show UI with rationale before requesting a permission.
public static boolean shouldShowRequestPermissionRationale (Activity activity, String permission);
- 首次请求权限,返回false
-
被拒绝但没有选不再提醒,true
- 用户勾选了不再提醒,false
请求权限代码
在Android升级了兼容库AndroidX 1.2.0之后,我们可以使用AndroidX中的RequestPermission,RequestMultiplePermissions来请求权限。
如需请求一项权限,请使用 RequestPermission
如需同时请求多项权限,请使用 RequestMultiplePermissions
public static final class ActivityResultContracts.RequestPermission extends ActivityResultContract<String, Boolean>
public static final class ActivityResultContracts.RequestMultiplePermissions extends ActivityResultContract<String[], Map<String, Boolean>>
我们也可以使用传统的请求方式ActivityCompat.requestPermissions()
// Activity: The target activity.
// String: The requested permissions. Must me non-null and not empty.
// int: Application specific request code to match with a result reported to ActivityCompat.OnRequestPermissionsResultCallback.onRequestPermissionsResult(int, String[], int[]). Should be >= 0.
public static void requestPermissions (Activity activity, String[] permissions, int requestCode);
传统的主动请求方式
请求权限的过程,以下为在Activity或非Fragment、Activity之中的情况,如果是在Fragment中请求,我建议使用Fragment的方法
when {
// If on the Activity, we also can use these method
// this.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
// this.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ->
ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
//已获得权限
// your code
}
// If on the Activity, we also can use these method
// this.shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE)
// || this.shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
ActivityCompat.shouldShowRequestPermissionRationale(this,android.Manifest.permission.READ_EXTERNAL_STORAGE) ||
ActivityCompat.shouldShowRequestPermissionRationale(this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE) -> {
//需要提示用户为什么需要权限
// you code
}
else -> {
// If on the Activity, we also can use these method
// this.requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE), 100)
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE), 100);
//在Activity的onRequestPermissionsResult中获得回调
}
}
获得授权回调,在Activity或者Fragment中
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
PERMISSIONS_STORAGE_QUEST->{
if (grantResults.isNotEmpty() && grantResults.none { it == PackageManager.PERMISSION_DENIED }){
// 获得全部权限
// you code
}else{
// 可能部分权限未获得
}
}
else->{
//you code...
}
}
}
使用AndroidX请求权限
在依赖文件中加入
dependencies {
//Your code
// ...
// Java language implementation
implementation "androidx.activity:activity:1.2.0"
// Kotlin
implementation "androidx.activity:activity-ktx:1.2.0"
}
class PermissionsActivity : androidx.activity.ComponentActivity() {
companion object {
const val PERMISSIONS_STORAGE_QUEST = 100
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
when {
// If on the Activity, we also can use these method
// this.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
// this.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED ->
ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
}
// If on the Activity, we also can use these method
// this.shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE)
// || this.shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) ||
ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) -> {
}
else -> {
// // 请求单个权限
// val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
// if (isGranted) {
// //同意
// // Your code
// } else {
// //不同意
// // Your code
// }
// }
// requestPermissionLauncher.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE)
// 请求多个权限
val requestMultiplePermissionsLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { isGranteds ->
if (isGranteds.any { !it.value }) {
//同意
// Your code
} else {
//不同意
// Your code
}
}
requestMultiplePermissionsLauncher.launch(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE))
}
}
}
}
测试权限
后台定位
Android 11(SDK 30)在上传Google Play Store时,如果有background location的权限,会要求提供说明为何需要使用到background location,否则将下架整改。
而我们所使用的第三方工具,特别是涉及定位功能的SDK,大部分都包含background location的权限,此时,我们需要在AndroidManifest.xml中将其移除。
<!-- ... Your code... -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
tools:node="remove"/>
<!-- ... Your code... -->
文章评论