【源码阅读】AndPermission源码阅读

栏目: 软件资讯 · 发布时间: 5年前

内容简介:权限是绝大多数App必不可少的部分,不管你仍在用原生的方式,还是其他的开源库,AndPermission绝对是值得学习的一个开源库,今天,我们就来学习下它的设计思想。权限库的思路大体上都如下图所示,也玩不出太复杂的花样。

权限是绝大多数App必不可少的部分,不管你仍在用原生的方式,还是其他的开源库,AndPermission绝对是值得学习的一个开源库,今天,我们就来学习下它的设计思想。

AndPermission

思路

权限库的思路大体上都如下图所示,也玩不出太复杂的花样。

【源码阅读】AndPermission源码阅读

使用

implementation 'com.yanzhenjie.permission:support:2.0.1'
AndPermission.with(this)
            .runtime()
            .permission(permissions)
            .rationale(new RuntimeRationale())
            .onGranted(new Action<List<String>>() {
                @Override
                public void onAction(List<String> permissions) {
                    toast(R.string.successfully);
                }
            })
            .onDenied(new Action<List<String>>() {
                @Override
                public void onAction(@NonNull List<String> permissions) {
                    toast(R.string.failure);
                    if (AndPermission.hasAlwaysDeniedPermission(MainActivity.this, permissions)) {
                        showSettingDialog(MainActivity.this, permissions);
                    }
                }
            })
            .start();
复制代码
  • 3.安装应用
private void installPackage() {
        AndPermission.with(this)
            .install()
            .file(new File(Environment.getExternalStorageDirectory(), "android.apk"))
            .rationale(new InstallRationale())
            .onGranted(new Action<File>() {
                @Override
                public void onAction(File data) {
                    // Installing.
                    toast(R.string.successfully);
                }
            })
            .onDenied(new Action<File>() {
                @Override
                public void onAction(File data) {
                    // The user refused to install.
                    toast(R.string.failure);
                }
            })
            .start();
    }
复制代码
  • 4.应用上显示(悬浮窗)
private void requestPermissionForAlertWindow() {
        AndPermission.with(this).overlay().rationale(new OverlayRationale()).onGranted(new Action<Void>() {
            @Override
            public void onAction(Void data) {
                toast(R.string.successfully);
                showAlertWindow();
            }
        }).onDenied(new Action<Void>() {
            @Override
            public void onAction(Void data) {
                toast(R.string.failure);
            }
        }).start();
    }
复制代码
  • 5.修改系统设置
private void requestWriteSystemSetting() {
        AndPermission.with(this).setting().write().rationale(new WriteSettingRationale()).onGranted(new Action<Void>() {
            @Override
            public void onAction(Void data) {
                toast(R.string.successfully);
            }
        }).onDenied(new Action<Void>() {
            @Override
            public void onAction(Void data) {
                toast(R.string.failure);
            }
        }).start();
    }
复制代码
  • 6.通知
private void requestNotificationListener() {
        AndPermission.with(this)
            .notification()
            .listener()
            .rationale(new NotifyListenerRationale())
            .onGranted(new Action<Void>() {
                @Override
                public void onAction(Void data) {
                    toast(R.string.successfully);
                }
            })
            .onDenied(new Action<Void>() {
                @Override
                public void onAction(Void data) {
                    toast(R.string.failure);
                }
            })
            .start();
    }
复制代码

源码分析

  • 1. with 方法
public static Option with(Context context) {
        return new Boot(getContextSource(context));
    }
public static Option with(Fragment fragment) {
        return new Boot(new SupportFragmentSource(fragment));
    }
public static Option with(android.app.Fragment fragment) {
        return new Boot(new FragmentSource(fragment));
    }
public static Option with(Activity activity) {
        return new Boot(new ActivitySource(activity));
    }
复制代码

with 方法可以传入 ContextFragmentandroid.app.Fragment fragmentActivity ,返回的都是 Option 对象,而它是个接口,我们来看看 Option 的实现类 Boot

