目录

  • Android录屏功能实现—MediaProjection
    • 概述
      • 工具类
      • 作用
    • 过程
      • 权限申请
      • 连接服务
      • 开始录制
      • 停止录制
    • 总结

不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!

Android录屏功能实现—MediaProjection

参考博客:Android实现录屏MediaProjection以及相关异常解决

参考GitHub:github中最容易理解的Android录屏的版本

概述

Android录屏功能实现有很多种方式,这里记录最常见的一种,用Android自带的apk来实现,即使用MediaProjection来实现。

工具类

实现Android的录屏功能,需要用到一些工具类:MediaProjectionMediaProjectionManagerMediaRecoderVirtualDisplayDisplayMetrics等。

作用

  • MediaProjection

用于屏幕采集。

  • MediaProjectionManager

用于创建MediaProjection

  • MediaRecoder

用于屏幕录制。

  • VirtualDisplay

用于创建虚拟屏幕。

  • DisplayMetrics

用于获取屏幕参数。

过程

权限申请

需要使用录屏功能,必须请求读写和录像录音权限。

  • 静态权限申请——Manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.RECORD_AUDIO"/>
  • Android 6.0以上还需要动态申请权限
    //权限检查,连接录屏服务public void checkPermission() {//调用检查权限接口进行权限检查if ((ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) && (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)){//如果没有权限,获取权限//调用请求权限接口进行权限申请ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO},PERMISSION_REQUEST_CODE);}else{//有权限,连接录屏服务,进行录屏connectService();}}
  • 申请权限后,还需要判断用户是否同意
 //没有权限,去请求权限后,需要判断是否请求成功@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode == PERMISSION_REQUEST_CODE){//请求码相同if(grantResults.length != 0 &&((grantResults[0] != PackageManager.PERMISSION_GRANTED) ||(grantResults[1] != PackageManager.PERMISSION_GRANTED))){//如果结果都存在,但是至少一个没请求成功,弹出提示Toast.makeText(MainActivity.this,"请同意必须的应用权限,否则无法正常使用该功能!", Toast.LENGTH_SHORT).show();}else if(grantResults.length != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&grantResults[1] == PackageManager.PERMISSION_GRANTED){//如果结果都存在,两个权限都申请成功,连接服务,启动录屏connectService();}}}

连接服务

注意点:记住一定要在Manifest中声明自定义的Service,不然后面得到的Service对象都是NULL

  • Manifest.xml
<service android:name=".ScreenRecordService"/>
  • 连接服务
 //连接服务public void connectService(){//通过intent为中介绑定Service,会自动createIntent intent = new Intent(this,ScreenRecordService.class);//绑定过程连接,选择绑定模式bindService(intent,serviceConnection,BIND_AUTO_CREATE);}
  • 判断服务是否连接成功
  • 成功则向系统发送录屏请求
//连接服务成功与否,具体连接过程//调用连接接口,实现连接,回调连接结果private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {//服务连接成功,需要通过Binder获取服务,达到Activity和Service通信的目的//获取BinderScreenRecordService.ScreenRecordBinder binder = (ScreenRecordService.ScreenRecordBinder) iBinder;//通过Binder获取ServicescreenRecordService = binder.getScreenRecordService();//获取到服务,初始化录屏管理者mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);//通过管理者,创建录屏请求,通过IntentIntent captureIntent = mediaProjectionManager.createScreenCaptureIntent();//将请求码作为标识一起发送,调用该接口,需有返回方法startActivityForResult(captureIntent,REQUEST_CODE);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {//连接失败Toast.makeText(MainActivity.this,"录屏服务未连接成功,请重试!",Toast.LENGTH_SHORT).show();}};
  • 请求之后,获得返回的信息
@Override//返回方法,获取返回的信息protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);//首先判断请求码是否一致,结果是否okif(requestCode == REQUEST_CODE && resultCode == RESULT_OK){//录屏请求成功,使用工具MediaProjection录屏//从发送获得的数据和结果中获取该工具mediaProjection = mediaProjectionManager.getMediaProjection(resultCode,data);//将该工具给Service,并一起传过去需要录制的屏幕范围的参数if(screenRecordService != null){screenRecordService.setMediaProjection(mediaProjection);screenRecordService.setConfig(metrics.widthPixels,metrics.heightPixels,metrics.densityDpi);}}}

