【笔记】android录音权限遇到的问题和兼容8.0权限请求的方案
来源:互联网 发布:ffmpeg java api 编辑:程序博客网 时间:2024/05/17 02:12
android6.0之后出现的运行时权限请求给开发者带来了很多的不便,但也出现了很多权限请求方面的工具类、框架,之前自己也实现过一个Android6.0之后权限请求工具类。
但随着8.0的出现,之前的工具类需要做下调整,而且在实际的使用中也出现了部分手机权限请求类无法解决的问题,这里记录下这些天在录音权限上遇到的坑。
部分6.0以下手机不兼容情况
部分6.0以下的手机在录音权限被禁止的情况下去检查ContextCompat#checkSelfPermission是否拥有权限时,获取到的结果是拥有该权限。这种情况下去开启录音一般会出现三种情况:
可能情况一:调用录音方法后AudioRecord#startRecording直接崩溃;
可能情况二:调用录音方法后不崩溃,但查看当前状态会发现不是处于录音状态;
可能情况三:调用方法后不崩溃并且处于录音状态,但如果调用AudioRecord#read方法是无法读取到录音数据的;
针对以上三种情况,查询资料并整理后实现一个检测录音权限是否开启的方法
private static boolean hasRecordPermission() { int minBufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); int bufferSizeInBytes = 640; byte[] audioData = new byte[bufferSizeInBytes]; int readSize = 0; AudioRecord audioRecord = null; try { audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize); // 开始录音 audioRecord.startRecording(); } catch (Exception e) { //可能情况一 if (audioRecord != null) { audioRecord.release(); audioRecord = null; } return false; } // 检测是否在录音中,6.0以下会返回此状态 if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { //可能情况二 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } return false; } else {// 正在录音 readSize = audioRecord.read(audioData, 0, bufferSizeInBytes); // 检测是否可以获取录音结果 if (readSize <= 0) { //可能情况三 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } LogUtil.e(TAG, "没有获取到录音数据,无录音权限"); return false; } else { //有权限,正常启动录音并有数据 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } return true; } } }
兼容8.0权限请求的常用工具类
在8.0的官网更新说明上可以看到对权限的请求做出了一些调整,6.0的权限请求里我们只需要请求一组权限中的其中一个权限,其他权限也将被允许,但在8.0中谷歌申明这是一个bug,并作出调整在需要使用某权限时,如果该权限没有被允许,即使同组权限中有其他权限被允许,该权限也还是要请求,所以对权限请求工具类做出一些调整。
/** * 权限请求工具类 * * @author SJL * @date 2017/3/22 */@TargetApi(Build.VERSION_CODES.M)public class PermisstionUtil { private static final String TAG = "PermisstionUtil"; //日历 public static String[] CALENDAR = {Manifest.permission.READ_CALENDAR, Manifest.permission.WRITE_CALENDAR}; //相机 public static String[] CAMERA = {Manifest.permission.CAMERA}; //联系人 public static String[] CONTACTS = {Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS, Manifest.permission.GET_ACCOUNTS}; //位置 public static String[] LOCATION = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; //麦克风 public static String[] MICROPHONE = {Manifest.permission.RECORD_AUDIO}; //手机 public static String[] PHONE = {Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.READ_CALL_LOG, Manifest.permission.WRITE_CALL_LOG, Manifest.permission.ADD_VOICEMAIL, Manifest.permission.USE_SIP, Manifest.permission.PROCESS_OUTGOING_CALLS}; //传感器 public static String[] SENSORS = {Manifest.permission.BODY_SENSORS}; //短信 public static String[] SMS = {Manifest.permission.SEND_SMS, Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_WAP_PUSH, Manifest.permission.RECEIVE_MMS}; //文件读写 public static String[] STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; private static HashMap<String, Object> map = new HashMap<String, Object>(); /** * 版本检测 * * @return */ private static boolean checkSDK() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } /** * 权限请求 * * @param context * @param permissions 需要请求的权限 * @param requestCode * @param explainMsg 权限解释 * @param onPermissionResult */ public static void requestPermissions(@NonNull Context context, @NonNull String[] permissions, int requestCode, String explainMsg, OnPermissionResult onPermissionResult) { onPermissionResult = initOnPermissionResult(onPermissionResult, permissions, requestCode, explainMsg); if (permissions.length == 0) { invokeOnRequestPermissionsResult(context, onPermissionResult); } else if (context instanceof Activity || (Object) context instanceof Fragment) { if (checkSDK()) { onPermissionResult.deniedPermissions = getDeniedPermissions(context, permissions); if (onPermissionResult.deniedPermissions.length > 0) {//存在被拒绝的权限 onPermissionResult.rationalePermissions = getRationalePermissions(context, onPermissionResult.deniedPermissions); if (onPermissionResult.rationalePermissions.length > 0) {//向用户解释请求权限的理由 shouldShowRequestPermissionRationale(context, onPermissionResult); } else { invokeRequestPermissions(context, onPermissionResult); } } else {//所有权限允许 onPermissionResult.grantResults = new int[permissions.length]; for (int i = 0; i < onPermissionResult.grantResults.length; i++) { onPermissionResult.grantResults[i] = PackageManager.PERMISSION_GRANTED; } invokeOnRequestPermissionsResult(context, onPermissionResult); } } else { onPermissionResult.grantResults = getPermissionsResults(context, permissions); invokeOnRequestPermissionsResult(context, onPermissionResult); } } } /** * 获取被拒绝的权限 * * @param context * @param permissions * @return */ private static String[] getDeniedPermissions(Context context, String[] permissions) { List<String> list = new ArrayList<String>(); for (String permission : permissions) { if (checkPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { list.add(permission); } } return list.toArray(new String[list.size()]); } /** * 获取权限请求结果 * * @param context * @param permissions * @return */ private static int[] getPermissionsResults(Context context, String[] permissions) { int[] results = new int[permissions.length]; for (int i = 0; i < results.length; i++) { results[i] = checkPermission(context, permissions[i]); } return results; } private static String[] getRationalePermissions(Context context, String[] deniedPermissions) { List<String> list = new ArrayList<String>(); for (String permission : deniedPermissions) { if (context instanceof Activity) { if (((Activity) context).shouldShowRequestPermissionRationale(permission)) { list.add(permission); } } else if ((Object) context instanceof Fragment) { if (((Fragment) (Object) context).shouldShowRequestPermissionRationale(permission)) { list.add(permission); } } else { throw new IllegalArgumentException("context 只能是Activity或Fragment"); } } return list.toArray(new String[list.size()]); } /** * 调用权限请求方法 * * @param context * @param onPermissionResult */ private static void invokeRequestPermissions(Context context, OnPermissionResult onPermissionResult) { if (context instanceof Activity) ((Activity) context).requestPermissions(onPermissionResult.deniedPermissions, onPermissionResult.requestCode); else if ((Object) context instanceof Fragment) ((Fragment) (Object) context).requestPermissions(onPermissionResult.deniedPermissions, onPermissionResult.requestCode); } /** * 调用权限请求结果回调 * * @param context * @param onPermissionResult */ private static void invokeOnRequestPermissionsResult(Context context, OnPermissionResult onPermissionResult) { if (context instanceof Activity) { if (checkSDK()) { ((Activity) context).onRequestPermissionsResult(onPermissionResult.requestCode, onPermissionResult.permissions, onPermissionResult.grantResults); } else if (context instanceof ActivityCompat.OnRequestPermissionsResultCallback) { ((ActivityCompat.OnRequestPermissionsResultCallback) context).onRequestPermissionsResult(onPermissionResult.requestCode, onPermissionResult.permissions, onPermissionResult.grantResults); } else { onRequestPermissionsResult(onPermissionResult.requestCode, onPermissionResult.permissions, onPermissionResult.grantResults); } } else if ((Object) context instanceof Fragment) { ((Fragment) (Object) context).onRequestPermissionsResult(onPermissionResult.requestCode, onPermissionResult.permissions, onPermissionResult.grantResults); } } /** * 显示权限解释 * * @param context * @param onPermissionResult */ private static void shouldShowRequestPermissionRationale(final Context context, final OnPermissionResult onPermissionResult) { new AlertDialog.Builder(context instanceof Activity ? context : ((Fragment) (Object) context).getActivity()) .setTitle("提示") .setMessage(onPermissionResult.explainMsg) .setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); invokeRequestPermissions(context, onPermissionResult); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); onPermissionResult.grantResults = getPermissionsResults(context, onPermissionResult.permissions); invokeOnRequestPermissionsResult(context, onPermissionResult); } }).show(); } /** * 检查权限 * * @param context * @param permission * @return */ private static int checkPermission(Context context, String permission) { int result = context.checkPermission(permission, Process.myPid(), Process.myUid()); if (Manifest.permission.RECORD_AUDIO.equalsIgnoreCase(permission) && result == PackageManager.PERMISSION_GRANTED) { //录音权限特殊处理 result = hasRecordPermission() ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED; } return result; } /** * 权限请求结果 * * @param requestCode * @param permissions * @param grantResults */ public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { synchronized (TAG) { OnPermissionResult onPermissionResult = (OnPermissionResult) map.get(String.valueOf(requestCode)); if (onPermissionResult != null) { List<String> deniedPermissions = new ArrayList<String>(); for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { deniedPermissions.add(permissions[i]); } } if (deniedPermissions.size() > 0) { onPermissionResult.denied(requestCode); } else { onPermissionResult.granted(requestCode); } map.remove(String.valueOf(requestCode)); } } } /** * 初始化权限请求回调 * * @param onPermissionResult * @param permissions * @param requestCode * @param explainMsg @return */ private static OnPermissionResult initOnPermissionResult(OnPermissionResult onPermissionResult, String[] permissions, int requestCode, String explainMsg) { synchronized (TAG) { if (onPermissionResult == null) { onPermissionResult = new OnPermissionResult() { @Override public void granted(int requestCode) { } @Override public void denied(int requestCode) { } }; } onPermissionResult.permissions = permissions; onPermissionResult.requestCode = requestCode; onPermissionResult.explainMsg = explainMsg; onPermissionResult.grantResults = new int[0]; map.put(String.valueOf(requestCode), onPermissionResult); return onPermissionResult; } } /** * 是否有录音权限 * 部分6.0之前的手机录音权限在被禁止的情况下可能返回有权限,使用中发现一般可以通过以下三种现象判断是否有权限 * 可能情况一:权限被禁止,启动录音直接崩溃 * 可能情况二:权限被禁止,启动录音后状态不是录音中 * //可能情况三:权限被禁止,正常启动录音,但没有数据 * * @return */ private static boolean hasRecordPermission() { int minBufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); int bufferSizeInBytes = 640; byte[] audioData = new byte[bufferSizeInBytes]; int readSize = 0; AudioRecord audioRecord = null; try { audioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize); // 开始录音 audioRecord.startRecording(); } catch (Exception e) { //可能情况一 if (audioRecord != null) { audioRecord.release(); audioRecord = null; } return false; } // 检测是否在录音中,6.0以下会返回此状态 if (audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) { //可能情况二 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } return false; } else {// 正在录音 readSize = audioRecord.read(audioData, 0, bufferSizeInBytes); // 检测是否可以获取录音结果 if (readSize <= 0) { //可能情况三 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } return false; } else { //有权限,正常启动录音并有数据 if (audioRecord != null) { audioRecord.stop(); audioRecord.release(); audioRecord = null; } return true; } } } /** * 多组权限合并 * * @param items * @return */ public static String[] getPermissions(String[]... items) { int length = 0; for (String[] item : items) { length += item.length; } String[] result = new String[length]; int i = 0; for (String[] item : items) { for (String itemIn : item) { result[i] = itemIn; i++; } } return result; } public abstract static class OnPermissionResult { int requestCode; String explainMsg; String[] permissions; String[] deniedPermissions; String[] rationalePermissions; int[] grantResults; //权限允许 public abstract void granted(int requestCode); //权限拒绝 public abstract void denied(int requestCode); }}
阅读全文
1 0
- 【笔记】android录音权限遇到的问题和兼容8.0权限请求的方案
- 【Android】5.0录音权限处理时遇到的问题
- 关于android录音权限被用户禁用的问题解决方案
- android 兼容6.0的权限问题
- android 不同机型因录音权限出现的不同问题
- Android 权限及7.0权限的兼容
- Android修改文件权限遇到的问题
- 项目中遇到的录音、6.0权限、隐式服务转显式的问题
- android 权限录音权限检测
- android 6.0 Permission权限兼容的封装
- Android权限处理,不同版本的兼容
- Android 录音和摄像头权限适配
- android apk的签名和权限问题
- Android 权限,权限分组的一些问题
- android手机 录音权限是否打开的检测
- Android开发录音和播放音频的步骤(动态获取权限)
- 权限的管理方案
- android 动态请求权限笔记
- MySQL 基础知识
- NOIP模拟(11.02)T2 最佳序列
- 【Leetcode】Valid Parentheses
- 接口
- centos tftp 服务端配置手册
- 【笔记】android录音权限遇到的问题和兼容8.0权限请求的方案
- git使用
- H5各种头部meta标签功能大全
- 从文件系统读取数组(Objective-C 开发范例)
- java作业
- Ubifs文件系统和mkfs.ubifs以及ubinize工具的用法
- 打造丝般顺滑的 H5 翻页库
- 【Ionic】常用小模块及经验总结
- Stream详解