这也许是Android权限适配更简单的解决方案

背景

关于运行时的权限不用多说,这个概念已经很久,近期工信部在强推TargetSDK26,我这边做了一些适配工作,其中有一项就是运行时权限,今天将对运行时权限提供一个更优雅的解决方案,如果你还不了解运行时权限,请移步:Android运行时权限浅谈

现状:

以直接调用打电话功能为例

首先我们项目中可能会有这么一个方法:

    /**
     * 拨打指定电话
     */
    public static void makeCall(Context context, String phoneNumber) {
   
   
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + phoneNumber);
        intent.setData(data);
        if (!(context instanceof Activity)) {
   
   
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        context.startActivity(intent);
    }

那么在适配动态权限以前,在我们任意用到打电话的业务页面我们可能就是这么用:

 public void makeCall() {
   
   
     Utils.makeCall(BeforeActivity.this, "10086");
    }

于是乎,某一天,我们应用要适配targetSdk 26,首先我们要适配的就是动态权限,所以下面的代码就会变成这样:

  public void makeCall() {
   
   
        //6.0以下 直接即可拨打
        if (android.os.Build.VERSION.SDK_INT < M) {
   
   
            Utils.makeCall(BeforeActivity.this, "10086");
        } else {
   
   
            //6.0以上
            if (ContextCompat.checkSelfPermission(BeforeActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
   
   
                ActivityCompat.requestPermissions(BeforeActivity.this, new String[]{
   
   Manifest.permission.CALL_PHONE},
                        REQUEST_CODE_CALL);
            } else {
   
   
                Utils.makeCall(BeforeActivity.this, "10086");
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
   
   
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CODE_CALL) {
   
   
            if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
   
   
                Toast.makeText(BeforeActivity.this, "本次拨打电话授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show();
            } else {
   
   
                Utils.makeCall(BeforeActivity.this, "10086");
            }
        }
    }

以上就是拨打电话功能新老权限版本的基本实现(还不包括shouldShowRequestPermissionRationale的部分)。
目前也有一些知名的开源库,如PermissionsDispatcher,RXPermission等。虽然也能实现我们的功能,但无论自己适配还是现有开源库方案大体上都会或多或少有以下几个问题:

现有权限库存在的问题:
  • 每个页面都要重写onPermissionResult方法、维护requestCode、或者第三方库封装的onPermissionResult方法,如果项目庞大,适配到每个业务点会非常繁琐。
  • 权限申请还区分Activity和Fragment,又要分别处理
  • 每个权限都要写大量的if else代码去做版本判断,判断新老机型分别处理

基于第一个业务繁琐的问题,很多应用选择适配权限的时候,把所用到的敏感权限放在一个特定的页面去申请,比如欢迎页(某知名音乐播放器等),如果授权不成功,则会直接无法进入应用,这样虽然省事,但是用户体验不好,我在应用一打开,提示需要电话权限,用户会很疑惑。这样其实就违背了“运行时授权”的初衷,谷歌希望我们在真正调用的该功能的时候去请求,这样权限请求和用户的目的是一致的,也更容易授予权限成功。

那么能不能做到如下几个点呢?

对权限适配的期望:
  • 基于用户体验考虑,我不希望在应用一打开就向用户索取一堆授权,异或是跳一个页面专门去授权、困扰我们宝贵的用户
  • 不需要去重写onPermissionResult、甚至不需要Activity和Fragment。
  • 去除版本判断。无论什么系统版本的新老手机,都是走一个方法
  • 一行代码完成从权限检查、请求、到最终完我要做的事情
  • 我不需要在原有项目中改太多代码

带着上述几个问题,我们今天的主角:SoulPermission应运而生。

当使用了SoulPermission以后,最直观上看,我们上面的代码就变成了这样:

 public void makeCall() {
   
   
        SoulPermission.getInstance()
                .checkAndRequestPermission(Manifest.permission.CALL_PHONE, new CheckRequestPermissionListener() {
   
   
                    @Override
                    public void onPermissionOk(Permission permission) {
   
   
                        Utils.makeCall(AfterActivity.this, "10086");
                    }

                    @Override
                    public void onPermissionDenied(Permission permission) {
   
   
                        Toast.makeText(AfterActivity.this, "本次拨打电话授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show();
                    }
                });
    }

SoulPermission:

优势:
  • 解耦Activity和Fragment、不再需要Context、不再需要onPermissionResult
  • 内部涵盖版本判断,一行代码解决权限相关操作,无需在调用业务方写权限适配代码,继而实现真正调用时请求的“真运行时权限”
  • 接入成本低,零入侵,仅需要在gradle配置一行代码
工作流程:

如果我以在Android手机上要做一件事(doSomeThing),那么我最终可以有两个结果:

  • A:可以做
  • B:不能做

基于上述两种结果,那么SoulPermission的大致工作流程如下:

在这里插入图片描述

从开始到结束展示了我们上述打电话的流程,A即直接拨打,B即toast提示用户,无法继续后续操作,绿色部分流程即可选部分,即对shouldShowRequestPermissionRationale的处理,那么完整权限流程下来,我们拨打电话的代码就是这么写:

   public void makeCall() {
   
   
        SoulPermission.getInstance()
                .checkAndRequestPermission(Manifest.permission.CALL_PHONE, new CheckRequestPermissionListener() {
   
   
                    @Override
                    public void onPermissionOk(Permission permission) {
   
   
                        Utils.makeCall(AfterActivity.this, "10086");
                    }

                    @Override
                    public void onPermissionDenied(Permission permission) {
   
   
                        //绿色框中的流程
                        //用户第一次拒绝了权限且没有勾选"不再提示"的情况下这个值为true,此时告诉用户为什么需要这个权限。
                        if (permission.shouldRationale()) {
   
   
                            new AlertDialog.Builder(AfterActivity.this)
                                    .setTitle("提示")
                                    .setMessage("如果你拒绝了权限,你将无法拨打电话,请点击授予权限")
                                    .setPositiveButton("授予", new DialogInterface.OnClickListener() {
   
   
                                        @Override
                                        public void onClick(DialogInterface dialogInterface, int i) {
   
   
                                            //用户确定以后,重新执行请求原始流程
                                            makeCall();
                                        }
                                    }).create().show();
                        } else {
   
   
                            Toast.makeText(AfterActivity.this, "本次拨打电话授权失败,请手动去设置页打开权限,或者重试授权权限", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值