Android 6.0 权限 运行流畅 介绍

本文详细介绍Android 6.0中新增的运行时权限申请机制,包括检查权限状态、请求权限及处理权限请求结果的具体步骤,并提供了一个完整的权限申请示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 6.0 权限 运行流畅 介绍

总所周知,Android 在6.0的时候添加了权限申请机制,默认情况下,系统是没有给你这些权限的。在你需要使用这些权限的时候,是需要申请了,不然会很悲剧。

举个栗子
比如你需要定位,如果你不获取定位权限,那么你是获取到的经纬度可能是0 and 0
在比如,在分享的时候,如果缺少对应的权限,会直接失败
在比如 …(此处省略1万个字)

总之运行时权限的申请在6.0越来越普及的今天,已经成为一个必不可少的技能了。

关于6.0权限详细解析,请参考下面几篇文献,这里篇文章主要介绍一下权限申请时候的流程。
详解Android 6.0运行时权限
Android 6.0运行时权限详解

首先先放两张效果图
mi 5
nexus 6

两部手机运行的程序为一份代码,且都是7.0的系统 ,但是由于厂家优化问题,所呈现的效果有着巨大的差异。这里我使用Google 亲儿子作为讲解。

首先要先介绍三个方法

checkSelfPermission

    /**
     * Determine whether <em>you</em> have been granted a particular permission.
     *
     * @param permission The name of the permission being checked.
     *
     * @return {@link android.content.pm.PackageManager#PERMISSION_GRANTED} if you have the
     * permission, or {@link android.content.pm.PackageManager#PERMISSION_DENIED} if not.
     *
     * @see android.content.pm.PackageManager#checkPermission(String, String)
     */
    public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
        if (permission == null) {
            throw new IllegalArgumentException("permission is null");
        }

        return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());
    }

我相信看不懂这堆鸟文的不只我一个 ,现在我就来解释解释。

这个方法主要是用于检测 是否具备某个权限。
如果返回值 == PackageManager.PERMISSION_GRANTED,那就恭喜你,app已经获取到了相应的权限。
相反,如果 != 则需要申请权限。
举个栗子

ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED

shouldShowRequestPermissionRationale

这个方法很有意思

    /**
     * Gets whether you should show UI with rationale for requesting a permission.
     * You should do this only if you do not have the permission and the context in
     * which the permission is requested does not clearly communicate to the user
     * what would be the benefit from granting this permission.
     * <p>
     * For example, if you write a camera app, requesting the camera permission
     * would be expected by the user and no rationale for why it is requested is
     * needed. If however, the app needs location for tagging photos then a non-tech
     * savvy user may wonder how location is related to taking photos. In this case
     * you may choose to show UI with rationale of requesting this permission.
     * </p>
     *
     * @param activity The target activity.
     * @param permission A permission your app wants to request.
     * @return Whether you can show permission rationale UI.
     *
     * @see #checkSelfPermission(android.content.Context, String)
     * @see #requestPermissions(android.app.Activity, String[], int)
     */
    public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,
            @NonNull String permission) {
        if (Build.VERSION.SDK_INT >= 23) {
            return ActivityCompatApi23.shouldShowRequestPermissionRationale(activity, permission);
        }
        return false;
    }

英语好的可以直接啃api 。

这个方法我的理解是这样的
默认返回 false ,也就是什么都没发生的时候;
被拒绝了 ,用户没有勾选 do't ask again ,返回 true;
do't ask again 拒绝了,返回false;

个人认为这个申请API中最麻烦的就是这玩意了。

requestPermissions

    //这个源码太多了,我就不放了
requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)

这个方法主要作用是用于申请权限

从参数 String[] permissions 上可以发现,这个方法可以一次性申请多个权限,但是官方并不推荐这样做。

同样,参数 requestCode 说明这种申请方式 与 startActivityForResult 是一样的。

友情提醒, requestCode 不要太大,Can only use lower 16 bits for requestCode

onRequestPermissionsResult

onRequestPermissionsResult(int requestCode,String[] permissions,int[] grantResults)

这个方法是 FragmentActivity 中的方法,所以如果申请了权限,需要重写这个方法来获取申请的结果。

最终申请的结果都放在了 grantResults 之中,如果这个数组中的值 == PackageManager.PERMISSION_GRANTED ,就说明获取了权限,反之亦然。

栗子

首先要申请权限,那就需要现在Manifest中进行注册,比如我想GET这两个权限。

    <!--用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!--用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

在主页面中建个按钮,用于开始申请权限。代码很简单,我就不贴了。

在代码中先定义这两个权限

String pNet = Manifest.permission.ACCESS_FINE_LOCATION;
String pGPS = Manifest.permission.ACCESS_COARSE_LOCATION;

因为会多次使用,所以先偷个懒先。

点击事件代码

    @Override
    public void onClick(View v)
    {
        if (ActivityCompat.checkSelfPermission(this, pNet) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, pGPS) != PackageManager.PERMISSION_GRANTED)
        {
            if (shouldShowRequest())
            {
                //被拒绝了一次
                mHintDialog.setMessage("被拒绝过了,但是还是可以申请权限")//
                        .setPositiveButton("确定", new RequestPermissionsClick())//
                        .show();
            } else
            {
                //第一次申请权限
                 //被无限拒绝
                 //都会到这里来
                mHintDialog.setMessage("我想要个权限申请权限")//
                        .setPositiveButton("确定", new RequestPermissionsClick())//
                        .show();
            }
        } else
        {
            mHintDialog.setMessage("你已经拥有权限了,不用瞎申请了")//
                    .setPositiveButton("确定", null)//
                    .show();
        }
    }
