Android 6.0 权限

在Android6.0之前,应用安装时系统会列出AndroidManifest清单上申请的所有权限,用户必须全部接受才能继续安装,并且这些权限授权之后无法撤销。这对于开发者来说是比较方便的,需要什么权限只需要在AndroidManifest申请即可,不需要考虑权限被拒绝等各种场景。但是对于用户来说却没有办法自主选择屏蔽他不想授予的权限,也容易给恶意程序利用。

Android6.0之后,权限的申请由安装时变成了运行时。开发者仍然需要在AndroidManifest里面列出所需要的所有权限,但用户安装时不需要对这些权限进行授权,而是在运行时需要用到某个权限时才询问用户是否授权,用户可以选择接受或者拒绝。另外即使用户接受了,也可以在权限管理中进行撤销。如果直接使用用户没有授权的权限会导致crash,因此,开发时需要考虑这些场景,并作出处理。

对于一些老的应用来说,也不用太担心,如果app的targetSdkVersion低于23,将继续使用旧有规则。看到这有人可能觉得干脆将所有的targetSdkVersion设置为23以下不就好了,也不用那么麻烦考虑权限的问题。但是要注意,在6.0的系统上,即使安装时取得了所有的权限,用户仍然可以之后在权限管理中撤销授权。因此,我们还是需要与时俱进,将targetSdkVersion升级到23并好好处理权限问题。

Android的权限总的来说分为三种,分别是normal类型、dangerous类型和special类型:

1、normal类型的权限不会威胁到用户的隐私,可以直接在AndroidManifest里面注册,在安装时就被授权,不需要每次使用时都检查权限,并且用户不能取消。主要包括:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

2、dangerous类型的权限可以直接访问用户的敏感数据,不仅需要在AndroidManifest里面注册,还需要在使用时请求授权。主要包括:



可以看到dangerous类型的权限进行了分组,同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS权限了。

dangerous类型的权限申请主要调用这几个方法:

Context.checkSelfPermission(String permission) 检查是否被授予了某个权限
Activity.requestPermissions(String[] permissions, int requestCode) 申请一组权限
Activity.onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) 权限申请结果回调

由于这些方法都是在api23引入的,所以需要在使用时先进行版本判断。下面以相机为例说明怎样申请权限:

public void checkCameraPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // 23及以后的版本需要检测权限
        int hasCameraPermission = checkSelfPermission(Manifest.permission.CAMERA);
        if (hasCameraPermission != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE_CAMERA);
        } else {
            cameraPermissionGranted(true);
        }
    } else {
        // 23之前的版本权限在安装时已经获取
        cameraPermissionGranted(true);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == PERMISSION_REQUEST_CODE_CAMERA) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            cameraPermissionGranted(true);
        } else {
            cameraPermissionGranted(false);
        }
    }
}

另外,v4包中也提供了兼容方法ContextCompat.checkSelfPermission()和ActivityCompat.requestPermissions()可以避免版本判断,唯一的区别就是需要带上额外的参数Context或Activity,其他都一样:

private void checkCameraPermission(Activity activity) {
    int hasCameraPermission = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
    if (hasCameraPermission != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE_CAMERA);
    } else {
        cameraPermissionGranted(true);
    }
}

权限的判断和申请其实比较简单,对于开发者来说更重要的其实是权限被接受或拒绝后的不同处理,也就是上面的cameraPermissionGranted(boolea granted)方法。比如如果你的应用必须使用相机,那么在相机权限申请拒绝后可以弹框提示用户,直到用户授权后才能进入使用界面。又或者应用并非必须使用相机,也可以从相册加载图片,那么当用户拒绝授权时,只需要禁掉相机部分的功能即可。

3、special类型的权限包括WRITE_SETTINGS和SYSTEM_ALERT_WINDOW,Android单独制作了一个activity作为这两个权限的用户授权界面,必须通过指定intent,然后通过startActivity(intent)的方式来申请。
special类型的权限申请主要用到以下几个方法:

Settings.System.canWrite(Context context) 检查是否被授予了WRITE_SETTINGS权限
Settings.canDrawOverlays(Context context) 检查是否被授予了SYSTEM_ALERT_WINDOW权限
startActivityForResult(Intent intent, in requestCode) 打开用户授权界面
onActivityResult(int requestCode, int resultCode, Intent data) 权限申请结果回调

申请WRITE_SETTINGS权限的代码如下:

public void checkWriteSettingsPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.System.canWrite(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, PERMISSION_REQUEST_CODE_WRITE_SETTINGS);
        } else {
            writeSettingsPermissionGranted(true);
        }
    } else {
        writeSettingsPermissionGranted(true);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PERMISSION_REQUEST_CODE_WRITE_SETTINGS) {
        // 判断是否有WRITE_SETTINGS权限
        if (Settings.System.canWrite(this)) {
            writeSettingsPermissionGranted(true);
        }else {
            writeSettingsPermissionGranted(false);
        }
    }
}

申请SYSTEM_ALERT_WINDOW的代码如下:

public void checkSystemAlertWindowPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!Settings.canDrawOverlays(this)) {
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, PERMISSION_REQUEST_CODE_SYSTEM_ALERT_WINDOW);
        } else {
            systemAlertWindowPermissionGranted(true);
        }
    } else {
        systemAlertWindowPermissionGranted(true);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PERMISSION_REQUEST_CODE_SYSTEM_ALERT_WINDOW) {
        if (Settings.canDrawOverlays(this)) {
            systemAlertWindowPermissionGranted(true);
        } else {
            systemAlertWindowPermissionGranted(false);
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容