Android常用框架----权限管理系列框架

时间:2024-10-08 07:44:55

并非所有的权限都需要动态申请,Android6.0将权限分为两种,普通权限跟敏感(危险)权限,普通权限是不需要动态申请的,但是敏感权限需要动态申请。


3、怎样动态适配权限

对于敏感权限的适配有一个原则,那就是实时检查,因为权限随时可能被回收,比如用户可以在设置里面把权限给取消,但是APP并不一定知道,因此每次都需要检查,一旦没有,就需要请求,之后,根据返回结果处理后续逻辑。


三、简单使用


以打电话为例

     
     
package ;
 
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import .;
import ;
import ;
import ;
 
import ;
 
/**
* Created by huangy on 2017/7/13.
*/
public class CallPermission extends AppCompatActivity implements View.OnClickListener {
private String phoneNumber = "10086";
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(.activity_main);
 
Button button = (Button) findViewById();
("打电话");
(this);
 
}
 
@Override
public void onClick(View view) {
//判断系统是否高于或等于6.0
if (.SDK_INT >= Build.VERSION_CODES.M) {
//第一步:检测权限
if((this, .CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
 
if((this, .CALL_PHONE)){
//判断是否需要先弹出自定义的解释说明,需要注意的是这个方法在首次请求的时候是返回false的,
//只有当用户拒绝过一次授权后才会返回true,毕竟多一步交互会造成体验下降,只有在用户对权限产生困扰的时候才需要向用户进行解释说明。
}else {
//第二步:不具备打电话的权限,请求权限
(this, new String[]{ .CALL_PHONE }, 1);
}
 
}else {
//具有打电话的权限,直接调用拨号功能
callPhone(phoneNumber);
}
}else {
//当前系统小于6.0,直接调用拨号功能
}
 
}
 
private void callPhone(String phoneNumber) {
try {
Intent intent = new Intent(Intent.ACTION_CALL);
(("tel:" + phoneNumber));
startActivity(intent);
}catch (SecurityException e){
();
}
 
}
 
//第三步:处理权限请求结果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode){
case 1:
if( > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){//打电话权限
callPhone(phoneNumber);
}else {
//不具有相关权限,给予用户提醒,比如Toast或者对话框,让用户去系统设置-应用管理里把相关权限开启
(this,"You denied the permission",Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
}

对于 shouldShowRequestPermissionRationale()方法官网文档的解释


记得在清单文件中配置权限
      
      
<uses-permission android:name=".CALL_PHONE"/>

运行效果如下(华为p8 max):
点击打电话按钮后会弹出权限申请提示框
 
点击始终允许后,再次点击打电话按钮就进入拨号界面了


四、按照开源的PermissionGen思路对权限申请进行了封装后的使用

1、权限工具类
      
      
package ;
 
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import .;
 
import ;
 
/**
* 权限工具类
*
*/
public class PermissionUtil {
 
public static void needPermission(Fragment context, int reqCode, String... permissions) {
needPermission((), reqCode, permissions);
}
 
public static void needPermission(Activity context, int reqCode, String... permissions) {
if (.SDK_INT < Build.VERSION_CODES.M) {
//6.0以下版本不需要代码申请权限
executeSuccessResult(context, reqCode);
}
 
boolean granted = hasPermission(context, permissions);//检查权限
if (granted) {
//已获得权限
executeSuccessResult(context, reqCode);
} else {
//申请权限
(context, permissions, reqCode);
}
}
 
private static void executeSuccessResult(Object context, int reqCode) {
Method successMethod = getTargetMethod(context, reqCode,);
try {
(context);
} catch (Exception e) {
();
}
}
 
private static void executeFailResult(Object context, int reqCode) {
Method successMethod = getTargetMethod(context, reqCode,);
try {
(context);
} catch (Exception e) {
();
}
}
 
private static Method getTargetMethod(Object context, int reqCode,Class annotation) {
Method[] declaredMethods = ().getDeclaredMethods();
for (Method method : declaredMethods) {
if (!()) {
(true); //私有的方法必须强制
}
//判断方法上是否使用了目标注解
boolean annotationPresent = (annotation);
if (annotationPresent) {
if (isTargetMethod(method,reqCode,annotation)) { //比较requestCode是否相等
return method;
}
}
}
return null;
}
private static boolean isTargetMethod(Method method, int reqCode, Class cls){
if(()){
return reqCode == ().requestCode();
}else if(()){
return reqCode == ().requestCode();
}
return false;
}
private static boolean hasPermission ( Context context , String ... permissions ) {
for (String permission : permissions) {
int granted = (context, permission);
if (granted == PackageManager.PERMISSION_DENIED) {
return false;
}
}
return true;
}
public static void onRequestPermissionsResult ( Fragment context , int requestCode , @NonNull String [] permissions , @NonNull int [] grantResults ) {
onRequestPermissionsResult(context, requestCode, permissions, grantResults);
}
 
public static void onRequestPermissionsResult(Activity context, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean permissionGranted = true;
for (int grant : grantResults) {
if (grant == PackageManager.PERMISSION_DENIED) {
permissionGranted = false;
break;
}
}
if (permissionGranted) {
//获得权限
executeSuccessResult(context, requestCode);
} else {
//权限被用户拒绝
executeFailResult(context, requestCode);
}
}
}

2、权限获取成功接口
       
       
package ;
 
import ;
import ;
import ;
import ;
 
/**
* 标识权限获取成功
*/
@Retention()
@Target()
public @interface PermissionSuccess {
int requestCode();
}

3、权限获取失败接口
        
        
package ;
 
import ;
import ;
import ;
import ;
 
/**
* 标识权限获取失败
*/
@Target()
@Retention()
public @interface PermissionFail {
int requestCode();
}

4、相机主类
        
        
package ;
 
import ;
import ;
import ;
import .;
import ;
import ;
 
import ;
 
/**
* Created by huangy on 2017/7/13.
*/
 
public class PhotoPermission extends AppCompatActivity implements View.OnClickListener {
private final int PER_CAMERA = 3;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(.activity_photo);
findViewById().setOnClickListener(this);
}
 
@Override
public void onClick(View v) {
switch (()) {
case :
(this,PER_CAMERA, );
break;
}
}
 
@PermissionSuccess(requestCode = PER_CAMERA)
private void grantPermissionSuccess(){
(this,"已获照相机得权限",Toast.LENGTH_SHORT).show();
}
 
@PermissionFail(requestCode = PER_CAMERA)
private void grantPersmissionFail(){
(this,"照相机权限被拒绝",Toast.LENGTH_SHORT).show();
}
 
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
(this,requestCode,permissions,grantResults);
}
 
}

