App实战:权限管理再封装之一键调用

App实战:权限管理再封装之一键调用

一直以来我对于权限申请这方面我都是在用着谷歌官方开源的EasyPermissions这个库,其实它的内部算是比较简单,内部是把一些Android SDK自带的权限方法封装了起来。如果只是想看关于这个库的使用,可以看一下我之前写的一篇博客App实战:动态申请权限以及为所欲为之终极扩展。这里首先我对这个库的流程做一个总结,如下图所示:

App实战:权限管理再封装之一键调用_第1张图片
虽然说逻辑上比较简单,但是我们现在很多App都是在动态申请权限,所以说用到的地方多了还是回感觉到有一些繁琐的。所以我想给EasyPermissions进行二次封装,目的当然是为了简单易用。那么如何封装呢?

开始封装

首先回到封装的定义:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体。反正我是看到这个定义后我就明白了,封装就是你把程序需要的参数传进去,里面怎么处理外部不需要操心就能得到一个结果。所以第一步是要弄清楚权限申请需要什么参数,要想弄清楚需要什么参数就得知道EasyPermissions这一套下来调用那些方法。我们一一来理清楚:

  • 检测权限。
/**
 * Check if the calling context has a set of permissions.
 *
 * @param context the calling context.
 * @param perms   one ore more permissions, such as {@link Manifest.permission#CAMERA}.
 * @return true if all permissions are already granted, false if at least one permission is not
 * yet granted.
 * @see Manifest.permission
 */
public static boolean hasPermissions(Context context, @NonNull String... perms)

需要context和你需要申请的权限。2个参数。

  • 申请权限。
public static void requestPermissions(@NonNull Fragment host, @NonNull String rationale,
        int requestCode, @NonNull String... perms) {

    requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel,
            requestCode, perms);
}

这里需要注意的是我申请权限的地方是在一个内部fragment,这个方案也是来自网络开源,据说最早使用的是Rxpermission库。需要一个fragment(不算,这个不是外部传进去的),一个rationale权限解释和一个requestCode请求码。2个参数。

  • 权限申请的回调,授予还是拒绝。
/**
 * Callback interface to receive the results of {@code EasyPermissions.requestPermissions()}
 * calls.
 */
public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback {

    void onPermissionsGranted(int requestCode, List perms);

    void onPermissionsDenied(int requestCode, List perms);

}

1个参数。

所以加起来一个有5个参数,如果按照正常的封装大概就是PermissionHelper.request(param1,param2,param3,param4,param5,);,但是很显然一个方法参数多了会导致调用者不太舒服的,所以我采用了builder建造者模式。这里面没有什么难点,需要注意的是空UI的Fragment的创建方法是如下所示的:

public static void addNoUiFgToActivity(@NonNull FragmentManager fragmentManager, @NonNull Fragment fragment,
                                       String tag)
{
    checkNotNull(fragmentManager);
    checkNotNull(fragment);
    FragmentTransaction transaction = fragmentManager.beginTransaction();
    transaction.add(fragment, tag);
    transaction.commit();
}

并且我在里面利用的这个空Fragment来申请权限,所以这个Fragment需要实现EasyPermissions.PermissionCallbacks接口。还有一点EasyPermissions.PermissionCallbacks接口里面有3个方法,而我只需要其中两个,所以写了一个抽象类实现了其中一个空方法

public abstract static class PermissionListener implements EasyPermissions.PermissionCallbacks
{
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
            grantResults)
    {
    }
}

我们传入的5个参数中的那个回调参数就是实现这个匿名内部类。这里记一下最开始犯的一个很zz的错误,就是我想把这个参数传递给Fragment的时候,我采用了setArgument的方式,然后很sb的让这个抽象类实现Serializable接口就是序列化,后面就有一直报错。请教了一下大佬,大佬也是说我是不是对序列化有什么误解,确实是自己对这块没理解深刻。Java序列化:Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。

图就不上了,可以看以前的那篇博客,效果都是一样的。最后针对录音权限代码调用如下,真的非常简单了,多权限申请也是一样的,因为权限参数是一个String数组:

public static final int RECORD_CODE = 1;
String[] recordPerm = {Manifest.permission.RECORD_AUDIO};

private void record()
{
    PermissionHelper.init(this)
            .permissions(recordPerm)
            .rationale("录音权限")
            .requestCode(RECORD_CODE)
            .permissionListener(new PermissionHelper.PermissionListener()
            {
                @Override
                public void onPermissionsGranted(int requestCode, List perms)
                {
                   //权限已授予
                }

                @Override
                public void onPermissionsDenied(int requestCode, List perms)
                {
                    //权限被拒绝,或者点击解释框取消按钮时都会调用此方法
                }
            }).build().request();
}

