Android6.0权限处理不再复杂

前言

谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授权的不合理,现在6.0出来,使得用户权限授权变得合理。

Android 6.0版本之前

在此版本之前,只要在清单文件(AndroidManifest)中申请需要用到的权限,安装之后,所申请的权限将会被允许。

Android 6.0版本之后

从Android6.0开始,APP可以直接安装,但所需的权限则需要动态申请。App在运行时询问用户授予权限,弹出Dialog窗口进行询问是否允许,【拒绝】之后,也可以引导用户前往设置界面。

权限分类

Google将权限分为两类:
一类是Normal Permissions,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等,所以开发者直接在清单文件中申请即可;

另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等;

但在Dangerous Permission中,其实还有比较特殊的两个权限存在,分别是SYSTEM_ALERT_WINDOW(允许一个程序打开窗口,显示在其他所有程序的顶层)WRITE_SETTINGS(允许应用程序更改主屏幕中的设置和快捷方式)

这两个权限也属于Dangerous Permission,但是在申请上却有点特殊。这两个权限是不能自动授权,也不能运行时请求授权,只能引导用户去应用的设置页手动开启

PS:Dangerous Permission的权限9大类别

Dangerous Permission的权限9大类别

只要授权某一个类别中的其中某一个权限,则该类别的权限默认全部授权,不需要针对该类别再次询问用户是否允许。

常用的权限申请

从Android6.0后,我们常用的权限申请,例如相机权限的申请,代码如下:

// 相机权限 2017/3/8 11:45
public static final int REQUEST_CAMERA = 4;
private static String[] PERMISSIONS_CAMERA = {
        Manifest.permission.CAMERA};

/**
 * 申请相机权限 2017/3/8 11:48
 * @param activity
 */
public static void cameraPermissions(Activity activity) {
    logger.debug("Camera permissions.");
    int permission = ActivityCompat.checkSelfPermission(activity,
            Manifest.permission.CAMERA);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        logger.debug("Not have camera permissions.");
        ActivityCompat.requestPermissions(activity, PERMISSIONS_CAMERA,
                REQUEST_CAMERA);
    }
}

上面是申请相机权限的代码,那么在调用的Activity类中,重写如下方法:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == RequestPermissions.REQUEST_CAMERA) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

        } else {
            Toast.makeText(this, "请授予相机权限", Toast.LENGTH_SHORT).show();
            finish();
        }

        return;
    }

    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

以上就是我们常用的权限申请。

PermissionsDispatcher

权限调度者

使用

在module.build.gradle中配置,如下:

compile 'com.github.hotchemi:permissionsdispatcher:2.3.2'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:2.3.2'

PS

旧版需要在top.build.gradle中配置如下信息:

buildscript {
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

在module.build.gradle中配置,如下:

apply plugin: 'android-apt'

我在最新的版本2.3.2已经不需要以上的配置了,不然会生成失败。等会在下面会讲。

Activity中的使用

package com.example.chenchubin.mypermission;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;

import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.OnNeverAskAgain;
import permissions.dispatcher.OnPermissionDenied;
import permissions.dispatcher.OnShowRationale;
import permissions.dispatcher.PermissionRequest;
import permissions.dispatcher.RuntimePermissions;

@RuntimePermissions
public class ScanQRActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scan);

        // 检查权限 2017/4/13 17:22
        ScanQRActivityPermissionsDispatcher.getCameraWithCheck(this);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
            grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // 回调代理进行处理 2017/4/13 17:22
        ScanQRActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
    }

    /**
     * 已授权时,进入Activity会调用该方法 2017/4/13 17:22
     */
    @NeedsPermission(Manifest.permission.CAMERA)
    public void getCamera() {

    }

    /**
     * 授权申请提示,回调 2017/4/13 17:22
     * @param request
     */
    @OnShowRationale(Manifest.permission.CAMERA)
    public void showRationaleForCamera(final PermissionRequest request) {
        new AlertDialog.Builder(this)
                .setCancelable(false)
                .setTitle("权限申请")
                .setMessage("应用需要使用相机权限,您是否确定要使用")
                .setNegativeButton("拒绝", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        request.cancel();
                    }
                })
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        request.proceed();
                    }
                })
                .setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialog) {

                    }
                })
                .show();
    }

    /**
     * 拒绝时,回调 2017/4/13 17:22
     */
    @OnPermissionDenied(Manifest.permission.CAMERA)
    public void showDeniedForCamera() {
        new AlertDialog.Builder(this)
                .setCancelable(false)
                .setTitle("权限申请")
                .setMessage("在设置-应用-当前应用权限中开启相机权限,以正常使用拍照")
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                })
                .setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //开启设置页
                        startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS));
                        dialog.dismiss();
                    }
                })
                .show();
    }

    /**
     * 不再询问时,回调 2017/4/13 17:23
     */
    @OnNeverAskAgain(Manifest.permission.CAMERA)
    public void showNeverAskForCamera() {
        new AlertDialog.Builder(this)
                .setCancelable(false)
                .setTitle("权限申请")
                .setMessage("您已禁止不再询问,请前往设置-应用-当前应用权限中开启相机权限,以正常使用拍照")
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        finish();
                    }
                })
                .setPositiveButton("去设置", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //开启设置页
                        startActivity(new Intent(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS));
                        dialog.dismiss();
                    }
                })
                .show();
    }
}

注解的意思

@RuntimePermissions
(必选)运行时,需要检查权限的类。

@NeedsPermission
(必选)当进入Activity类时,如果已授权,会直接调用该注解的方法。

@OnShowRationale
(可选)授权申请时,调用。

@OnPermissionDenied
(可选)授权申请被拒绝时,调用。

@OnNeverAskAgain
(可选)授权申请被勾选不再提示时,调用。

PS:

1,执行request.proceed()调用系统申请权限的弹窗;
如果在系统申请弹窗中勾选了不在提示并且拒绝,会调用@OnNeverAskAgain的方法;

2,执行request.cancel()会调用@OnPermissionDenied的方法。

Make Project

Make Project后,编译器会在app\build\intermediates\classes\debug目录下与被注解的Activity同一个包下生成一个辅助类,名称为被注解的Activity名称+PermissionsDispatcher.class,如图所示:

ScanQRActivityPermissionsDispatcher

PS:

这里需要注意,因为我在这里遇到了一个大坑

就是上面提到的,新版中已不需要在top.build.gradle中配置android-apt插件,要不上面的ScanQRActivityPermissionsDispatcher一直没有生成出来,找了我半个小时。。。

生成代理类后,检查调用,代码如下:

// 检查权限 2017/4/13 17:22
ScanQRActivityPermissionsDispatcher.getCameraWithCheck(this);

运行效果

进入检查提示
确定时,提示
拒绝时,提示

这样使用后,Android权限请求这一块的逻辑就变得比较友好。

以上的所有内容就是今天要讲的关于Android6.0权限处理的内容。

我自己在写这文章时,也有所收获,同时希望能对大家有所帮助。

谢谢支持~~~

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

推荐阅读更多精彩内容