美文网首页Android收藏集
Android 运行权限那点事

Android 运行权限那点事

作者: 有没有口罩给我一个 | 来源:发表于2018-07-26 00:31 被阅读183次

    对于6.0以下的权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装,造成了我们想要使用某个app,就要默默忍受其一些不必要的权限(比如是个app都要访问通讯录、短信等)。而在6.0以后,我们可以直接安装,当app需要我们授予不恰当的权限的时候,我们可以予以拒绝(比如:单机的象棋对战,请求访问任何权限,我都是不同意的)。当然你也可以在设置界面对每个app的权限进行查看,以及对单个权限进行授权或者解除授权。
    新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等;另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等。

    • Normal Permissions如下:

      ACCESS_LOCATION_EXTRA_COMMANDS
      ACCESS_NETWORK_STATE
      ACCESS_NOTIFICATION_POLICY
      ACCESS_WIFI_STATE
      BLUETOOTH
      BLUETOOTH_ADMIN
      BROADCAST_STICKY
      CHANGE_NETWORK_STATE
      CHANGE_WIFI_MULTICAST_STATE
      CHANGE_WIFI_STATE
      DISABLE_KEYGUARD
      EXPAND_STATUS_BAR
      GET_PACKAGE_SIZE
      INSTALL_SHORTCUT
      INTERNET
      KILL_BACKGROUND_PROCESSES
      MODIFY_AUDIO_SETTINGS
      NFC
      READ_SYNC_SETTINGS
      READ_SYNC_STATS
      RECEIVE_BOOT_COMPLETED
      REORDER_TASKS
      REQUEST_INSTALL_PACKAGES
      SET_ALARM
      SET_TIME_ZONE
      SET_WALLPAPER
      SET_WALLPAPER_HINTS
      TRANSMIT_IR
      UNINSTALL_SHORTCUT
      USE_FINGERPRINT
      VIBRATE
      WAKE_LOCK
      WRITE_SYNC_SETTINGS
      
    • Dangerous Permissions:

       group:android.permission-group.CONTACTS
           permission:android.permission.WRITE_CONTACTS
           permission:android.permission.GET_ACCOUNTS
           permission:android.permission.READ_CONTACTS
      
       group:android.permission-group.PHONE
           permission:android.permission.READ_CALL_LOG
           permission:android.permission.READ_PHONE_STATE
           permission:android.permission.CALL_PHONE
           permission:android.permission.WRITE_CALL_LOG
           permission:android.permission.USE_SIP
           permission:android.permission.PROCESS_OUTGOING_CALLS
           permission:com.android.voicemail.permission.ADD_VOICEMAIL
      
       group:android.permission-group.CALENDAR
             permission:android.permission.READ_CALENDAR
             permission:android.permission.WRITE_CALENDAR
      
       group:android.permission-group.CAMERA
             permission:android.permission.CAMERA
      
       group:android.permission-group.SENSORS
               permission:android.permission.BODY_SENSORS
      
       group:android.permission-group.LOCATION
             permission:android.permission.ACCESS_FINE_LOCATION
             permission:android.permission.ACCESS_COARSE_LOCATION
      
       group:android.permission-group.STORAGE
             permission:android.permission.READ_EXTERNAL_STORAGE
             permission:android.permission.WRITE_EXTERNAL_STORAGE
      
       group:android.permission-group.MICROPHONE
             permission:android.permission.RECORD_AUDIO
      
       group:android.permission-group.SMS
             permission:android.permission.READ_SMS
             permission:android.permission.RECEIVE_WAP_PUSH
             permission:android.permission.RECEIVE_MMS
             permission:android.permission.RECEIVE_SMS
             permission:android.permission.SEND_SMS
             permission:android.permission.READ_CELL_BROADCASTS
      

    看到上面的dangerous permissions,会发现一个问题,好像危险权限都是一组一组的,恩,没错,的确是这样的,
    那么有个问题:分组对我们的权限机制有什么影响吗?
    的确是有影响的,如果app运行在Android 6.x的机器上,对于授权机制是这样的。如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

    不过需要注意的是,不要对权限组过多的依赖,尽可能对每个危险权限都进行正常流程的申请,因为在后期的版本中这个权限组可能会产生变化,就目前8.0,就已经做了这样的变化了。

    在 Android 8.0 之前,如果应用在运行时请求权限并且被授予该权限,系统会错误地将属于同一权限组并且在清单中注册的其他权限也一起授予应用。

    对于针对 Android 8.0 的应用,此行为已被纠正。系统只会授予应用明确请求的权限。然而,一旦用户为应用授予某个权限,则所有后续对该权限组中权限的请求都将被自动批准。

    例如,假设某个应用在其清单中列出 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE。应用请求 READ_EXTERNAL_STORAGE,并且用户授予了该权限。如果该应用针对的是 API 级别 24 或更低级别,系统还会同时授予 WRITE_EXTERNAL_STORAGE,因为该权限也属于同一 STORAGE 权限组并且也在清单中注册过。如果该应用针对的是 Android 8.0,则系统此时仅会授予 READ_EXTERNAL_STORAGE;不过,如果该应用后来又请求 WRITE_EXTERNAL_STORAGE,则系统会立即授予该权限,而不会提示用户。
    所以不要对权限组过多的依赖,下面是我最近封装了一个权限申请:
    1、检查权限是否已被授予;

         checkSelfPermission(String permission)
    

    2、没有则申请权限;

        requestPermissions(@NonNull String[] permissions, int requestCode)
    

    3、处理申请权限结果,成功和失败;

    onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
           @NonNull int[] grantResults)
    

    基本上就完事了,下面就是一些部分代码。

    open class BasePermissionsActivity : RxAppCompatActivity(), PermissionsTransfer {
    private val REQUEST_PERMISSIONS = 0x20
    private var mPermissionPendingRunnable: Runnable? = null
    
    /**
     * 请求权限:
     *
     */
    override fun requestPermissions(permissions: Array<String>, pendingRunnable: Runnable?) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkPermissions(permissions)) {
                executePendingRunnable(pendingRunnable)
                return
            }
            //Remind the pendingRunnable
            mPermissionPendingRunnable = pendingRunnable
            return
        }
        //否则直接执行
        executePendingRunnable(pendingRunnable)
    }
    
    override fun onDestroy() {
        super.onDestroy()
        mPermissionPendingRunnable = null
    }
    
    override fun requestPermissions(permissions: Array<String>, pendingRunnable: () -> Unit) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkPermissions(permissions)) {
                pendingRunnable()
            }
            return
        }
        //否则直接执行
        pendingRunnable()
    }
    
    private fun executePendingRunnable(action: Runnable?) = action?.run()
    
    
    @TargetApi(Build.VERSION_CODES.M)
    private fun checkPermissions(permissions: Array<String>): Boolean {
        val needRequestPermissions = ArrayList<String>(1)
    
        permissions.forEach {
            if (checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED) {
                needRequestPermissions.add(it)
            }
        }
    
        if (needRequestPermissions.size > 0) {
            val requestPermissions = arrayOfNulls<String>(needRequestPermissions.size)
            needRequestPermissions.toArray(requestPermissions)
            requestPermissions(requestPermissions, REQUEST_PERMISSIONS)
            return false
        }
        // 如果已经具有本次所需的权限,则返回True
        return true
    }
    
    
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            REQUEST_PERMISSIONS -> {
                handlePermissionsResult(permissions as Array<String>, grantResults)
            }
            else -> {
            }
        }
    }
    
    /**
     * 处理权限请求结果
     */
    private fun handlePermissionsResult(permissions: Array<String>, grantResults: IntArray) {
        val requestPermissionLength = permissions.size
        val requestFailurePermissionsList = ArrayList<String>(1)
        for (index in 0 until requestPermissionLength) {
            val permission = permissions[index]
            val isPermissionGranted = grantResults[index] == PackageManager.PERMISSION_GRANTED
            KLogUtil.e("RequestPermission:$permission granted:$isPermissionGranted")
            if (!isPermissionGranted) {
                requestFailurePermissionsList.add(permission)
            }
        }
        if (requestFailurePermissionsList.size > 0) {
            val requestFailurePermissions = arrayOfNulls<String>(requestFailurePermissionsList.size)
            requestFailurePermissionsList.toArray(requestFailurePermissions)
            handleRequestPermissionsFailure(requestFailurePermissions)
        } else {
            handleRequestPermissionSuccess(permissions)
        }
    }
    
    private fun handleRequestPermissionSuccess(permissions: Array<String>) {
        onRequestPermissionsSuccess(permissions)
        executePendingRunnable(mPermissionPendingRunnable)
        mPermissionPendingRunnable = null
    }
    
    private fun handleRequestPermissionsFailure(requestFailurePermissions: Array<String?>) {
        onRequestPermissionsFailure(requestFailurePermissions)
        mPermissionPendingRunnable = null
        Build.VERSION_CODES.JELLY_BEAN
    }
    
    override fun onRequestPermissionsFailure(requestFailurePermissions: Array<String?>) {
    }
    
    override fun onRequestPermissionsSuccess(permissions: Array<String>) {
    }
    }
    

    最近项目紧,好久没有更新了,把最近在项目中权限给总结一下,以前总是使用第三方库,不如直接自己封装,后面用起来方便一些。

    相关文章

      网友评论

      本文标题:Android 运行权限那点事

      本文链接:https://www.haomeiwen.com/subject/otcvmftx.html