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

前言

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 )里的注释

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

最后

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • android-获取网络时间、获取特定时区时间、时间同步的方法

    最近整理出android-获取网络时间.获取特定时区时间.时间同步的方法.具体如下: 方法一: SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); dff.setTimeZone(TimeZone.getTimeZone("GMT+08")); String ee = dff.format(new Date()); 这个方法获取的结果是24小时制的,月份也正确. 这个方法不随手机时间

  • Android实现歌曲播放时歌词同步显示具体思路

    我们需要读取以上歌词文件的每一行转换成成一个个歌词实体: 复制代码 代码如下: public class LyricObject { public int begintime; // 开始时间 public int endtime; // 结束时间 public int timeline; // 单句歌词用时 public String lrc; // 单句歌词 } 可根据当前播放器的播放进度与每句歌词的开始时间,得到当前屏幕中央高亮显示的那句歌词.在UI线程中另起线程,通过回调函数 onDra

  • Android多线程之同步锁的使用

    本文主要介绍了Android多线程之同步锁的使用,分享给大家,具体如下: 一.同步机制关键字synchronized 对于Java来说,最常用的同步机制就是synchronized关键字,他是一种基于语言的粗略锁,能够作用于对象.函数.class.每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限.当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象.而synchronized作用于class时则是锁的这个Class类,并非具体对象. public cl

  • Android获取点击屏幕的位置坐标

    在Android开发过程中,有时需要获取触摸位置的坐标,以便作进一步处理,比如做炫酷的动画效果,或者响应其他操作. 本文简单介绍Android中触屏操作时,触屏的开始位置.当前位置.结束位置. 布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:l

  • Android seekbar(自定义)控制音量同步更新

    Android seekbar控制音量同步更新 作为开发人员来讲,seekbar你一定会碰到,那么怎么自定义seekbar以及seekbar控制的音量怎么与系统的seekbar音量同步更新.今天就下拉菜单中添加SeekBar控制音量为例(Android 5.1系统)   一:自定义Seekbar 先来看一下所自定义的效果图: 首先来来看一下布局文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/androi

  • Android自适应不同屏幕大小的全部方法

    本文讲述了Android自适应不同屏幕大小的全部方法.分享给大家供大家参考,具体如下: 本文将告诉你如何让你的应用程序支持各种不同屏幕大小,主要通过以下几种办法: 让你的布局能充分的自适应屏幕: 根据屏幕的配置来加载合适的UI布局: 确保正确的布局应用在正确的设备屏幕上: 提供可以根据屏幕大小自动伸缩的图片: 使用 "wrap_content" 和 "match_parent". 为了确保你的布局能够自适应各种不同屏幕大小,你应该在布局的视图中使用"wra

  • Android6.0开发中屏幕旋转原理与流程分析

    本文实例讲述了Android6.0开发中屏幕旋转原理与流程.分享给大家供大家参考,具体如下: 从Android 系统开发开始,这里写下Android 6.0 屏幕旋转系统分析. 第一部分 Kenel Android 系统屏幕旋转得以实现,是靠从底层驱动gsensor 中获取数据,从而判断屏幕方向的.kernel sensor的驱动先就不在这里赘述,简单介绍下,gsensor 驱动注册input 事件 在/dev/input/下,可以通过adb getevent -p 可以查看系统所有的输入事件.

  • Android手机屏幕同步工具asm.jar

    有时候可能需要将手机上的一些操作投影出来,比如一些App Demo的展示等.其实,有专门的硬件设备能干这件事儿,但没必要专门为展示个Demo去花钱买硬件设备.正好,对于Android系统的手机,有一个开源的jar包能干这事儿:Android Screen Monitor(asm.jar) 步骤: 一 . 下载附件 asm.jar 官网 https://code.google.com/p/android-screen-monitor/ 二. 放到任意目录下, 这里放到D盘根目录; 将asm.jar

  • android中ListView数据刷新时的同步方法

    本文实例讲述了android中ListView数据刷新时的同步方法.分享给大家供大家参考.具体实现方法如下: public class Main extends BaseActivity { private static final String TAG = "tag"; private static final int STATUS_CHANGE = 0; ExpandableListView mElv; ArrayList<GroupInfo> mGroupArray;

  • Android异步方法以同步方式实现

    Android强制异步转同步方法,供大家参考,具体内容如下 Android系统中规定耗时任务需要在异步线程中进行,特别是网络请求必须在异步线程中进行否则会抛出NetworkOnMainThreadException,但是在一些特殊的情况我们需要保证在获得到网络请求结果之后在进行余下操作,这时候便需要在UiThread中进行相关操作. 这样就需要用到线程阻塞的原理,这里可以借助Callable或FutureTask来实现. public static String getSyncBusiness(

随机推荐