Android权限机制

Android系统在第一版就开始有了权限机制,如访问网络、读取联系人等操作都需要声明权限,但之前的权限仅仅在AndroidManifest文件中声明一下就行了,容易造成滥用权限的现象,在用户安全和隐私保护上没起到多大的作用。从Android 6.0(API 21)开始,Android引入运行时权限。将常用的权限分为两类,一类是普通权限,一类是危险权限。普通权限不会对用户的安全和隐私造成威胁,与之前一样,要使用时只需在Manifast文件中声明即可。危险权限除了在AndroidManifest文件中声明以外,还必须由用户手动授权才可以,否则在使用相关功能时系统将会抛出异常。

AndroidManifest文件的声明如下所示。

  1. <uses-permission android:name="android.permission.INTERNET" /> <!-- 声明网络权限 -->
  2. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 声明接收开机广播权限 -->

申请运行时权限

需要注意的是,Android将30个危险权限分为了11组,只要成功申请某一个危险权限,那么该权限组的所有权限都会被系统自动授权。比如SEND_SMS权限和READ_SMS权限同在SMS权限组,只要应用申请了SEND_SMS权限,就自动获取了READ_SMS权限。30个危险权限见Android权限组
image.png

在App没有重装或在设置中更改权限授予的情况下,一个权限申请成功一次后就不需要再次申请了。这里以申请打电话权限为例介绍两种申请权限的方式,一种是直接通过原生代码申请,一种是通过常用的权限框架申请。

原生方式申请

这里用Kotlin代码演示如何申请CALL_PHONE权限。
首先在AndroidManifest中声明CALL_PHONE的权限。

  1. <uses-permission android:name="android.permission.CALL_PHONE" />

然后在Activity中申请权限重写onRequestPermissionsResult方法,。

  1. class MainActivity : AppCompatActivity() {
  2. override fun onCreate(savedInstanceState: Bundle?) {
  3. super.onCreate(savedInstanceState)
  4. setContentView(R.layout.activity_main)
  5. // 检查当前是否已经拥有某个权限
  6. if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
  7. == PackageManager.PERMISSION_DENIED)
  8. {
  9. // 申请相关权限
  10. ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), 1)
  11. } else {
  12. // 已经拥有相关权限,直接执行
  13. call()
  14. }
  15. }
  16. // 申请权限后会回调这个方法
  17. override fun onRequestPermissionsResult(
  18. requestCode: Int,
  19. permissions: Array<out String>,
  20. grantResults: IntArray
  21. ) {
  22. super.onRequestPermissionsResult(requestCode, permissions, grantResults)
  23. when (requestCode) {
  24. 1 -> {
  25. if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  26. call() // 申请权限成功,执行相关操作
  27. } else {
  28. Log.d("TAG", "You denied the permisson")
  29. }
  30. }
  31. }
  32. }
  33. // 拨打电话
  34. private fun call() {
  35. val intent = Intent(Intent.ACTION_CALL)
  36. intent.data = Uri.parse("tel:10086")
  37. startActivity(intent)
  38. }
  39. }

使用权限框架申请

Android USB权限