【笔记】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);    }}


原创粉丝点击