开始录制

  • 获得了返回的信息,将参数都发送过去后,开始录制
//服务的两个主要逻辑//开始录屏public boolean startRecord() {//首先判断是否有录屏工具以及是否在录屏if (mediaProjection == null || running) {return false;}//有录屏工具,没有在录屏,就进行录屏//初始化录像机,录音机RecorderinitRecorder();//根据获取的屏幕参数创建虚拟的录屏屏幕createVirtualDisplay();//本来不加异常也可以,但是这样就不知道是否start成功//万一start没有成功,但是running置为true了,就产生了错误也无提示//提示开始录屏了,但是并没有工作try{//准备工作都完成了,可以开始录屏了mediaRecorder.start();//标志位改为正在录屏running = true;return true;}catch (Exception e){e.printStackTrace();//有异常,start出错,没有开始录屏,弹出提示Toast.makeText(this,"开启失败,没有开始录屏",Toast.LENGTH_SHORT).show();//标志位变回没有录屏的状态running = false;return false;}}
  • 录制需要录像机
//初始化Recorder录像机public void initRecorder() {//新建RecordermediaRecorder = new MediaRecorder();//设置录像机的一系列参数//设置音频来源mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置视频来源mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);//设置视频格式为mp4mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//设置视频存储地址,返回的文件夹下的命名为当前系统事件的文件videoPath = getSaveDirectory() + System.currentTimeMillis() + ".mp4";//保存在该位置mediaRecorder.setOutputFile(videoPath);//设置视频大小,清晰度mediaRecorder.setVideoSize(width, height);//设置视频编码为H.264mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);//设置音频编码mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//设置视频码率mediaRecorder.setVideoEncodingBitRate(2 * 1920 * 1080);mediaRecorder.setVideoFrameRate(18);//初始化完成,进入准备阶段,准备被使用//截获异常,处理try {mediaRecorder.prepare();} catch (IOException e) {e.printStackTrace();//异常提示Toast.makeText(this,"Recorder录像机prepare失败,无法使用,请重新初始化!",Toast.LENGTH_SHORT).show();}}
  • 录制需要虚拟屏幕
 public void createVirtualDisplay() {//虚拟屏幕通过MediaProjection获取,传入一系列传过来的参数//可能创建时会出错,捕获异常try {virtualDisplay = mediaProjection.createVirtualDisplay("VirtualScreen", width, height, dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);}catch (Exception e){e.printStackTrace();Toast.makeText(this,"virtualDisplay创建录屏异常,请退出重试!",Toast.LENGTH_SHORT).show();}}
  • 录制的视频需要存储在一个位置
//获取存储文件夹的位置public String getSaveDirectory() {if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//如果确认为视频类型,设置根目录,绝对路径下的自定义文件夹中String rootDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "录屏文件" + "/";//创建该文件夹File file = new File(rootDir);if (!file.exists()) {//如果该文件夹不存在if (!file.mkdirs()) {//如果没有创建成功return null;}}//创建成功了,返回该目录return rootDir;} else {//不是音视频文件,不保存,无路径return null;}}

停止录制

  • 停止录制,一切设备还原
//停止录屏public boolean stopRecord() {if (!running) {//没有在录屏,无法停止return false;}//无论设备是否还原或者有异常,但是确实录屏结束,修改标志位为未录屏running = false;//本来加不加捕获异常都可以,但是为了用户体验度,加入会更好try{//Recorder停止录像,重置还原,以便下一次使用mediaRecorder.stop();mediaRecorder.reset();//释放virtualDisplay的资源virtualDisplay.release();}catch (Exception e){e.printStackTrace();//有异常,保存失败,弹出提示Toast.makeText(this,"录屏出现异常,视频保存失败!",Toast.LENGTH_SHORT).show();return false;}//无异常,保存成功Toast.makeText(this,"录屏结束,保存成功!",Toast.LENGTH_SHORT).show();return true;}

总结

总的来说,只有两个文件,一个Activity,一个Service,一个负责给用户操作,一个负责后台实现逻辑。

  • MainActivity
package com.example.screencap;import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;public class MainActivity extends AppCompatActivity implements View.OnClickListener {//请求码private final static int REQUEST_CODE = 101;//权限请求码private final static int PERMISSION_REQUEST_CODE = 1101;//录屏工具MediaProjectionManager mediaProjectionManager;MediaProjection mediaProjection;//开始按钮,停止按钮Button btn_start_recorder;Button btn_stop_recorder;//获取录屏范围参数DisplayMetrics metrics;//录屏服务ScreenRecordService screenRecordService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//实例化按钮btn_start_recorder = findViewById(R.id.btn_start_recorder);btn_stop_recorder = findViewById(R.id.btn_stop_recorder);//点击按钮,请求录屏btn_start_recorder.setOnClickListener(this);btn_stop_recorder.setOnClickListener(this);}//权限检查,连接录屏服务public void checkPermission() {//调用检查权限接口进行权限检查if ((ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED) && (ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)){//如果没有权限,获取权限//调用请求权限接口进行权限申请ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.RECORD_AUDIO},PERMISSION_REQUEST_CODE);}else{//有权限,连接录屏服务,进行录屏connectService();}}//没有权限,去请求权限后,需要判断用户是否同意权限请求@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if(requestCode == PERMISSION_REQUEST_CODE){//请求码相同if(grantResults.length > 0 &&(grantResults[0] != PackageManager.PERMISSION_GRANTED ||grantResults[1] != PackageManager.PERMISSION_GRANTED)){//如果结果都存在,但是至少一个没请求成功,弹出提示Toast.makeText(MainActivity.this,"请同意必须的应用权限,否则无法正常使用该功能!", Toast.LENGTH_SHORT).show();}else if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED &&grantResults[1] == PackageManager.PERMISSION_GRANTED){//如果结果都存在,两个权限都申请成功,连接服务,启动录屏Toast.makeText(MainActivity.this,"权限申请成功,用户同意!",Toast.LENGTH_SHORT).show();connectService();}}}//连接服务public void connectService(){//通过intent为中介绑定Service,会自动createIntent intent = new Intent(this,ScreenRecordService.class);//绑定过程连接,选择绑定模式bindService(intent,serviceConnection,BIND_AUTO_CREATE);}//连接服务成功与否,具体连接过程//调用连接接口,实现连接,回调连接结果private ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {//服务连接成功,需要通过Binder获取服务,达到Activity和Service通信的目的//获取BinderScreenRecordService.ScreenRecordBinder binder = (ScreenRecordService.ScreenRecordBinder) iBinder;//通过Binder获取ServicescreenRecordService = binder.getScreenRecordService();//获取到服务,初始化录屏管理者mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);//通过管理者,创建录屏请求,通过IntentIntent captureIntent = mediaProjectionManager.createScreenCaptureIntent();//将请求码作为标识一起发送,调用该接口,需有返回方法startActivityForResult(captureIntent,REQUEST_CODE);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {//连接失败Toast.makeText(MainActivity.this,"录屏服务未连接成功,请重试!",Toast.LENGTH_SHORT).show();}};@Override//返回方法,获取返回的信息protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {super.onActivityResult(requestCode, resultCode, data);//首先判断请求码是否一致,结果是否okif(requestCode == REQUEST_CODE && resultCode == RESULT_OK){//录屏请求成功,使用工具MediaProjection录屏//从发送获得的数据和结果中获取该工具mediaProjection = mediaProjectionManager.getMediaProjection(resultCode,data);//将该工具给Service,并一起传过去需要录制的屏幕范围的参数if(screenRecordService != null){screenRecordService.setMediaProjection(mediaProjection);//获取录屏屏幕范围参数metrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(metrics);screenRecordService.setConfig(metrics.widthPixels,metrics.heightPixels,metrics.densityDpi);}}}@Override//点击事件public void onClick(View view) {switch (view.getId()) {case R.id.btn_start_recorder://点击请求录屏后,第一件事,检查权限checkPermission();//参数传过去以后,如果在录制,提示if(screenRecordService != null && screenRecordService.isRunning()){Toast.makeText(MainActivity.this,"当前正在录屏,请不要重复点击哦!",Toast.LENGTH_SHORT).show();} else if(screenRecordService != null && !screenRecordService.isRunning()){//没有录制,就开始录制,弹出提示,返回主界面开始录制screenRecordService.startRecord();//返回主界面开始录制setToBackground();} else if(screenRecordService == null){connectService();}break;case R.id.btn_stop_recorder:if(screenRecordService != null && !screenRecordService.isRunning()){//没有在录屏,无法停止,弹出提示Toast.makeText(MainActivity.this,"您还没有录屏,无法停止,请先开始录屏吧!",Toast.LENGTH_SHORT).show();}else if(screenRecordService != null && screenRecordService.isRunning()){//正在录屏,点击停止,停止录屏screenRecordService.stopRecord();}break;}}//返回主界面开始录屏,相当于home键private void setToBackground(){//主页面的IntentIntent home = new Intent(Intent.ACTION_MAIN);//设置清除栈顶的启动模式home.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);//匹配符号home.addCategory(Intent.CATEGORY_HOME);//转换界面,隐式匹配,显示调用startActivity(home);}//当应用结束的时候,需要解除绑定服务,防止造成内存泄漏@Overrideprotected void onDestroy() {super.onDestroy();unbindService(serviceConnection);}
}
  • activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/btn_start_recorder"android:layout_width="200dp"android:layout_height="100dp"android:layout_gravity="center"android:layout_marginTop="200dp"android:background="@drawable/btn_start_recorder"android:text="Start Recorder"android:textSize="25dp" /><Buttonandroid:id="@+id/btn_stop_recorder"android:layout_width="200dp"android:layout_height="100dp"android:layout_gravity="center"android:layout_marginTop="50dp"android:background="@drawable/btn_stop_recorder"android:text="Stop Recorder"android:textSize="25dp" /></LinearLayout>
  • ScreenRecordService
package com.example.screencap;import android.app.Service;
import android.content.Intent;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Environment;
import android.os.HandlerThread;
import android.os.IBinder;
import android.widget.Toast;import androidx.annotation.Nullable;import java.io.File;
import java.io.IOException;public class ScreenRecordService extends Service {//录屏工具MediaProjectionprivate MediaProjection mediaProjection;//录像机MediaRecorderprivate MediaRecorder mediaRecorder;//用于录屏的虚拟屏幕private VirtualDisplay virtualDisplay;//声明录制屏幕的宽高像素private int width;private int height;
//    private int width = 720;
//    private int height = 1080;private int dpi;//标志,判断是否正在录屏private boolean running;//声明视频存储路径private String videoPath = "";//    @Override
//    public void onCreate() {//        super.onCreate();
        HandlerThread serviceThread = new HandlerThread("service_thread", android.os.Process.THREAD_PRIORITY_BACKGROUND);
        serviceThread.start();
//        running = false;
//    }@Overridepublic void onCreate() {super.onCreate();}//    @Override
//    public int onStartCommand(Intent intent, int flags, int startId) {//        return START_STICKY;
//    }@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();}@Overridepublic boolean onUnbind(Intent intent) {return super.onUnbind(intent);}//返回的Binderpublic class ScreenRecordBinder extends Binder {//返回Service的方法public ScreenRecordService getScreenRecordService() {return ScreenRecordService.this;}}@Nullable@Override//返回一个Binder用于通信,需要一个获取Service的方法public IBinder onBind(Intent intent) {return new ScreenRecordBinder();}//设置录屏工具MediaProjectionpublic void setMediaProjection(MediaProjection projection) {mediaProjection = projection;}//设置需要录制的屏幕参数public void setConfig(int width, int height, int dpi) {this.width = width;this.height = height;this.dpi = dpi;}//返回判断,判断其是否在录屏public boolean isRunning() {return running;}//服务的两个主要逻辑//开始录屏public boolean startRecord() {//首先判断是否有录屏工具以及是否在录屏if (mediaProjection == null || running) {return false;}//有录屏工具,没有在录屏,就进行录屏//初始化录像机,录音机RecorderinitRecorder();//根据获取的屏幕参数创建虚拟的录屏屏幕createVirtualDisplay();//本来不加异常也可以,但是这样就不知道是否start成功//万一start没有成功,但是running置为true了,就产生了错误也无提示//提示开始录屏了,但是并没有工作try{//准备工作都完成了,可以开始录屏了mediaRecorder.start();//标志位改为正在录屏running = true;return true;}catch (Exception e){e.printStackTrace();//有异常,start出错,没有开始录屏,弹出提示Toast.makeText(this,"开启失败,没有开始录屏",Toast.LENGTH_SHORT).show();//标志位变回没有录屏的状态running = false;return false;}}//停止录屏public boolean stopRecord() {if (!running) {//没有在录屏,无法停止return false;}//无论设备是否还原或者有异常,但是确实录屏结束,修改标志位为未录屏running = false;//本来加不加捕获异常都可以,但是为了用户体验度,加入会更好try{//Recorder停止录像,重置还原,以便下一次使用mediaRecorder.stop();mediaRecorder.reset();//释放virtualDisplay的资源virtualDisplay.release();}catch (Exception e){e.printStackTrace();//有异常,保存失败,弹出提示Toast.makeText(this,"录屏出现异常,视频保存失败!",Toast.LENGTH_SHORT).show();return false;}//无异常,保存成功Toast.makeText(this,"录屏结束,保存成功!",Toast.LENGTH_SHORT).show();return true;}//初始化Recorder录像机public void initRecorder() {//新建RecordermediaRecorder = new MediaRecorder();//设置录像机的一系列参数//设置音频来源mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置视频来源mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);//设置视频格式为mp4mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//设置视频存储地址,返回的文件夹下的命名为当前系统事件的文件videoPath = getSaveDirectory() + System.currentTimeMillis() + ".mp4";//保存在该位置mediaRecorder.setOutputFile(videoPath);//设置视频大小,清晰度mediaRecorder.setVideoSize(width, height);//设置视频编码为H.264mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);//设置音频编码mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//设置视频码率mediaRecorder.setVideoEncodingBitRate(2 * 1920 * 1080);mediaRecorder.setVideoFrameRate(18);//初始化完成,进入准备阶段,准备被使用//截获异常,处理try {mediaRecorder.prepare();} catch (IOException e) {e.printStackTrace();//异常提示Toast.makeText(this,"Recorder录像机prepare失败,无法使用,请重新初始化!",Toast.LENGTH_SHORT).show();}}public void createVirtualDisplay() {//虚拟屏幕通过MediaProjection获取,传入一系列传过来的参数//可能创建时会出错,捕获异常try {virtualDisplay = mediaProjection.createVirtualDisplay("VirtualScreen", width, height, dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null);}catch (Exception e){e.printStackTrace();Toast.makeText(this,"virtualDisplay创建录屏异常,请退出重试!",Toast.LENGTH_SHORT).show();}}//获取存储文件夹的位置public String getSaveDirectory() {if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//如果确认为视频类型,设置根目录,绝对路径下的自定义文件夹中String rootDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "录屏文件" + "/";//创建该文件夹File file = new File(rootDir);if (!file.exists()) {//如果该文件夹不存在if (!file.mkdirs()) {//如果没有创建成功return null;}}//创建成功了,返回该目录return rootDir;} else {//不是音视频文件,不保存,无路径return null;}}
}

【Android】录屏功能实现——MediaProjection相关推荐

  1. android 实现手机录屏功能,基于MediaProjection实现Android移动手机截屏和录屏功能

    Android软件应用经常要求实现截屏和录屏的功能,那么如何实现Android软件截屏和录屏功能呢?本文将介绍基于MediaProjection实现Android移动手机截屏和录屏功能. MediaP ...

  2. Android 录屏功能的实现

    最近开发中,要实现录屏功能,查阅相关资料,发现调用 MediaProjectionManager的api 实现录屏功能即可: import android.Manifest; import andro ...

  3. android录屏功能

    思路 android实现录屏功能有两种方案,一种是直接使用android自带的MediaProjectionManager实现录屏功能,第二种是是只录语音,用户的操作通过某种方式进行记录保存,最后通过 ...

  4. android录屏功能的实现

    近期项目需要录屏功能,功能已实现,特此记录一下. //<----------------------------------录屏开始------------------------------- ...

  5. android 手机录屏功能,Android录屏功能的实现

    最近做一个Android开发的项目用到了录屏的功能,开始查阅了一些资料和博客,基本上都是在讨论ROOT的.直到后来在github上看到一个比较新的代码,才恍然发现,Android 5.0时候开放了一个 ...

  6. 如何调用android录屏功能吗,Android录屏功能的实现

    最近做一个Android开发的项目用到了录屏的功能,开始查阅了一些资料和博客,基本上都是在讨论ROOT的.直到后来在github上看到一个比较新的代码,才恍然发现,Android 5.0时候开放了一个 ...

  7. webRTC(二十一):android 录屏功能

    效果 录屏和截屏的思路基本一致,请看详细代码 布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/an ...

  8. Android 和dialog 防录屏功能失效,游戏防录屏功能失效.

    1. 正常禁止录屏在Activity的onCreate()方法中调用如下代码,但是在小米,OPPO等设备上只能禁止截屏,无法禁止录屏. @Overrideprotected void onCreate ...

  9. android 手机录屏功能,手机自带录屏功能在哪里找?轻松搞定屏幕录制

    手机的录屏功能如何使用?智能手机发展到现在,除了无线通话功能.讯息发送功能之外,又逐渐发展出拍照功能.上网功能.各类应用交互功能.尤其近几年在手机上看视频成为打发碎片化时间的重要消遣,在手机上录屏的需 ...

最新文章

  1. python语音合成 标贝_tacotronV2 + wavernn 实现中文语音合成(Tensorflow + pytorch)
  2. input框必填星号*垂直居中变大设置
  3. 【iOS-cocos2d-X 游戏开发之十三】cocos2dx通过Jni调用Android的Java层代码(上)
  4. 无插件web直播解决方案,ffmpeg+nginx-http-flv-module+flv.js
  5. Leaflet中使用leaflet-cion-pulse插件实现波动的图标效果
  6. mplayer1.3.0交叉编译
  7. DC/DC变换器的典型拓扑
  8. 如何用ant给Java项目生成文档
  9. Java后台与VUE跨域交接
  10. python实现软件的注册功能(机器码+注册码机制)
  11. 一个程序员的逗逼瞬间(四)
  12. html5编辑漂亮静态页面工具_青岛HTML5与Web前端
  13. RecyclerView数据显示不全的问题
  14. ARouter路由简单使用以及源码解析
  15. 一些医学影像的成像原理
  16. 计算机毕业设计Java河南省农村多元化养老服务管理系统设计与实现(源码+系统+mysql数据库+lw文档)
  17. 【基础入门题031】三色球问题
  18. java中定义数组的3种方式
  19. php怎么自动识别车牌号,你知道车牌识别系统是如何自动识别车牌的吗?
  20. 计算机主机配置科普,一秒看懂电脑配置,组装电脑不求人

热门文章

  1. java dbcp连接池_Java——DBCP连接池
  2. matlab移相法实现单边带调制,利用希尔伯特变换实现单边带调制
  3. 易宝支付声明称遭遇大规模黑客攻击
  4. 【路径规划】基于FLOYD算法实现邮政运输网络中的邮路规划和邮车调度matlab代码
  5. 云服务器相比传统IDC有哪些优势?这里讲得很清楚了
  6. python制表符是什么
  7. [转]视频捕捉全教程(vc+vfw)
  8. Java 实现长图文生成
  9. 计算机图文混合排版教学设计,图文表混合排版教学设计.doc
  10. 简单网站统计功能的实现 PV IP 真实访客数(UV)