一、6.0动态授权(注意拒绝权限后的处理)
在6.0下新的权限机制分为两类,Normal Permissions,这类权限是不需要用户授权。一类是Dangerous Permissions,这类权限需要动态的去申请。
常见的危险权限有:
permission:android.permission.CAMERA
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.CALL_PHONE
等等。
我们常见的第三方库EasyPermission,其使用方法如下:
1.添加依赖
compile 'pub.devrel:easypermissions:0.3.0'
2.定义变量,为要申请的权限
private String[] perms = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO};
3.在需要权限的地方,如下代码
try {
if (EasyPermissions.hasPermissions(CameraActivity.this, perms)) {//检查是否获取该权限
method();
//code.....获得权限后要做的事
} else {
//第二个参数是被拒绝后再次申请该权限的解释
//第三个参数是请求码
//第四个参数是要申请的权限
EasyPermissions.requestPermissions(CameraActivity.this,
getString(R.string.necessary_pemmision), 0, perms);
}
}
4.添加回调
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//把申请权限的回调交由EasyPermissions处理
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
5.实现EasyPermissions.PermissionCallbacks接口并添加EasyPermissions的回调
回调中处理成功和失败的逻辑。
//下面两个方法是实现EasyPermissions的EasyPermissions.PermissionCallbacks接口
//分别返回授权成功和失败的权限
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Log.i(TAG, "获取成功的权限" + perms);
method(); //code.....获得权限后要做的事
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
Log.i(TAG, "获取失败的权限" + perms);
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this).setTitle(R.string.permmision_apply).setRationale(
R.string.camera_voice_denied_dsc).setRequestCode(
IConstants.REQ_CODE.PERMISSION).setNegativeButton(getString(R.string.cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showShort(getString(R.string.camera_permmision_dsc));
finish();
}
}).build().show();
}
}
二、7.0 FileProvider的使用
为什么要用FileProvider,简单点说,避免FileUriExposedException异常。
如何使用?
1.manifest定义provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
2.指定路径,比如如下路径D:\Project\projectname\app\src\main\res\xml\file_paths.xml
这个xml里放的什么呢?
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="files_root"
path="Android/data/包名/" />
<external-path
name="external_storage_root"
path="." />
<root-path
name="camera_photos"
path="" />
</paths>
root-path是后来补充上去的,因为部分手机可以外置SD卡设置为根目录。
paths>元素必须包含以下一个或多个子元素:
表示应用程序内部存储区域的file/子目录中的文件.这个子文件与Context.getFilesDir()返回的结果相同
表示应用程序内部存储区域的缓存子目录中的文件。该子目录的根路径与getCacheDir()返回值相同
表示外部存储区域根目录中的文件。该子目录的根路径与Environment.getExternalStorageDirectory()返回的值相同
表示应用程序外部存储区域根目录中的文件。该子目录的根路径与Context#getExternalFilesDir(String) 和Context.getExternalFilesDir(null)返回的值相同
表示应用程序外部缓存区域根目录中的文件。该子目录的根路径与Context.getExternalCacheDir()返回的值相同
3.我写的一个获取Uri的工具类,就这么几行
/**
* FileProvider工具类
*/
public static Uri getFileUri(Context context, File dir) {
Uri uri;
if (Build.VERSION.SDK_INT >= 24) {
uri = FileProvider.getUriForFile(context, "包名.fileprovider", dir);
} else {
uri = Uri.fromFile(dir);
}
return uri;
}
4.实际使用,直接贴一个照相部分的代码了
/**
* 拍照后做裁剪处理,矩形
*/
public void cameraSelectResult(int width, int height) {
//先更新系统文件(让拍照的图片显示在相册中)
File file = new File(path_camera);
if (file.exists()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = CommonUtils.getFileUri(getContext(), file);
// Uri contentUri = Uri.fromFile(file);
mediaScanIntent.setData(contentUri);
if (mContext != null) {
mContext.sendBroadcast(mediaScanIntent);
} else if (mFragment != null) {
mFragment.getContext().sendBroadcast(mediaScanIntent);
}
} else {
if (mContext != null) {
mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory() + path_camera)));
} else if (mFragment != null) {
mFragment.getContext().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory() + path_camera)));
}
}
}
doTailor(path_camera, width, height, false);
}
三、接下来开始填坑了
1.部分手机比如魅族在android 5.0对语音权限有类似动态授权的东西。既然是5.0,肯定不会走动态授权的,那就是永远有权限。厂家做的类似授权的东西你如果拒绝了,就会崩。
网上找了一个工具类,借鉴了。如果作者不允许,请告知我删掉。
public class CheckAudioPermission {
public static final int STATE_RECORDING = -1;
public static final int STATE_NO_PERMISSION = -2;
public static final int STATE_SUCCESS = 1;
/**
* 用于检测是否具有录音权限
*/
public static int getRecordState() {
int minBuffer = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 44100, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, (minBuffer * 100));
short[] point = new short[minBuffer];
int readSize = 0;
try {
audioRecord.startRecording();//检测是否可以进入初始化状态
} catch (Exception e) {
if (audioRecord != null) {
audioRecord.release();
audioRecord = null;
Log.e("CheckAudioPermission", "无法进入录音初始状态");
}
return STATE_NO_PERMISSION;
}
if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
//6.0以下机型都会返回此状态,故使用时需要判断bulid版本
//检测是否在录音中
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
Log.e("CheckAudioPermission", "录音机被占用");
}
return STATE_RECORDING;
} else {
//检测是否可以获取录音结果
readSize = audioRecord.read(point, 0, point.length);
if (readSize <= 0) {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
Log.e("CheckAudioPermission", "录音的结果为空");
return STATE_NO_PERMISSION;
} else {
if (audioRecord != null) {
audioRecord.stop();
audioRecord.release();
audioRecord = null;
}
return STATE_SUCCESS;
}
}
}
}
这个的使用稍微看一下
@Override
public void onVoiceBtnClicked() {
boolean hasPermissions = EasyPermissions.hasPermissions(getContext(), permissions);
if (hasPermissions) {
if (CheckAudioPermission.getRecordState() == CheckAudioPermission.STATE_SUCCESS) {
inputMenu.toggleVoice(1);
listView.setSelection(conversation.getAllMessages().size() - 1);
} else {
inputMenu.toggleVoice(2);
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) {
ToastUtil.showLong(getString(R.string.not_camera_denied1));
}
EasyPermissions.requestPermissions(CommonEaseChatFragment.this, getString(R.string.not_camera_denied), PERMI_MIC, permissions);
}
} else {
inputMenu.toggleVoice(2);
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) {
ToastUtil.showLong(getString(R.string.not_camera_denied1));
}
EasyPermissions.requestPermissions(CommonEaseChatFragment.this, getString(R.string.not_camera_denied), PERMI_MIC, permissions);
}
}