public class Boot implements Option {
    public Boot(Source source) {
        this.mSource = source;
    }
    @Override
    public RuntimeOption runtime() {
        return new Runtime(mSource);
    }
    @Override
    public InstallRequest install() {
        return INSTALL_REQUEST_FACTORY.create(mSource);
    }
    @Override
    public OverlayRequest overlay() {
        return OVERLAY_REQUEST_FACTORY.create(mSource);
    }
    @Override
    public NotifyOption notification() {
        return new Notify(mSource);
    }
    @Override
    public Setting setting() {
        return new Setting(mSource);
    }
}
复制代码

可以看到,这里对不同的 Request 做了封装,对以后的扩展非常有利,这也是AndPermission的亮点之一。

之前传入的 ContextFragmentandroid.app.Fragment fragmentActivity 只影响的 startActivitystartActivityForResultisShowRationalePermission 方法

Source 相关代码

public abstract void startActivity(Intent intent);

    public abstract void startActivityForResult(Intent intent, int requestCode);

    public abstract boolean isShowRationalePermission(String permission);
复制代码

ActivitySource 相关代码

public class ActivitySource extends Source {

    @Override
    public void startActivity(Intent intent) {
        mActivity.startActivity(intent);
    }
    @Override
    public void startActivityForResult(Intent intent, int requestCode) {
        mActivity.startActivityForResult(intent, requestCode);
    }
    @Override
    public boolean isShowRationalePermission(String permission) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
        return mActivity.shouldShowRequestPermissionRationale(permission);
    }
}
复制代码
  • 2. permission
@Override
    public PermissionRequest permission(@NonNull String... permissions) {
        //是否在`manifest.xml`中注册
        checkPermissions(permissions);
        return FACTORY.create(mSource).permission(permissions);
    }
复制代码

这里首先对传入的权限做了检查,是否在 manifest.xml 中注册,然后调用 FACTORY.create 创建了一个 PermissionRequest

static {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            FACTORY = new MRequestFactory();
        } else {
            FACTORY = new LRequestFactory();
        }
    }
    public interface PermissionRequestFactory {
        PermissionRequest create(Source source);
    }
复制代码
  • 3. rationale 相当于是个拦截器,当没有权限时会执行。

这个有什么用呢?比如说,App需要申请全局悬浮窗权限,相比直接跳到授权页,弹个提示框由用户选择是否去授权就显得友好的多。 当 showRationale() 被回调后说明没有权限,此时开发者必须回调 RequestExecutor#execute() 来启动设置或者 RequestExecutor#cancel() 来取消启动设置,否则将不会回调 onGranted() 或者 onDenied() 中的任何一个,也就是说 AndPermission 将不会有任何响应。

  • 4. onGranted 同意授权时调用, onDenied 拒绝授权时调用
  • 5. start 开始授权

MRequest 相关代码如下

@Override
    public void start() {
        List<String> deniedList = getDeniedPermissions(STANDARD_CHECKER, mSource, mPermissions);
        mDeniedPermissions = deniedList.toArray(new String[deniedList.size()]);
        if (mDeniedPermissions.length > 0) {
            List<String> rationaleList = getRationalePermissions(mSource, mDeniedPermissions);
            if (rationaleList.size() > 0) {
                mRationale.showRationale(mSource.getContext(), rationaleList, this);
            } else {
                execute();
            }
        } else {
            onCallback();
        }
    }
复制代码

首先,判断传递进来的权限有哪些是没有已授权,如都已授权,直接回调成功;如有未授权的,先判断是否有需要拦截的,如没有,则调用 execute 方法

public void execute() {
        BridgeRequest request = new BridgeRequest(mSource);
        request.setType(BridgeRequest.TYPE_PERMISSION);
        request.setPermissions(mDeniedPermissions);
        request.setCallback(this);
        RequestManager.get().add(request);
    }
复制代码

RequestManager 它的核心是个线程池

相关方法

private RequestManager() {
        this.mQueue = new LinkedBlockingQueue<>();

        new RequestExecutor(mQueue).start();
    }
    public void add(BridgeRequest request) {
        mQueue.add(request);
    }
复制代码

RequestExecutor 相关方法