五、其他封装后的使用(参考文档   /u014099894/article/details/51896832  )

GitHub上有几个很出名,融合了EasyPermission和PermissionGen,删去了注解,使用PermissionGen的请求方式,并利用回调来处理权限申请后的逻辑。

修改后的EasyPermission的特点: 
1. 使用PermissionGen的方式申请权限 
2. 去掉了注解,只使用回调,代码更清晰,更专注于业务逻辑 
3. 必须让权限申请类实现接口,否则抛出异常

        
        
public class MainFragment extends Fragment implements EasyPermission.PermissionCallback {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
 
/*
像PermissionGen那样申请权限,清晰明了
*/
(this)//Activity或Fragment
.addRequestCode(RC_SMS_PERM)//RequestCode
.permissions(.READ_SMS)//请求的权限
//showRequestPermissionRationale时的对话框的提示信息
.rationale(getString(.rationale_sms))
.request();
}
 
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
/*
系统回调方法,传递给EasyPermission
*/
(this, requestCode, permissions, grantResults);
}
 
@Override
public void onPermissionGranted(int requestCode, List<String> perms) {
/*
用户授予权限,做业务逻辑
*/
(getActivity(), "TODO: SMS Granted", Toast.LENGTH_SHORT).show();
}
 
@Override
public void onPermissionDenied(int requestCode, List<String> perms) {
/*
用于拒绝授予权限,提示信息
*/
(getActivity(), "TODO: SMS Denied", Toast.LENGTH_SHORT).show();
 
//用户点击了不再询问,弹出对话框去Settings界面开启,这段代码根据业务需求可以添加,也可删去
(this, "授权啊,不授权没法用啊," + "去设置里授权大哥", perms);
}
 
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
/*
从Settings界面跳转回来,标准代码,就这么写
*/
if (requestCode == EasyPermission.SETTINGS_REQ_CODE) {
if((getContext(), .READ_SMS)){
//已授权,处理业务逻辑
//...
}else{
(getContext(),"没有权限,无法工作",Toast.LENGTH_SHORT).show();
}
}
}
}