Android 6.0+ 运行时权限探索

原创文章,转载请注明 ( 来自:http://blog.csdn.net/leejizhou/article/details/51511630 李济洲的博客 )

引言:去年Android 6.0发布后,其新引入的(Requesting Permissions at Run Time)运行时权限就备受开发者关注,随着今年国内手机厂商对6.0系统的普及,觉得大家有必要了解下这个新特性,因为在TargetSDK23+进行开发不注意这些会造成APP运行在6.0+手机上崩溃,这篇博文将对这个新特性进行探索。

在之前的SDK开发中,如果需要用到一些权限例如打电话,发短信只在AndroidManifest中配置一下就可以了,但是SDK23+以上用到一些危险敏感(Dangerous Permissions)权限就不仅仅是在AndroidManifest配置一下就可以了,需要在操作发生前需要让用户进行授予权限才能进行下一步的操作,跟iOS的权限处理很像,如果没让用户授予权限或用户拒绝了此权限再进行操作例如打电话就会造成软件崩溃。

*如果你的app TargetSDK设置在了23以下那么在6.0+系统中运行是不会崩溃的,当然你也可以TargetSDK一直设置在23以下,那么这篇文章你就没必要继续看了:)

那么到底哪些权限需要进行在运行时进行授权呢?看下官方的说明

Dangerous permissions

以上这些权限不仅仅需要在AndroidManifest配置,还需要在运行时让用户进行授予权限才能使用这些功能。

可以看到打电话是需要进行运行时授权的,我们就做个点击按钮打电话的小demo,看看这个运行时权限到底怎么回事。

1:需要将APP的targetSdkVersion设置到23以上并且在Android6.0以上系统运行

2:在AndroidManifest中配置拨打电话的权限

<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

3:在布局layout中我们就简简单单放个按钮,点击进行拨打电话(略)

4.1:如果不做运行时权限处理会怎么样呢?我们直接进行点击按钮拨打电话

  public void CallPhone(View v) {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + "10010");
        intent.setData(data);
        startActivity(intent);
    }

运行效果:

可以看到在android 6.0系统上运行会崩溃

4.2:我们加上运行时权限的处理再运行

 private static final int REQUESTCODE = 8;

    public void CallPhone(View v) {
        //检查权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED) {

            //没有权限,申请权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.CALL_PHONE},
                    REQUESTCODE);

        } else {
            //已经拥有权限进行拨打
            call();
        }

    }

API:

REQUESTCODE的作用是为了进行回调处理,因为申请权限是有回调结果的后面会说到。

ContextCompat.checkSelfPermission 主要用于检测某个权限是否已经被授予,方法参数为(context,需要检测的权限)方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED,当返回PackageManager.PERMISSION_DENIED时需要调用API进行权限申请。

ActivityCompat.requestPermissions 用于权限的申请,方法参数为(context,需要申请的权限数组,自定义的请求码),系统会弹出一个申请权限的对话框。

运行效果:

可以看到程序已经成功进行了电话的拨打。

4.3 但是如果用户拒绝了此权限并且设置了不再提醒怎么办呢?点击按钮就会没响应了,是非常不友好的,如下。

稍稍改下代码

 public void CallPhone(View v) {
        //检查权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.CALL_PHONE)) {

                new AlertDialog.Builder(MainActivity.this)
                        .setMessage("app需要开启权限才能使用此功能")
                        .setPositiveButton("设置", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                intent.setData(Uri.parse("package:" + getPackageName()));
                                startActivity(intent);
                            }
                        })
                        .setNegativeButton("取消", null)
                        .create()
                        .show();
            } else {

                //申请权限
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.CALL_PHONE},
                        REQUESTCODE);
            }

        } else {
            //已经拥有权限进行拨打
            call();
        }

    }

这里我们在申请权限前加了个判断ActivityCompat.shouldShowRequestPermissionRationale(this,

Manifest.permission.CALL_PHONE)方法参数为(context,需要检测的权限)如果返回true证明用户上次点击已经选了拒绝,所以我们进行一些友好的提示,这里做的是进行进行提示并让用户跳转到设置将权限打开。

运行效果:

5:OK 最后介绍下,申请权限的回调方法处理

 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUESTCODE: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //用户同意了授权
                    call();

                } else {
                    //用户拒绝了授权
                // Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }

    }

这个方法跟onActivityResult比较类似,先判断requestCode,之后在判断用户的授权状态,grantResults数组代表了权限的结果数组,有点绕口,哈哈,之前申请权限是支持数组的,所以 onRequestPermissionsResult的返回结果也放到了一个数组里面,数组grantResults[n] == PackageManager.PERMISSION_GRANTED代表这个权限已经被用户授权了。

final:最后我们看下完整的代码

/**
 * blog:www.lijizhou.com
 */
public class MainActivity extends AppCompatActivity {

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

    }
    private static final int REQUESTCODE = 8;

    public void CallPhone(View v) {
        //检查权限
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.CALL_PHONE)) {

                new AlertDialog.Builder(MainActivity.this)
                        .setMessage("app需要开启权限才能使用此功能")
                        .setPositiveButton("设置", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                intent.setData(Uri.parse("package:" + getPackageName()));
                                startActivity(intent);
                            }
                        })
                        .setNegativeButton("取消", null)
                        .create()
                        .show();
            } else {

                //申请权限
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.CALL_PHONE},
                        REQUESTCODE);
            }

        } else {
            //已经拥有权限进行拨打
            call();
        }

    }

    private void call() {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + "10010");
        intent.setData(data);
        startActivity(intent);

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case REQUESTCODE: {
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //用户同意了授权
                    call();

                } else {
                    //用户拒绝了授权
                // Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
                }
                return;
            }
        }

    }

}

