【 Android 】Android Runtime Permi

作者: Tyhoo_Wu | 来源:发表于2017-06-21 00:45 被阅读769次
    permissions.png

    Android 运行时请求权限大家都并不陌生,网上类似的 Sample 铺天盖地。为什么我还要针对 Android 运行时请求权限去做文章呢?那就是适配 Android O !
    在 Android 官方文档中 https://developer.android.google.cn/preview/behavior-changes.html
    对 Android O 的行为变更中的运行时请求权限做了修改。官方文档中强调:

    权限.png
    说白了就是对权限申请更加严格。针对这一变更,作为开发者既要兼顾 Android M - Android N 的运行时请求权限,也要适配 Android O 的运行时请求权限。

    好的,跟着我的思路开始我们的运行时请求权限解决方案。

    先看效果图:
    ① 在没授予权限之前,所有需要的权限都是未选中状态。


    1.png

    ② Android 运行时请求权限。


    2.gif
    ③ 权限授予之后,所有需要的权限都是选中状态。
    3.png

    看过示例图之后,我们先来了解一下哪些权限需要在运行时请求。

    根据官方 API 文档 https://developer.android.google.cn/guide/topics/security/permissions.html 中所描述的内容,我们可以归纳出以下几点需要注意的地方:

    1. 如果设备运行的是 Android 6.0(API 级别 23)或更高版本,并且应用的 targetSdkVersion 是 23 或更高版本,则应用在运行时向用户请求权限。用户可随时调用权限,因此应用在每次运行时均需检查自身是否具备所需的权限。

    2. 如果设备运行的是 Android 5.1(API 级别 22)或更低版本,并且应用的 targetSdkVersion 是 22 或更低版本,则系统会在用户安装应用时要求用户授予权限。如果将新权限添加到更新的应用版本,系统会在用户更新应用时要求授予该权限。用户一旦安装应用,他们撤销权限的唯一方式是卸载应用。

    3. 可能在程序运行期间的多个位置实施特定权限:
      ① 在调用系统时,防止应用执行某些功能。
      ② 在启动 Activity 时,防止应用启动其他应用的 Activity。
      ③ 在发送和接收广播时,控制谁可以接收您的广播,谁可以向您发送广播。
      ④ 在访问和操作内容提供程序时。
      ⑤ 绑定至服务或启动服务。

    4. 正常权限和危险权限
      ① 正常权限涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。例如,设置时区的权限就是正常权限。如果应用声明其需要正常权限,系统会自动向应用授予该权限。
      ② 危险权限涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如,能够读取用户的联系人属于危险权限。如果应用声明其需要危险权限,则用户必须明确向应用授予该权限。

    5. 危险权限和权限组
      分成 9 大类:

    CALENDAR                 READ_CALENDAR
                                WRITE_CALENDAR
    
    CAMERA                   CAMERA
    
    CONTACTS                 READ_CONTACTS
                                WRITE_CONTACTS
                                GET_ACCOUNTS
    
    LOCATION                 ACCESS_FINE_LOCATION
                                ACCESS_COARSE_LOCATION 
    
    MICROPHONE               RECORD_AUDIO
    
    PHONE                    READ_PHONE_STATE
                                CALL_PHONE
                                READ_CALL_LOG
                                WRITE_CALL_LOG
                                ADD_VOICEMAIL
                                USE_SIP
                                PROCESS_OUTGOING_CALLS
    
    SENSORS                  BODY_SENSORS
    
    SMS                      SEND_SMS 
                                RECEIVE_SMS 
                                READ_SMS 
                                RECEIVE_WAP_PUSH 
                                RECEIVE_MMS 
    
    STORAGE                  READ_EXTERNAL_STORAGE 
                                WRITE_EXTERNAL_STORAGE
    

    了解了哪些权限属于危险权限之后,跟随我一起进行 Android Runtime Permissions 解决方案。

    (这里以 CALENDAR 为例,其他大同小异,获取完整代码请拖拽至文章末尾处。)

    1. 定义请求权限
    private static final int REQUEST_CALENDAR = 0;
    
    1. 考虑到 Android O 之后的权限请求,故将同一类的都放在一个数组里进行处理
    private static String[] PERMISSION_CALENDAR = {
            Manifest.permission.READ_CALENDAR,
            Manifest.permission.WRITE_CALENDAR
    };
    
    1. 做权限请求的回调
    public void showCalendar(View viewShowCalendar) {
        Log.i(TAG, "Show calendar button pressed. Checking permissions.");
    
        // Verify that all required contact permissions have been granted.
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR)
                != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CALENDAR)
                != PackageManager.PERMISSION_GRANTED) {
            // Calendar permissions have not been granted.
            Log.i(TAG, "Calendar permissions has not been granted. Requesting permissions.");
            requestCalendarPermissions();
        } else {
            // Calendar permissions have been granted. Show the contacts fragment.
            Log.i(TAG,
                    "Calendar permissions have already been granted. Displaying calendar details.");
            showCalendarDetails();
        }
    }
    

    这里就要做分支处理:
    ① 没有给予请求所需的权限,就要发出权限请求 requestCalendarPermissions()
    ② 如果已授予权限,那么就执行你想要执行的动作 showCalendarDetails()

    1. 发出权限请求
    private void requestCalendarPermissions() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_CALENDAR)
                || ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_CALENDAR)) {
    
            // Provide an additional rationale to the user if the permission was not granted
            // and the user would benefit from additional context for the use of the permission.
            // For example, if the request has been denied previously.
            Log.i(TAG, "Displaying calendar permission rationale to provide additional context.");
    
            // Display a SnackBar with an explanation and a button to trigger the request.
            Snackbar.make(mLayout, R.string.permission_calendar_rationale,
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.ok, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            ActivityCompat
                                    .requestPermissions(MainActivity.this, PERMISSION_CALENDAR,
                                            REQUEST_CALENDAR);
                        }
                    })
                    .show();
        } else {
            // Calendar permissions have not been granted yet. Request them directly.
            ActivityCompat.requestPermissions(this, PERMISSION_CALENDAR, REQUEST_CALENDAR);
        }
    }
    
    1. 当权限已被授于,自定义执行动作
    private void showCalendarDetails() {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.content_fragment, CalendarFragment.newInstance())
                .addToBackStack("calendar")
                .commit();
    }
    

    ✱✱✱ 重中之重 ✱✱✱ 当权限请求完成之后回调。重写 onRequestPermissionsResult()

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
    
        if (requestCode == REQUEST_CALENDAR) {
            Log.i(TAG, "Received response for calendar permissions request.");
    
            // We have requested multiple permissions for calendar, so all of them need to be
            // checked.
            if (PermissionUtil.verifyPermissions(grantResults)) {
                // All required permissions have been granted, display contacts fragment.
                Snackbar.make(mLayout, R.string.permission_available_calendar,
                        Snackbar.LENGTH_SHORT)
                        .show();
            } else {
                Log.i(TAG, "Calendar permissions were not granted.");
                Snackbar.make(mLayout, R.string.permissions_not_granted, Snackbar.LENGTH_SHORT)
                        .show();
            }
        }
        
        ...
    
    }
    

    </br>
    最后在 AndroidManifest 里面申请需要的权限

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.haocent.android.androidruntimepermissions">
    
        <uses-permission-sdk-23 android:name="android.permission.READ_CALENDAR" />
        <uses-permission-sdk-23 android:name="android.permission.WRITE_CALENDAR" />
    
        ...
    
    </manifest>
    

    项目代码已上传至 GitHub https://github.com/cnwutianhao/AndroidRuntimePermissions
    欢迎 Star 、Fork 。如有遗漏或错误请指摘。

    项目已在以下机器上进行完整测试
    Nexus 5 Android 6.0.1 (真机)
    Nexus 5x Android O (模拟器)

    相关文章

      网友评论

      本文标题:【 Android 】Android Runtime Permi

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