整个帮助类的代码如下:

public class PermissionHelper
{

    public static final String TAG = "PermissionHelper";

    private Context mContext;
    private String[] mPerms;
    private PermissionListener mPermissionListener;
    private String mRationale;
    private int mRequestCode;
    private PermissionFragment mPermissionFragment;
    private List permsList;

    public static Builder init(FragmentActivity context)
    {
        Builder mBuilder = new Builder(context);
        return mBuilder;
    }

    private PermissionHelper(Builder builder)
    {
        mContext = builder.mContext;
        mPerms = builder.mPerms;
        mPermissionListener = builder.mPermissionListener;
        mRationale = builder.mRationale;
        mRequestCode = builder.mRequestCode;
        mPermissionFragment = builder.mPermissionFragment;
        permsList = builder.permsList;
    }

    public void request()
    {
        if (EasyPermissions.hasPermissions(mContext, mPerms))
        {
            mPermissionListener.onPermissionsGranted(mRequestCode, permsList);
        } else
        {
            Observable.timer(50, TimeUnit.MILLISECONDS).subscribe(new Consumer()
            {
                @Override
                public void accept(Long aLong) throws Exception
                {
                    EasyPermissions.requestPermissions(mPermissionFragment, mRationale, mRequestCode, mPerms);
                }
            });
        }
    }

    public static class Builder
    {
        private FragmentActivity mContext;
        private String[] mPerms;
        private PermissionListener mPermissionListener;
        private String mRationale;
        private int mRequestCode;
        private PermissionFragment mPermissionFragment;
        private List permsList = new ArrayList<>();

        public Builder(FragmentActivity context)
        {
            this.mContext = context;
        }

        public Builder permissionListener(PermissionListener perssionListener)
        {
            this.mPermissionListener = perssionListener;
            return this;
        }

        public Builder permissions(String[] pers)
        {
            this.mPerms = pers;
            for (String perm : mPerms)
            {
                permsList.add(perm);
            }
            return this;
        }

        public Builder rationale(String rationale)
        {
            this.mRationale = rationale;
            return this;
        }

        public Builder requestCode(int requestCode)
        {
            this.mRequestCode = requestCode;
            return this;
        }

        public PermissionHelper build()
        {
            FragmentManager fragmentManager = mContext.getSupportFragmentManager();
            mPermissionFragment = (PermissionFragment) fragmentManager.findFragmentByTag(TAG);
            if (mPermissionFragment == null)
            {
                mPermissionFragment = PermissionFragment.newInstance();
                mPermissionFragment.setPermissionListener(mPermissionListener);
                ActivityUtils.addNoUiFgToActivity(fragmentManager, mPermissionFragment, TAG);
            }
            return new PermissionHelper(this);
        }

    }

    public abstract static class PermissionListener implements EasyPermissions.PermissionCallbacks
    {
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
                grantResults)
        {
        }
    }

    public static class PermissionFragment extends Fragment implements EasyPermissions.PermissionCallbacks
    {

        PermissionListener mPermissionCallbacks;

        public static PermissionFragment newInstance()
        {
            Bundle args = new Bundle();
            PermissionFragment fragment = new PermissionFragment();
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
        }

        public void setPermissionListener(PermissionListener permissionListener)
        {
            this.mPermissionCallbacks = permissionListener;
        }

        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState)
        {
            super.onActivityCreated(savedInstanceState);
            L.e("onActivityCreated(" + TAG + ".java:" + Thread.currentThread().getStackTrace()[2].getLineNumber() +
                    ")" + "");
        }

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

        @Override
        public void onPermissionsGranted(int requestCode, List perms)
        {
            mPermissionCallbacks.onPermissionsGranted(requestCode, perms);
        }

        @Override
        public void onPermissionsDenied(int requestCode, List perms)
        {
            mPermissionCallbacks.onPermissionsDenied(requestCode, perms);
        }
    }

}

总结

重温了下Android中对权限申请的机制,学习了空Fragment的使用,更加明白了封装的含义,也知道了Java序列化的基本机制。更加开心的是,每一次用着自己亲自动手封装的东西,真的那种愉悦感是很爽的啊。

Github Demo

如果对你有帮助,不要吝啬你的赞哦。
上一篇博客:
App实战:夜间模式实现方法一
下一篇博客:Android Studio一些使用技巧

你可能感兴趣的:(Android实战开发)