危险权限列表(Dangerous Permissions)
在Android Marshmallow 或以上,以下权限需要动态申请:
https://developer.android.com/reference/android/Manifest.permission_group.html#CAMERA
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS
group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR
group:android.permission-group.CAMERA
permission:android.permission.CAMERA
group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS
group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION
group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE
group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO
group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS
调用方式
简单示例代码
1.定义需要申请的权限
public static final int REQUEST_CODE = 1001;
// 需要申请的运行时权限
private String[] permissions = new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};
// 被用户拒绝的权限列表
private List<String> mPermissionList = new ArrayList<>();
2.调用函数申请
private void checkPermissions() {
// Marshmallow开始才用申请运行时权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (int i = 0; i < permissions.length; i++) {
if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permissions[i]);
}
}
if (!mPermissionList.isEmpty()){
String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);
ActivityCompat.requestPermissions(this, permissions,REQUEST_CODE);
}
}
}
3.获得回调结果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE){
for (int i = 0; i <grantResults.length; i++) {
if (grantResults[i] != PackageManager.PERMISSION_GRANTED){
Log.i(TAG, permissions[i] + "权限被禁止");
}
}
}
}
封装辅助类
PermissionUtil工具类:
public class PermissionUtil {
// 判断是否有某个权限
public static boolean hasPermission(Context context, String permission) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
// 弹出对话框请求权限
public static void requestPermissions(Activity activity, String[] permissions, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.requestPermissions(permissions, requestCode);
}
}
// 返回缺失的权限
public static String[] getDeniedPermissions(Context context, String[] permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> deniedPermissionList = new ArrayList<>();
for (String permission : permissions) {
if (context.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
deniedPermissionList.add(permission);
}
}
if (!deniedPermissionList.isEmpty()) {
return deniedPermissionList.toArray(new String[deniedPermissionList.size()]);
}
}
return null;
}
}
PermissionHelper动态权限帮助类
public class PermissionHelper {
// 权限回调接口
public interface PermissionInterface {
// 设置需要请求的权限
String[] getPermissions();
// 请求权限回调
void requestPermissionsResult(boolean isSuccess);
}
private Activity mActivity;
private PermissionInterface mPermissionInterface;
private int mPermissionRequestCode;
public PermissionHelper(Activity activity, PermissionInterface permissionInterface, int permissionRequestCode) {
mActivity = activity;
mPermissionInterface = permissionInterface;
mPermissionRequestCode = permissionRequestCode;
}
/**
* 开始请求权限。
*/
public void requestPermissions() {
String[] deniedPermissions = PermissionUtil.getDeniedPermissions(mActivity, mPermissionInterface.getPermissions());
if (deniedPermissions != null && deniedPermissions.length > 0) {
PermissionUtil.requestPermissions(mActivity, deniedPermissions, mPermissionRequestCode);
} else {//如果设备还不是M或以上版本,默认是成功的
mPermissionInterface.requestPermissionsResult(true);
}
}
/**
* 在Activity中的onRequestPermissionsResult中调用,true表示已处理,false 对该requestCode不感兴趣,不处理
*/
public boolean requestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == mPermissionRequestCode) {
boolean isAllGranted = true;//是否全部权限已授权
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_DENIED) {
isAllGranted = false;
break;
}
}
if (isAllGranted) {
//已全部授权
mPermissionInterface.requestPermissionsResult(true);
} else {
//权限有缺失
mPermissionInterface.requestPermissionsResult(false);
}
return true;
}
return false;
}
}
调用方式:
1.导入接口
implements PermissionHelper.PermissionInterface
实现接口类方法
@Override
public String[] getPermissions() {
// 申请需要的权限
return new String[]{
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};
}
@Override
public void requestPermissionsResult(boolean isSuccess) {
// 做想做的事情
}
2.初始化
mPermissionHelper = new PermissionHelper(this, this, REQUEST_CODE);
mPermissionHelper.requestPermissions();
3.回调中处理:
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (mPermissionHelper.requestPermissionsResult(requestCode, permissions, grantResults)) {
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
其他库
EasyPermission
调用方式也是非常简单,可以直接参看其demo:
1.定义权限列表以及requestcode.
private static final int REQUESTCODE_FROM_ACTIVITY = 1001;
private static final String[] mPression = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
2.storageTask
中先调用EasyPermissions.hasPermissions
检测是否有权限,没有则调用EasyPermissions.requestPermissions
请求权限。
private void storageTask() {
if (false == EasyPermissions.hasPermissions(this, mPression)){
// Ask for both permissions
EasyPermissions.requestPermissions(
this,
"这个app需要读写你的SD卡权限",
PRESSION_REQUEST_CODE,
mPression
);
}
}
3.onRequestPermissionsResult
调用 EasyPermissions.onRequestPermissionsResult
做结果处理。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// EasyPermissions handles the request result.
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
4.EasyPermissions.PermissionCallbacks
的两个接口回调onPermissionsGranted
+onPermissionsDenied
,成功+失败。
@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
Log.d(TAG, "onPermissionsGranted:" + requestCode + ":" + perms.size());
Toast.makeText(this, "权限被允许", Toast.LENGTH_LONG).show();
}
@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size());
Toast.makeText(this, "权限被拒绝", Toast.LENGTH_LONG).show();
国产小米等手机
小米这一类手机,用上面两种方式都无效,无论你怎么申请,小米就是不弹出权限申请对话框,与此同时小米默认授权失败。
可使用Permissions4M开源库
使用方式也很简单:
private static final String[] mPressions = {Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
private static final int REQUEST_CODE = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkPermissions();
}
//----------------------------------------------------------------------------------------------
// 权限申请
private void checkPermissions() {
Permissions4M.get(MainActivity.this)
.requestPermissions(mPressions)
.requestCodes(REQUEST_CODE)
.requestPageType(Permissions4M.PageType.MANAGER_PAGE)
.request();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions4M.onRequestPermissionsResult(MainActivity.this, requestCode, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@PermissionsGranted(REQUEST_CODE)
public void storageAndCallGranted() {
Toast.makeText(MainActivity.this,"读写SD卡权限授权成功 in activity with annotation", Toast.LENGTH_SHORT).show();
}
@PermissionsDenied(REQUEST_CODE)
public void storageAndCallDenied() {
Toast.makeText(MainActivity.this,"读写SD卡权限授权失败 in activity with annotation", Toast.LENGTH_SHORT).show();
}
@PermissionsRationale(REQUEST_CODE)
public void storageAndCallNonRationale() {
Toast.makeText(MainActivity.this,"请开启读写SD卡授权 in activity with annotation", Toast.LENGTH_SHORT).show();
}
@PermissionsNonRationale({REQUEST_CODE})
public void storageAndCallRationale(int code, final Intent intent) {
switch (code) {
case REQUEST_CODE:
new AlertDialog.Builder(MainActivity.this)
.setMessage("用户您好,我们需要您开启读写SD卡\n请点击前往设置页面\n(in activity with listener)")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
startActivity(intent);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.show();
break;
}
}