Android 11 运行时权限
Posted
技术标签:
【中文标题】Android 11 运行时权限【英文标题】:Android 11 Runtime Permissions 【发布时间】:2021-10-05 07:45:29 【问题描述】:几天前,代码运行良好,没有权限问题。
我无法在运行时授予权限,在从设置授予权限时也遇到问题。 (应用权限详情页面)。
var permissions = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
arrayOf(Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
else
arrayOf(Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
在相应的按钮单击时请求权限。
permissionResultLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) permissions ->
var allPermissionGranted = true
permissions.entries.forEach
if (!it.value)
Log.e(TAG, "Permission $it.key granted : $it.value")
allPermissionGranted = false
if (!permissionDeniedDialog && !allPermissionGranted)
showDialog(
"Required",
"App needs Bluetooth and Location permissions to scan bluetooth devices.",
"Later",
"Allow",
object : DialogView.ButtonListener
override fun onNegativeButtonClick(dialog: AlertDialog)
dialog.dismiss()
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", requireActivity().applicationContext.packageName, null))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
override fun onPositiveButtonClick(dialog: AlertDialog)
dialog.dismiss()
requestRequirdPermissions()
)
else
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", requireActivity().applicationContext.packageName, null))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
permissionDeniedDialog = true
permissionResultLauncher.launch(permissions)
权限检查功能
private fun checkPermission(): Boolean
for (permission in permissions)
if (ContextCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) return false
return true
有人可以告诉我为什么上述方法不起作用吗?系统直接在结果上,应用程序正在将应用程序重定向到设置页面,但我也无法从设置页面授予权限。
这是特定于操作系统的吗?有人遇到与 ColorOS 11 相同的问题吗? 如果我身边缺少任何东西,请指导我。
设备:OPPO F17 Pro 操作系统:Color OS 11,基于 Android 11
注意:
以上代码,使用三星设备,基于 Android 11(OneUI 3.1),应用程序不要求运行时,但在设置页面上重定向后,我授予位置权限并且应用程序工作正常,关于 OPPO 我无法授予权限从设置页面。
尝试了什么:
var permissions = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
arrayOf(Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
else
arrayOf(Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_COARSE_LOCATION)
private fun requestRequirdPermissions()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)
permissionResultLauncher.launch(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION))
else
permissionResultLauncher.launch(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION ))
【问题讨论】:
“几天前,代码运行良好,没有权限问题”。那么从那以后你有什么改变呢? 什么都没变,和以前一样,这就是我来这里的原因,因为我从2小时就开始检查了。 您不能一次请求所有不同的位置权限。阅读文档。 谢谢,但不确定,我已经尝试使用名为 ACCESS_BACKGROUND_LOCATION 的单一权限仍然无法正常工作。 @Ashvinsolanki 您必须逐步请求位置许可:请求前景 (ACCESS_FINE_LOCATION
) 然后在获得许可后您可以请求背景 (ACCESS_BACKGROUND_LOCATION
)。如果您在没有先授予前景的情况下要求背景或同时要求两者,则请求会立即被拒绝,甚至不会显示对话框。见***.com/questions/66321232/…
【参考方案1】:
试试这个方法可能对你有帮助
fun checkPermission()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
var permissions: ArrayList<String> = ArrayList<String>()
permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION)
val listPermissionsNeeded: ArrayList<String> = ArrayList()
for (p in permissions)
var result = ContextCompat.checkSelfPermission(this, p!!)
if (result != PackageManager.PERMISSION_GRANTED)
listPermissionsNeeded.add(p)
if (!listPermissionsNeeded.isEmpty())
ActivityCompat.requestPermissions(
this,
listPermissionsNeeded.toTypedArray(),
CODE
)
else
next()
else
next()
override fun onRequestPermissionsResult(
requestc: Int,
permissions: Array<String>,
grantRes: IntArray
)
super.onRequestPermissionsResult(requestc, permissions, grantRes);
when (requestc)
CODE ->
var isGrant = true
if (grantRes.size > 0)
for (i in 0 until grantResults.size)
if (grantResults[i] == PackageManager.PERMISSION_DENIED)
isGrant = false
if (isGrant)
next()
else
checkRationalePermission(permissions)
var alertDialogRatinal: android.app.AlertDialog? = null
fun checkRationale(permissions: Array<String>)
if (alertDialogRatinal != null && alertDialogRatinal!!.isShowing || permissions.size == 0)
return
var someDenied = false
for (permission in permissions)
if (ActivityCompat.shouldShowRequestPermissionRationale(
this@Activity,
permission!!
)
)
else
if (ActivityCompat.checkSelfPermission(
this@Activity,
permission
) == PackageManager.PERMISSION_GRANTED
)
else
someDenied = true
if (someDenied)
val alertDialogBuilder =
android.app.AlertDialog.Builder(this@Activity)
alertDialogRatinal = alertDialogBuilder.setTitle("Permissions Required")
.setMessage(
"Please open settings, go to permissions and allow them."
)
.setPositiveButton(
"Settings"
) dialog, which ->
val intent = Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts(
"package",
this@Activity.getPackageName(),
null
)
)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivityForResult(intent, 100)
.setNegativeButton(
"Cancel"
) dialog, which ->
.setCancelable(false)
.create()
alertDialogRatinal!!.show()
【讨论】:
我建议你使用新的 API "ActivityResultContracts"【参考方案2】:我的问题已通过系统重置得到解决,但根据 cmets 和文档,请按照以下指南获取位置权限。
感谢Pawelcmets,
参考:https://***.com/a/66321942/9909365
后台位置权限不像其他权限那样工作。这是一个将位置权限从仅前台提升到前台和后台的请求。
用户必须有意识地选择“始终允许”才能执行此操作并授予后台位置权限。否则,该权限将被视为被拒绝。
除非已授予前台位置,否则您甚至无法请求后台位置 - 当系统权限活动显示时,它应该已经选择了选项 2 或 3。
见https://developer.android.com/training/location/permissions#request-background-location
注意:
当您的应用使用此后台位置时,请准备一段简短的视频,演示您的应用中基于位置的功能,该功能需要在后台访问位置(当应用未使用时)。
见https://support.google.com/googleplay/android-developer/answer/9799150
【讨论】:
【参考方案3】:private val requestIdMultiplePermissions = 1
private val permissionsRequest: ArrayList<String> =
arrayListOf(READ_CALENDAR
, CAMERA)
findViewById<Button>(R.id.multiplePermissionBtn).setOnClickListener
if (checkMultipleRequestPermissions())
doOperation()
private fun doOperation()
Toast.makeText(this, "Successfully granted", Toast.LENGTH_LONG).show()
private fun checkMultipleRequestPermissions(): Boolean
val listPermissionsNeeded: MutableList<String> = ArrayList()
for (p in permissionsRequest)
val result = ContextCompat.checkSelfPermission(this, p)
if (result != PackageManager.PERMISSION_GRANTED)
listPermissionsNeeded.add(p)
if (listPermissionsNeeded.isNotEmpty())
ActivityCompat.requestPermissions(
this,
listPermissionsNeeded.toTypedArray(),
requestIdMultiplePermissions
)
return false
return true
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
)
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == requestIdMultiplePermissions)
if (grantResults.isNotEmpty())
var isGrant = true
for (element in grantResults)
if (element == PackageManager.PERMISSION_DENIED)
isGrant = false
if (isGrant)
doOperation()
else
var someDenied = false
for (permission in permissions)
if (!ActivityCompat.shouldShowRequestPermissionRationale(
this,
permission
)
)
if (ActivityCompat.checkSelfPermission(
this,
permission
) == PackageManager.PERMISSION_DENIED
)
someDenied = true
if (someDenied)
settingActivityOpen()
else
showDialogOK _: DialogInterface?, which: Int ->
when (which)
DialogInterface.BUTTON_POSITIVE -> checkMultipleRequestPermissions()
DialogInterface.BUTTON_NEGATIVE ->
private fun settingActivityOpen()
Toast.makeText(
this,
"Go to settings and enable permissions",
Toast.LENGTH_LONG
)
.show()
val i = Intent()
i.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
i.addCategory(Intent.CATEGORY_DEFAULT)
i.data = Uri.parse("package:$packageName")
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
startActivity(i)
private fun showDialogOK(okListener: DialogInterface.OnClickListener)
MaterialAlertDialogBuilder(this)
.setMessage("All Permission required for this app")
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show()
【讨论】:
以上是关于Android 11 运行时权限的主要内容,如果未能解决你的问题,请参考以下文章
可以在 Android Marshmallow (API 23) 的运行时权限模型中同步请求权限吗?
Android 运行时权限流程:我可以使用 ActivityCompat.requestPermissions 发送额外内容吗?