内容简介:权限是绝大多数App必不可少的部分,不管你仍在用原生的方式,还是其他的开源库,AndPermission绝对是值得学习的一个开源库,今天,我们就来学习下它的设计思想。权限库的思路大体上都如下图所示,也玩不出太复杂的花样。
权限是绝大多数App必不可少的部分,不管你仍在用原生的方式,还是其他的开源库,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
方法可以传入 Context
、 Fragment
、 android.app.Fragment fragment
、 Activity
,返回的都是 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的亮点之一。
之前传入的 Context
、 Fragment
、 android.app.Fragment fragment
、 Activity
只影响的 startActivity
、 startActivityForResult
、 isShowRationalePermission
方法
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); } } 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
系统分析与设计方法
惠滕 / 孙慧、肖刚 / 机械工业出版社 / 2004-9 / 69.00元
本书是介绍信息系统分析和设计原理、方法、技术、工具和应用的力作,自问世以来,广受欢迎,以至于一版再版,延续至今。 本书采用一个完整的案例研究,以整个信息系统构件(基于Zachman框架)和信息系统开发生命周期(FAST方法学)为主线,详细探讨了系统开发生命周期的前期、中期和后期以及跨生命周期的活动。另外,书中第一章都提供了大量的练习题、讨论题、研究题和小型案例,以加深读者对书中所述理论的实际应用和......一起来看看 《系统分析与设计方法》 这本书的介绍吧!