Android 5.0+ 屏幕录制实现的示例代码

作者:OhHoo 时间:2023-11-19 13:02:30 

前言

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

实现步骤

1、在清单文件中声明需要的权限

因为录制用到麦克风,所以需要加上 AUDIO 权限,


<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 以上时,还需要动态获取权限。


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;
}

2、获取用户录制屏幕授权

这里先介绍 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();
     }
    }

3、在 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,"拒绝录屏");
 }
}

4、初始化 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 )里的注释

Android 5.0+ 屏幕录制实现的示例代码

所以为了反正奔溃,在 stop 的时候捕获异常,并且置空 MediaRecorder,下次录屏的时候再重新生成 MediaRecorder。

最后

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

来源:https://www.jianshu.com/p/7560ce9e4136

标签:Android5.0,屏幕录制
0
投稿

猜你喜欢

  • 分析ABA问题的本质及其解决办法

    2021-12-20 13:59:26
  • 玩转Android之Drawable的使用

    2023-07-01 22:42:46
  • Java nacos动态配置实现流程详解

    2021-06-04 19:18:30
  • 单点登录的三种方式和JWT的介绍与使用

    2023-05-19 22:10:59
  • SpringMVC使用hibernate-validator进行参数校验最佳实践记录

    2022-11-12 23:44:04
  • SpringBoot过滤器与拦截 器深入分析实现方法

    2023-11-28 23:04:15
  • WPF+DiffPlex实现文本比对工具

    2022-04-20 21:32:07
  • Java基于正则实现的日期校验功能示例

    2021-09-30 02:43:26
  • C++ 归并排序(merge sort)案例详解

    2022-03-23 00:00:00
  • springMvc请求的跳转和传值的方法

    2023-02-06 17:29:56
  • JAVA多线程并发下的单例模式应用

    2022-09-15 01:27:31
  • 设计模式系列之组合模式及其在JDK和MyBatis源码中的运用详解

    2022-12-27 12:56:57
  • Springboot启动执行特定代码的方式汇总

    2023-08-06 04:42:24
  • Java使用线程池实现socket编程的方法详解

    2022-12-17 22:05:12
  • Android通过自定义view实现刮刮乐效果详解

    2022-02-15 02:26:09
  • Java枚举详解及使用实例(涵盖了所有典型用法)

    2023-06-29 23:17:55
  • SpringBoot如何优雅的处理全局异常

    2021-06-09 21:28:13
  • Java日常练习题,每天进步一点点(42)

    2022-10-28 01:42:54
  • Spring JPA find单表查询方法示例详解

    2022-11-03 19:43:38
  • 详解在Spring中如何自动创建代理

    2023-11-15 15:28:52
  • asp之家 软件编程 m.aspxhome.com