Android 6.0之后,加入了运行时权限功能,参考郭神这里是一个运行时权限的封装。在这之前需要了解到如下相关信息:
- 运行时权限也必须在AndroidManifest.xml中申明,否则申请时不提示用户,直接回调开发者权限被拒绝。
- 同一个权限组的任何一个权限被授权了,这个权限组的其他权限也自动被授权。例如一旦WRITE_CONTACTS被授权了,App也有READ_CONTACTS和GET_ACCOUNTS了。
- 申请某一个权限的时候系统弹出的Dialog是对整个权限组的说明,而不是单个权限。例如我申请
READ_EXTERNAL_STORAGE
,系统会提示"允许xxx访问设备上的照片、媒体内容和文件吗?"
- 权限一旦允许,之后运行程序就是默认允许,不会再提示权限申请对话框,不过可在系统提供的程序权限管理中更改。
需要用到运行时权限的危险权限包括如下,当要使用一个权限时,查看属于这张表中的权限时,就需要进行运行时权限处理:
CALENDAR(日历)
READ_CALENDAR
WRITE_CALENDAR
CAMERA(相机)
CAMERA
CONTACTS(联系人)
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION(位置)
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE(麦克风)
RECORD_AUDIO
PHONE(手机)
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS(传感器)
BODY_SENSORS
SMS(短信)
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE(存储卡)
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
OK,接下来开始运行时权限的代码处理。这里为了能够在非Activity中使用,使用Activity管理器提供栈顶Activity,将运行时权限检测写入到BaseActivity中:
public class BaseActivity extends AppCompatActivity {
private static PermissionListener mListener;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
/**
* 请求运行时权限
*
* @param permissions
* @param listener
*/
public static void requestRuntimePermission(String[] permissions, PermissionListener listener) {
try {
Activity topActivity = ActivityCollector.getTopActivity();
if (topActivity == null) {
return;
}
mListener = listener;
List<String> permissionList = new ArrayList<>();
for (String permission : permissions) {
if (ContextCompat.checkSelfPermission(topActivity, permission) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(permission);
}
}
if (!permissionList.isEmpty()) {
ActivityCompat.requestPermissions(topActivity, permissionList.toArray(new String[permissionList.size()]), 1);
} else {
//授权成功
mListener.onGranted();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1:
//有权限被拒绝
if (grantResults.length > 0) {
List<String> deniedPermissions = new ArrayList<>();
for (int i = 0; i < grantResults.length; i++) {
int grantResult = grantResults[i];
String permission = permissions[i];
if (grantResult != PackageManager.PERMISSION_GRANTED) {
deniedPermissions.add(permission);
}
}
//全部授权成功
if (deniedPermissions.isEmpty()) {
mListener.onGranted();
} else {
mListener.onDenied(deniedPermissions);
}
}
break;
default:
break;
}
}
}
授权回调接口及使用:
//申明
public interface PermissionListener {
//授权,同意
void onGranted();
//拒绝
void onDenied(List<String> deniedPermission);
}
//具体调用示例,未继承自BaseActivity的类调用前需要添加BaseActivity.,否则不加。另外,下面的Manifest类是安卓SDK的类,打包时会自动进行引用编译,试着查看该类定义便可知道
BaseActivity.requestRuntimePermission(new String[]{Manifest.permission.CALL_PHONE, Manifest.permission.WRITE_EXTERNAL_STORAGE},new PermissionListener(){
@Override
public void onGranted() {
//真正想要执行的代码逻辑
}
@Override
public void onDenied(List<String> deniedPermission) {
//此处可进行提示信息
}
});
常用的ActivityCollector控制器:
public class ActivityCollector {
private static List<Activity> activityList = new ArrayList<>();
public static void addActivity(Activity activity){
activityList.add(activity);
}
public static void removeActivity(Activity activity){
activityList.remove(activity);
}
//获取当前栈顶activity
public static Activity getTopActivity(){
if (activityList.isEmpty()){
return null;
}else {
return activityList.get(activityList.size()-1);
}
}
public static void finishAll(){
for (Activity activity : activityList) {
if (!activity.isFinishing()){
activity.finish();
}
}
}
}