权限的目的
权限设立的目的是保护安全
权限机制
系统权限分三种:
- Android所有者权限,即Android Rom开发权限;
- Android Root权限,Linux系统中的最高用户权限;
- Android 应用程序权限,应用开发者在项目的AndroidManifest中声明,然后由用户授权获取
(Android 应用程序权限分为两种,普通权限(不涉及用户隐私,系统自动授权)和敏感权限(涉及用户隐私,需要用户手动授权))
1. 原生运行时权限请求
工具类封装
/**
* @Author: LiuJinYang
* 运行时权限工具类
*/
public class LjyPermissionUtil {
private PermissionResultListener permissionResultListener;
private LjyPermissionUtil() {
}
public static LjyPermissionUtil getInstance() {
return PermissionUtilHolder.instancePermissionUtil;
}
private static class PermissionUtilHolder {
private static final LjyPermissionUtil instancePermissionUtil
= new LjyPermissionUtil();
}
/**
* 判断当前应用是否有指定权限,运行时权限的检测
*/
public boolean hasPermissions(Context context, String[] permissions) {
if (permissions == null || permissions.length == 0) {
return true;
}
boolean ifSdk = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
for (String permission : permissions) {
if (ifSdk && !hasPermission(context, permission)) {
return false;
}
}
return true;
}
private boolean hasPermission(Context context, String permission) {
return ActivityCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED;
}
/**
* 动态申请指定权限,配合hasPermission使用,
* 注意在使用的activity中调用onRequestPermissionsResult权限申请结果的回调
*
* @param activity
* @param permissions
* @param requestCode
*/
public void requestPermission(final Activity activity, final String[] permissions,
final int requestCode, final PermissionResultListener permissionResultListener) {
this.permissionResultListener = permissionResultListener;
ActivityCompat.requestPermissions(activity, permissions, requestCode);
}
/**
* 申请权限的结果回调,需要在Activity的onRequestPermissionsResult中调用
*
* @param grantResults
*/
public void onPermissionResult(Activity activity, final int requestCode,
String[] permissions, int[] grantResults) {
boolean hasPermission = true;
List<String> deniedList = new ArrayList<>();
List<String> cancelList = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
boolean isAllow = grantResults[i] == PackageManager.PERMISSION_GRANTED;
hasPermission &= isAllow;
if (!isAllow) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
|| !activity.shouldShowRequestPermissionRationale(permissions[i])) {
deniedList.add(permissions[i]);
} else {
cancelList.add(permissions[i]);
}
}
}
if (permissionResultListener != null) {
if (hasPermission) {
permissionResultListener.onSuccess(requestCode);
} else {
if (deniedList.size() > 0) {
permissionResultListener.onDenied(deniedList);
}
if (cancelList.size() > 0) {
permissionResultListener.onCancel(cancelList);
}
}
}
}
/**
* 权限申请结果的回调接口
*/
public interface PermissionResultListener {
/**
* 申请成功
*/
void onSuccess(final int requestCode);
/**
* 拒绝的权限集合(不在弹框提醒)
*/
void onDenied(@NonNull List<String> deniedList);
/**
* 取消的权限集合
*/
void onCancel(@NonNull List<String> cancelList);
}
}
工具类的使用
//baseActivity的onRequestPermissionsResult中
open class BaseActivity : AppCompatActivity() {
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>, grantResults: IntArray) {
if (grantResults.isNotEmpty()) {
LjyPermissionUtil.getInstance().onPermissionResult(this,
requestCode, permissions, grantResults)
}
}
}
class PermissionActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_permission)
}
fun onBtnClick(view: View) {
when (view.id) {
//原生获取运行时权限
R.id.button_perm_1 -> requestPermission()
}
}
private fun requestPermission() {
val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA)
if (LjyPermissionUtil.getInstance().hasPermissions(this@PermissionActivity, permissions)) {
printFileName()
} else {
val mRequestCode=1002
LjyPermissionUtil.getInstance().requestPermission(
this@PermissionActivity,
permissions,
mRequestCode,
object : LjyPermissionUtil.PermissionResultListener {
override fun onSuccess(requestCode: Int) {
if (requestCode == mRequestCode) {
printFileName()
}
}
override fun onDenied(deniedList: MutableList<String>) {
LjyToastUtil.toast(this@PermissionActivity,
"权限被拒绝,将导致APP无法正常使用,请前往设置中修改")
for (it in deniedList) {
LjyLogUtil.d("deniedList:$it")
}
}
override fun onCancel(cancelList: MutableList<String>) {
LjyToastUtil.toast(this@PermissionActivity, "取消了权限申请")
for (it in cancelList) {
LjyLogUtil.d("failList:$it")
}
}
}
)
}
}
private fun printFileName() {
LjyLogUtil.d("操作文件...")
}
}
2. RxPermission
还有一些比较常用的权限请求框架,如RxPermission
//rxPermissionss的使用
//1. build.gradle中添加依赖
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.12'
}
//注意:最新版rxpermission需要配合RxJava3使用
//rxjava3
implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
//2.调用
//所有权限统一结果
new RxPermissions(this)
.request(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA)
.subscribe(accept -> {
if (accept) {
LjyLogUtil.d("允许了权限申请");
} else {
LjyLogUtil.d("拒绝了权限申请");
}
});
//将权限申请结果逐一返回
new RxPermissions(this)
.requestEach(Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA)
.subscribe(permission -> {
// will emit 2 Permission objects
LjyLogUtil.d(permission.toString());
if (permission.granted) {
// `permission.name` is granted !
LjyLogUtil.d("允许了权限申请:" + permission.name);
} else if (permission.shouldShowRequestPermissionRationale) {
// Denied permission without ask never again
LjyLogUtil.d("取消了权限申请:" + permission.name);
} else {
// Denied permission with ask never again
// Need to go to the settings
LjyLogUtil.d("权限被拒绝,将导致APP无法正常使用,请前往设置中修改:" + permission.name);
}
});
3. RxPermissions原理
新建RxPermissions类的时候,框架会悄悄的新建一个RxPermissionsFragment类,
也就是说框架在内部封装了一个没有界面的fragment,
这样做的好处是请求权限的回调可以在Fragment中实现,不需要用户再去调用onRequestPermissionsResult
网友评论