OK,一个利用android原始API进行的运行时权限处理就介绍完了,当然你也可以对此进行封装方便使用,欢迎大家在下方留言,本篇源码下载地址 http://download.csdn.net/detail/leejizhou/9532629

时间: 2024-12-15 07:01:44

Android 6.0+ 运行时权限探索的相关文章

Android 6.0 运行时权限管理最佳实践

Android 6.0 运行时权限管理最佳实践 版权声明:转载必须注明本文转自严振杰的博客: http://blog.yanzhenjie.com 这是一篇迟来的博客,Android M已经发布一年多了(6.0的变化),在Android M中权限系统被重新设计,发生了颠覆性的变化,很多人把握不好这个变化,一是对这个权限策略和套路还没有摸透,二是没有一个很好的实践来支撑,在我的技术开发群里很多人问我关于权限的问题,往往我都没有直接回答,因为这个问题不是一两句说的清楚的,这几点是今天我写这篇博客的原

1.Android6.0运行时权限简介_2.Android6.0权限适配之WRITE_EXTERNAL_STORAGE(SD卡写入)3_.Android 6.0 运行时权限理解

Android6.0运行时权限简介:http://unclechen.github.io/2016/03/05/Android6.0%E8%BF%90%E8%A1%8C%E6%97%B6%E6%9D%83%E9%99%90%E7%AE%80%E4%BB%8B/ Android6.0权限适配之WRITE_EXTERNAL_STORAGE(SD卡写入):https://blog.csdn.net/xiechengfa/article/details/52699233 Android 6.0 运行时权

Android 6.0+ 运行时权限

1.权限被分为了普通和危险两种 2.打电话的Demo import android.Manifest; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; import andro

Android 6.0 运行时权限处理完全解析

一.概述 随着Android 6.0发布以及普及,我们开发者所要应对的主要就是新版本SDK带来的一些变化,首先关注的就是权限机制的变化.对于6.0的几个主要的变化,查看查看官网的这篇文章http://developer.android.com/intl/zh-cn/about/versions/marshmallow/android-6.0-changes.html,其中当然包含Runtime Permissions. ok,本篇文章目的之一就是对运行时权限处理的一个介绍,以及对目前权限相关的库

Android 6.0 运行时权限管理

android 6.0 对权限进行了严格的管理 新的权限策略讲权限分为两类,第一类是不涉及用户隐私的,只需要在Manifest中声明即可,比如网络.蓝牙.NFC等:第二类是涉及到用户隐私信息的,需要用户授权后才可使用,比如SD卡读写.联系人.短信读写等. Normal Permissions 此类权限都是正常保护的权限,只需要在AndroidManifest.xml中简单声明这些权限即可,安装即授权,不需要每次使用时都检查权限,而且用户不能取消以上授权,除非用户卸载App. ACCESS_LOC

Android 6.0 运行时权限处理

运行时权限介绍 Android 6.0在我们原有的AndroidManifest.xml声明权限的基础上,又新增了运行时权限动态检测,以下权限都需要在运行时判断: 身体传感器 日历 摄像头 通讯录 地理位置 麦克风 电话 短信 存储空间 运行时权限处理 Android6.0系统默认为targetSdkVersion小于23的应用默认授予了所申请的所有权限,所以如果你以前的APP设置的targetSdkVersion低于23,在运行时也不会崩溃,但这也只是一个临时的救急策略,用户还是可以在设置中取

Android数据存储之Android 6.0运行时权限下文件存储的思考

前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以往直接sdcard根目录上直接新建了一个xxx/cache/目录来做文件存储就会不是那么容易控制了,所以有必要重新认识一下Android文件存储的相关知识了. 背景: 有关外置sdcard的读写权限 <uses-permission android:name="android.permissi

谈谈Android 6.0运行时权限理解

前言 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授权的不合理,现在6.0出来,使得用户权限授权变得合理.这可能也是参考IOS系统的,只有在用户需要使用权限的时候,才去授权请求,这样做的目的是提高用户体验,当然,用户感觉好了,受苦的是我们开发人员,原来的规则不适用了,现在我们去适应新的规则,毕竟是靠谷歌这颗大树吃饭的嘛. 原来权限模型 在Android 6.0版本之前,

Android 6.0运行时权限简析及最佳实践

1.前言 从Android 6.0(API 23)开始,对系统权限做了很大的改变.在之前用户安装APP前,只是把APP需要使用的权限列出来给用户告知一下,APP安装后都可以访问这些权限.从6.0开始,一些敏感权限,需要在使用时动态申请,并且用户可以选择拒绝授权访问这些权限,已授予过的权限,用户也可以去APP设置页面去关闭授权.这对用户来说提高了安全性,可以防止一些应用恶意访问用户数据,但是对于开发来说,也增加了不少工作量,这块不做适配处理的话,APP在访问权限的时候会容易crash. 2.权限等