美文网首页
Android开发笔记-权限管理

Android开发笔记-权限管理

作者: TheaZhu | 来源:发表于2016-04-07 13:52 被阅读277次

    Android 6.0对用户权限管理机制进行了改善。不再像之前一样在首次安装应用时处理权限请求,现在的权限设置只有在应用需要使用该功能的时候才会申请该权限,也就是我们所说的运行时权限。

    如果App暂未支持运行时权限,最好将targetSdkVersion设置为23以下,系统将会以旧的权限管理系统来处理,否则在Android 6.0系统上运行时可能会出问题。

    权限分组


    Android开发中,在使用某些特定功能时需要申请权限,但并非所以权限都是敏感权限,因此系统对权限进行了分类:

    • 正常权限(Normal Permissions)
    • 危险权限(Dangerous Permissions)
    • 特殊权限(Particular Permissions)
    • 其他权限(一般很少用到)

    正常权限(Normal Permissions)


    • 特点: 对用户隐私或设备操作没有较大影响。

    • 申请方式: 直接在AndroidManifest.xml文件中声明。

        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.android.app.myapp" >
      
            <uses-permission android:name="android.permission.RECEIVE_SMS" />
            ...
        </manifest>
      
    • 管理方式: 系统将自动为App赋予这些权限,不需要显示的提醒用户。

    • 权限列表:所涉及到的基本是关于网络、蓝牙、时区、快捷方式等方面。

        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
        INTERNET
        KILL_BACKGROUND_PROCESSES
        MODIFY_AUDIO_SETTINGS
        NFC
        READ_SYNC_SETTINGS
        READ_SYNC_STATS
        RECEIVE_BOOT_COMPLETED
        REORDER_TASKS
        REQUEST_INSTALL_PACKAGES
        SET_TIME_ZONE
        SET_WALLPAPER
        SET_WALLPAPER_HINTS
        TRANSMIT_IR
        USE_FINGERPRINT
        VIBRATE
        WAKE_LOCK
        WRITE_SYNC_SETTINGS
        SET_ALARM
        INSTALL_SHORTCUT
        UNINSTALL_SHORTCUT
      

    危险权限(Dangerous Permissions)


    • 特点: 可能会对用户隐私或设备的正常操作造成影响。是运行时权限主要处理的对象。

    • 申请方式: 当App运行时需要该权限时申请。每次需要权限是都要检查是否有被授予,如果没有则需要询问用户。

        private static final int REQUEST_READ_CONTACTS_PERMISSION = 22;
      
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            // 权限请求回调
            switch (requestCode) {
                case REQUEST_READ_CONTACTS_PERMISSION:
                    // 读取联系人权限成功获取
                    if (grantResults.length > 0 && grantResults[0] ==  PackageManager.PERMISSION_GRANTED)
                        queryContacts();
                    else
                        Toast.makeText(this, "没有读取联系人权限", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
      
        public boolean checkPermission(String permission) {
            // 判断是否有权限
            int permissionCheck = ContextCompat.checkSelfPermission(
                    this, permission);
            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {        // 没有获取权限
                // 判断是否应该说明申请权限的理由
                boolean shouldShowRationale = ActivityCompat.shouldShowRequestPermissionRationale(
                        this, Manifest.permission.READ_CONTACTS);
                Log.i(TAG, "rationale: " + shouldShowRationale);
                if (shouldShowRationale) {
                    // 说明理由,等待用户反馈,再申请权限
                }
                // 发起申请权限请求
                ActivityCompat.requestPermissions(this, new String[]{permission},
                        REQUEST_READ_CONTACTS_PERMISSION);
            }
            return permissionCheck == PackageManager.PERMISSION_GRANTED;
        }
      
        public void getContacts(View view) {
            if (Build.VERSION.SDK_INT < 23 || checkPermission(Manifest.permission.READ_CONTACTS))
                queryContacts();
        }
      
        public void queryContacts() {
            Cursor cursor = getContentResolver().query(
                    ContactsContract.Contacts.CONTENT_URI,
                    new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME},
                    null, null, ContactsContract.Contacts.SORT_KEY_PRIMARY);
      
            if (cursor == null)
                return;
      
            while (cursor.moveToNext()) {
                Log.i(TAG, "id: " + cursor.getString(0) + ", name: " + cursor.getString(1));
            }
      
            cursor.close();
        }
      
    • 注意:

      1. 当程序支持Android 6.0时,也要兼容以前的版本。

      2. Fragment中申请权限时,不要使用ActivityCompat.requestPermissions, 直接使用Fragment的requestPermissions方法,否则会回调到Activity的onRequestPermissionsResult

      3. (此问题23.3版本库已修复)如果在Fragment中嵌套Fragment,在子Fragment中使用requestPermissions方法,onRequestPermissionsResult不会回调回来,建议使用getParentFragment().requestPermissions方法,
        这个方法会回调到父Fragment中的onRequestPermissionsResult,加入以下代码可以把回调透传到子Fragment

         @Override
         public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
             super.onRequestPermissionsResult(requestCode, permissions, grantResults);
             List<Fragment> fragments = getChildFragmentManager().getFragments();
             if (fragments != null) {
                 for (Fragment fragment : fragments) {
                     if (fragment != null)
                         fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
                 }
             }
         }
        
    • 管理方式: 系统需要用户显示的授予这些权限,且用户随时可以撤回授予的权限。

    • 分组: 系统对权限进行了分组(Group),属于同一组的权限互相绑定,一旦组内某个权限被允许,该组的其他权限也将允许。

    • 权限列表:


    特殊权限(Particular Permissions)


    • 特点: 对系统来说是特别敏感的权限。

    • 权限列表:

        SYSTEM_ALERT_WINDOW   // 设置悬浮窗,进行一些黑科技
        WRITE_SETTINGS   // 修改系统设置        
      
    • 申请方式:在需要使用时,使用startActivityForResult启动授权界面来完成。

    相关开源框架


    参考文献


    相关文章

      网友评论

          本文标题:Android开发笔记-权限管理

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