Android 5.0+ 屏幕录制实现

前言

Android 从 4.0 开始就提供了手机录屏方法,可是须要 root 权限,比较麻烦不容易实现。可是从 5.0 开始,系统提供给了 app 录制屏幕的一系列方法,不须要 root 权限,只须要用户受权便可录屏,相对来讲较为简单。本文是在参考了网络上其余录屏资料后完成的,感谢。如下将介绍开发录屏功能的一系列步骤以及实现过程当中所遇到的一些须要注意的事项。android

实现步骤

  1. 在清单文件中声明须要的权限

由于录制用到麦克风,因此须要加上 AUDIO 权限,git

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
复制代码

若是开发的 app targetApi 在 6.0 以上时,还须要动态获取权限。github

public static void checkPermission(AppCompatActivity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            int checkPermission =
                    ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO)
                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE)
                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                            + ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE);
            if (checkPermission != PackageManager.PERMISSION_GRANTED) {
                //动态申请
                ActivityCompat.requestPermissions(activity, new String[]{
                        Manifest.permission.RECORD_AUDIO,
                        Manifest.permission.READ_PHONE_STATE,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
                return;
            } else {
                return;
            }
        }
        return;
    }
    
复制代码
  1. 获取用户录制屏幕受权

这里先介绍 MediaProjectionManager , MediaProjectionManager 是系统提供的一种服务,当咱们拿到这个服务对象,能够建立一个 Intent ,经过这个 Intent 能够启动一个弹框样式的 Activity,若是用户受权了,那咱们即可以继续下一步屏幕录制。须要说明的是,Intent 是去启动另外一个 Activity 的,有极少极少的机型是没有对应的受权Activity 的,因此这里须要多加判断,防止应用奔溃。网络

MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) activity.
                            getSystemService(Context.MEDIA_PROJECTION_SERVICE);
                    if (mediaProjectionManager != null){
                        Intent intent = mediaProjectionManager.createScreenCaptureIntent();
                        PackageManager packageManager = activity.getPackageManager();
                        if (packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null){
                            //存在录屏受权的Activity 
                            activity.startActivityForResult(intent,requestCode);
                        }else {
                            Toast.makeText(activity,R.string.can_not_record_tip,Toast.LENGTH_SHORT).show();
                        }
                    }

复制代码
  1. 在 onActivityResult 对用户的受权作处理

即便用户受权了,赞成录制操做,仍然须要捕获异常,由于有可能会出现这样一种状况,就是用户在赞成录屏的时候系统也正在录屏,录屏操做冲突了。app

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK){
            try {
                ScreenUtil.setUpData(resultCode,data);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            ToastUtil.show(this,"拒绝录屏");
        }
    }
复制代码
  1. 初始化 MediaRecorder、建立 VirtualDisplay
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void setUpMediaRecorder() {

        mRecordFilePath = getSaveDirectory()  + File.separator+  System.currentTimeMillis() + ".mp4";
        if (mMediaRecorder == null){
            mMediaRecorder = new MediaRecorder();
        }
        //设置音频来源
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //设置视频来源
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        //输出的录屏文件格式
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        //录屏文件路径
        mMediaRecorder.setOutputFile( mRecordFilePath );
        //视频尺寸
        mMediaRecorder.setVideoSize(mRecordWidth, mRecordHeight);
        //音视频编码器
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        //比特率
        mMediaRecorder.setVideoEncodingBitRate((int) (mRecordWidth * mRecordHeight * 3.6));
        //视频帧率
        mMediaRecorder.setVideoFrameRate(20);

        try {
            mMediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
复制代码

这一步是整个录屏操做最为关键的一步!咱们初始化了 MediaRecorder,设置了是否录上声音、录屏文件格式、录屏文件路径、音视频的编码器、比特率、视频帧率等 而后将在步骤 3 中的 resultCode 以及 data 做为必要的参数经过 MediaProjectionManager 建立 VirtualDisplay。VirtualDisplay 能够理解为虚拟的呈现器,它能够捕获屏幕上的内容,并将其捕获的内容渲染到 Surface 上(Surace 由 MediaRecorder 提供,经过 getSurface() 方法获得),MediaRecorder 再进一步将其封装处理为 Mp4 文件。ide

通过以上步骤 prepare 以后,当再次调用 MediaRecorder.start() 就能够开始录屏了,这里赞成也须要注意的时,调用 start() 方法开始录屏以后,不能当即调用 stop()方法中止录屏,不然会奔溃。测试在测试录屏功能时立马中止录屏,应用奔溃,一直找不到缘由。直到看到了源码( API 26 )里的注释测试

因此为了反正奔溃,在 stop 的时候捕获异常,而且置空 MediaRecorder,下次录屏的时候再从新生成 MediaRecorder。

最后

因为知识水平有限,不免有错误遗漏,欢迎指正!项目地址为 屏幕录制ui

相关文章
相关标签/搜索