内容简介:权限是绝大多数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);
}
}
复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。