public void run() {
        while (true) {
            synchronized (this) {
                try {
                    mRequest = mQueue.take();
                } catch (InterruptedException e) {
                    continue;
                }
                mMessenger = new Messenger(mRequest.getSource().getContext(), this);
                mMessenger.register();
                executeCurrent();
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    private void executeCurrent() {
            ...省略...
            case BridgeRequest.TYPE_PERMISSION: 
                BridgeActivity.requestPermission(mRequest.getSource(), mRequest.getPermissions());
                break;
            ...省略...
    }
复制代码

再来看看 BridgeActivity.requestPermission

static void requestPermission(Source source, String[] permissions) {
        Intent intent = new Intent(source.getContext(), BridgeActivity.class);
        intent.putExtra(KEY_TYPE, BridgeRequest.TYPE_PERMISSION);
        intent.putExtra(KEY_PERMISSIONS, permissions);
        source.startActivity(intent);
    }
复制代码

BridgeActivity 相关代码

@Override
    protected void onCreate(Bundle savedInstanceState) {
                 ...省略...
                 String[] permissions = intent.getStringArrayExtra(KEY_PERMISSIONS);
                requestPermissions(permissions, BridgeRequest.TYPE_PERMISSION);
                 ...省略...
     }
复制代码

看到这里大家就比较熟悉了,最后我们在看看授权的回调处理

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
        Messenger.send(this);
        finish();
    }
复制代码

Messenger 相关代码

public static void send(Context context) {
        Intent broadcast = new Intent(ACTION);
        context.sendBroadcast(broadcast);
    }
    @Override
    public void onReceive(Context context, Intent intent) {
        mCallback.onCallback();
    }

复制代码

这里回调到了 RequestExecutor#onCallback 方法,而其又回调到了 MRequest#onCallback 方法

MRequest 相关代码

@Override
    public void onCallback() {
        new AsyncTask<Void, Void, List<String>>() {
            @Override
            protected List<String> doInBackground(Void... voids) {
                return getDeniedPermissions(DOUBLE_CHECKER, mSource, mPermissions);
            }
            @Override
            protected void onPostExecute(List<String> deniedList) {
                if (deniedList.isEmpty()) {
                    callbackSucceed();
                } else {
                    callbackFailed(deniedList);
                }
            }
        }.execute();
    }
复制代码

这里再次对传入的权限做检查,如果没有未授权,则回调成功,否则回调失败。

  • 6.用户拒绝授权时提示
if (AndPermission.hasAlwaysDeniedPermission(MainActivity.this, permissions)) {
                        showSettingDialog(MainActivity.this, permissions);
                    }
复制代码

最终调用的逻辑是在 SettingPage#start 方法,这里对不同的机型做了适配

public void start(int requestCode) {
        Intent intent;
        if (MARK.contains("huawei")) {
            intent = huaweiApi(mSource.getContext());
        } else if (MARK.contains("xiaomi")) {
            intent = xiaomiApi(mSource.getContext());
        } else if (MARK.contains("oppo")) {
            intent = oppoApi(mSource.getContext());
        } else if (MARK.contains("vivo")) {
            intent = vivoApi(mSource.getContext());
        } else if (MARK.contains("meizu")) {
            intent = meizuApi(mSource.getContext());
        } else {
            intent = defaultApi(mSource.getContext());
        }
        try {
            mSource.startActivityForResult(intent, requestCode);
        } catch (Exception e) {
            intent = defaultApi(mSource.getContext());
            mSource.startActivityForResult(intent, requestCode);
        }
    }
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

解放战争(上)(1945年8月—1948年9月)

解放战争(上)(1945年8月—1948年9月)

王树增 / 人民文学出版社 / 2009-8 / 60.00

《解放战争》为王树增非虚构文学著述中规模最大的作品。武器简陋、兵力不足的军队对抗拥有现代武器装备的兵力庞大的军队,数量不多、面积有限的解放区最终扩展成为九百六十万平方公里的共和国,解放战争在短短四年时间里演绎的是人类历史上的战争传奇。国际风云,政治智慧,时事洞察,军事谋略,军队意志,作战才能,作品具有宏阔的视角和入微的体察,包含着惊心动魄的人生沉浮和变幻莫测的战场胜负,尽展中国历史上规模最大的一场......一起来看看 《解放战争(上)(1945年8月—1948年9月)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具