shouldShowRequest()
private boolean shouldShowRequest()
    {
        return ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
    }
RequestPermissionsClick
private class RequestPermissionsClick implements DialogInterface.OnClickListener
    {
        @Override
        public void onClick(DialogInterface dialog, int which)
        {
             //这里是不提倡的写法
            String[] p = {pNet, pGPS};
            ActivityCompat.requestPermissions(MainActivity.this, p, GET_LOCATION_REQUEST_CODE);
        }
    }

首先 通过 checkSelfPermission 判断是否拥有权限
在没有权限的情况下
可以通过判断 shouldShowRequestPermissionRationale 判断状态
如果返回 false ,说明可能是第一次,也可能是被宣判再也无法申请权限了。
如果返回 true , 说明被拒绝过,还可以在申请权限
最后都点击事件都执行 requestPermissions 进行权限的申请。

Created with Raphaël 2.1.0 开始 checkSelfPermission 拥有权限 shouldShowRequestPermissionRationale 已经被拒绝,但是还能申请权限 最后他们都能够调用申请权限方法,但被无限拒绝的不会再弹出提示框 申请权限 requestPermissions 第一次,或者被无限拒绝 yes no yes no

一般情下,在 shouldShowRequestPermissionRationale 返回fasle的时候我们会告诉用户我们需要什么权限。当然,用作可能并不会给予我们权限,所以在返回true的时候,我们还有补救的机会。也就是像用户解释,我们为什么需要这个权限。

onRequestPermissionsResult

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

        if (requestCode == GET_LOCATION_REQUEST_CODE)
        {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                mHintDialog.setMessage("获取权限成功")//
                        .setPositiveButton("确定", null)//
                        .show();
            } else
            {
                if (shouldShowRequest())
                {
                    //被拒绝了一次
                    mHintDialog.setMessage("虽然被拒绝了,但是还有的救")
                            .setPositiveButton("确定", new RequestPermissionsClick())//
                            .show();
                } else
                {
                    //已经被无限拒绝了
                    mHintDialog.setMessage("已经被彻底拒绝了")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener()
                            {
                                @Override
                                public void onClick(DialogInterface dialog, int which)
                                {
                                    Uri packageURI = Uri.parse("package:" + MainActivity.this.getPackageName());
                                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
                                    startActivity(intent);
                                }
                            })//
                            .show();
                }
            }
        }

    }

到这里 shouldShowRequestPermissionRationale 就不会出现应为默认而返回false 的情况下了,所以 当 shouldShowRequestPermissionRationale 返回false,就代表真的无法申请权限了,只有让用户自己开启权限。如果返回true,还可以通过提示引导用户授予权限。

Created with Raphaël 2.1.0 shouldShowRequestPermissionRationale 虽然被拒绝了,但还可以申请权限 申请权限 requestPermissions 只有让用户自己开启权限 yes no

需要注意的是 grantResults.length是有可能为0的,也就是可能为空。

至此,权限申请的全部流程已经讲解完毕,最后附上鄙人的Code:


import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
    String pNet = Manifest.permission.ACCESS_FINE_LOCATION;
    String pGPS = Manifest.permission.ACCESS_COARSE_LOCATION;
    //Can only use lower 16 bits for requestCode
    final int GET_LOCATION_REQUEST_CODE = 123;
    AlertDialog.Builder mHintDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnClickListener(this);
        mHintDialog = new AlertDialog.Builder(this)//
                .setTitle("提示")//
        ;
    }

    @Override
    public void onClick(View v)
    {
        if (ActivityCompat.checkSelfPermission(this, pNet) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(this, pGPS) != PackageManager.PERMISSION_GRANTED)
        {
            if (shouldShowRequest())
            {
                //被拒绝了一次
                mHintDialog.setMessage("被拒绝过了,但是还是可以申请权限")//
                        .setPositiveButton("确定", new RequestPermissionsClick())//
                        .show();
            } else
            {
                //第一次申请权限
                //被无限拒绝
                //都会到这里来
                mHintDialog.setMessage("我想要个权限申请权限")//
                        .setPositiveButton("确定", new RequestPermissionsClick())//
                        .show();
            }
        } else
        {
            mHintDialog.setMessage("你已经拥有权限了,不用瞎申请了")//
                    .setPositiveButton("确定", null)//
                    .show();
        }
    }

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

        if (requestCode == GET_LOCATION_REQUEST_CODE)
        {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                mHintDialog.setMessage("获取权限成功")//
                        .setPositiveButton("确定", null)//
                        .show();
            } else
            {
                if (shouldShowRequest())
                {
                    //被拒绝了一次
                    mHintDialog.setMessage("虽然被拒绝了,但是还有的救")
                            .setPositiveButton("确定", new RequestPermissionsClick())//
                            .show();
                } else
                {
                    //已经被无限拒绝了
                    mHintDialog.setMessage("已经被彻底拒绝了")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener()
                            {
                                @Override
                                public void onClick(DialogInterface dialog, int which)
                                {
                                    Uri packageURI = Uri.parse("package:" + MainActivity.this.getPackageName());
                                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageURI);
                                    startActivity(intent);
                                }
                            })//
                            .show();
                }
            }
        }

    }

    private boolean shouldShowRequest()
    {
        return ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_COARSE_LOCATION) && ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION);
    }

    private class RequestPermissionsClick implements DialogInterface.OnClickListener
    {
        @Override
        public void onClick(DialogInterface dialog, int which)
        {
            String[] p = {pNet, pGPS};
            ActivityCompat.requestPermissions(MainActivity.this, p, GET_LOCATION_REQUEST_CODE);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值