Android|Android 5.0+ 屏幕录制实现
前言
Android 从 4.0 开始就提供了手机录屏方法,但是需要 root 权限,比较麻烦不容易实现。但是从 5.0 开始,系统提供给了 app 录制屏幕的一系列方法,不需要 root 权限,只需要用户授权即可录屏,相对来说较为简单。本文是在参考了网络上其他录屏资料后完成的,感谢。以下将介绍开发录屏功能的一系列步骤以及实现过程中所遇到的一些需要注意的事项。
实现步骤
- 在清单文件中声明需要的权限
如果开发的 app targetApi 在 6.0 以上时,还需要动态获取权限。
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;
}
- 获取用户录制屏幕授权
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();
}
}
- 在 onActivityResult 对用户的授权做处理
@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,"拒绝录屏");
}
}
- 初始化 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 文件。
经过以上步骤 prepare 之后,当再次调用 MediaRecorder.start() 就可以开始录屏了,这里同意也需要注意的时,调用 start() 方法开始录屏之后,不能立即调用 stop()方法停止录屏,否则会奔溃。测试在测试录屏功能时立马停止录屏,应用奔溃,一直找不到原因。直到看到了源码( API 26 )里的注释
文章图片
image
所以为了反正奔溃,在 stop 的时候捕获异常,并且置空 MediaRecorder,下次录屏的时候再重新生成 MediaRecorder。
最后 【Android|Android 5.0+ 屏幕录制实现】由于知识水平有限,难免有错误遗漏,欢迎指正!项目地址为 屏幕录制
推荐阅读
- android第三方框架(五)ButterKnife
- Android中的AES加密-下
- 带有Hilt的Android上的依赖注入
- android|android studio中ndk的使用
- Android事件传递源码分析
- RxJava|RxJava 在Android项目中的使用(一)
- Android7.0|Android7.0 第三方应用无法访问私有库
- 深入理解|深入理解 Android 9.0 Crash 机制(二)
- 屏幕另一边的纠结
- android防止连续点击的简单实现(kotlin)