android 6.0动态权限

权限大全看这里:

权限科普文看这里:


自打 API 23(6.0)之后,android 权限必须要动态去获取啦,变化真的是好大,刚开始真是不适应

6.0 之后把权限分成2种:

  • Normal : 普通权限
  • Dangerous : 危险权限
20160719205241606.png

Normal 的权限和以前使用的方式一样,在配置文件里声明系统就会给,但是Dangerous 的权限就不行了,google 把涉及到用户隐私的权限都划归到 Dangerous 里面了,我们仅仅在配置文件里声明的话,使用到这个权限的代码就会直接 carsh ,蛋疼的设计。

Dangerous 权限范围:

  • calendar 时间(日历)
  • camera 相机
  • contacts 联系人(读,写,获取通讯录)
  • location (获取定位)
  • microphone (麦克风即话筒)
  • phone(电话)
  • sensors 传感器sms
  • storage 存储


    2950322-ca99c0b1d1ab831b.png

看到没,这么多的权限都变成为危险权限了,都需要我们去特殊处理,还都是我们最常用的。


6.0 权限适配

早期做法

我们把 targetSDKVersion<23 的时候,会和4.X 版本一样,仅在安装时赋予权限,使用时将不被提醒,当targetSDKVersion≥23的时候才会使用新的运行时权限规则,但是这种并不是Google所推荐使用的。

 compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.whoislcj.rxpermissions"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }

实测这招可以,就是在我们使用 studio 打包安装时会提示安装失败,我们多装几次就行。

6.0 适配

google 已经给我们提供好线程的 API 啦,我们按照下面的套路来就行,话说现在社会真是套路的社会,去哪哪套路,敲代码也都是套路。

判断是否是Android 6.0以上

 private boolean isSDK2API23() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

获取权限对应字符串

 String permission = Manifest.permission.CAMERA;

我们去 Manifest 这个类里去找好了

检查用户是否给了改权限

  private boolean isHavePermission(Context context, String permission) {
        return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, permission);
    }

ContextCompat.checkSelfPermission,主要用于检测某个权限是否已经被授予,方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED。当返回DENIED就需要进行申请授权了。

申请权限

 ActivityCompat.requestPermissions(this, new String[]{permission}, permissionRequestCode);

用户没给这个权限,判断是不是用户上次选择不再显示了

private boolean isUserNoShowPermissionDialig(Activity activity, String permission) {
        return !(ActivityCompat.shouldShowRequestPermissionRationale(activity, permission));
    }

为啥要用这个方法呢,因为用户在系统弹出的权限对话框中要是选了不再显示,那么我们再去申请这个权限的话,系统就不会弹出的权限对话框了,会直接替用户选择不给了。我们用这个方法可以判断出用户上次点没点不再显示这个选项,要是点了,那么我们通常的做法就是打开这个 app 对应的权限管理页,让用户去手动给这个权限。

注意这个方法返回 true 时,说明用户上次点了不再显示这个选项

打开这个 app 对应的权限管理页

private void startAppSettingActivity(Activity activity) {
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + activity.getPackageName()));

        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        activity.startActivityForResult(intent, 100);
    }

接受用户权限选择的结果

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == permissionRequestCode) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "您同意该权限", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "您不给该权限会出问题的", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

系统弹的权限对话框本质是一个 dialog 样式的 activity,使用 startActivityForResult 方法启动的,页面关闭返回一个记结果,所以我们只好重写 activity 的 onRequestPermissionsResult 方法

这点是我觉得系统最尼玛 SB 的设计,google 你就不能给自己一个全局弹窗的权限,真的谈一个 dialog 出来,多了 activity 的这个方法,代码怎么封装啊,这样的写法上太有侵入性了。

5.x 怎么适配

上面的做法是6.0以上的做法,但是国产好多手机在 5.X 上就集成了权限管理了,用刚刚的这段代码,你会发现用户就是不给这个权限,结果也是给了,实际是无法判断出来的。所以才会去限定 sdk 版本。但是我们真的要适配5.X 怎么办?


最后

最后啦,我把全部代码贴出来,这个写法只是让大家了解关于权限的基本 API,不是最终的写法, 之后我还写后续文章的

public class MainActivity extends AppCompatActivity {

    int permissionRequestCode = 200;

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

    public void checkPermission(View view) {

        if (!isSDK2API23()) {
            return;
        }

        String permission = Manifest.permission.CAMERA;

        if (!isHavePermission(this, permission)) {
            if (isUserNoShowPermissionDialig(this, permission)) {
                startAppSettingActivity(this);
            } else {
                ActivityCompat.requestPermissions(this, new String[]{permission}, permissionRequestCode);
            }
        } else {
            Toast.makeText(MainActivity.this, "已获取该权限", Toast.LENGTH_SHORT).show();
        }
    }

    private boolean isSDK2API23() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    private boolean isHavePermission(Context context, String permission) {
        return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, permission);
    }

    private boolean isUserNoShowPermissionDialig(Activity activity, String permission) {
        return !(ActivityCompat.shouldShowRequestPermissionRationale(activity, permission));
    }

    private void startAppSettingActivity(Activity activity) {
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + activity.getPackageName()));

        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
        activity.startActivityForResult(intent, 100);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == permissionRequestCode) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "您同意该权限", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "您不给该权限会出问题的", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}

参考文章

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

推荐阅读更多精彩内容