最近两天研究了一下安卓截屏和录屏功能的实现,基本的思路如下:

截屏:通过View绘制缓冲获得Bitmap,然后写到文件中,完成截屏的功能;

录屏:通过MediaRecorder进行video record,基本过程如下:

MediaRecorder recorder = new MediaRecorder();recorder.setAudioSource(MediaRecorder.AudioSource.MIC);recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);recorder.setOutputFile(PATH_NAME);recorder.prepare();recorder.start();   // Recording is now started...recorder.stop();recorder.reset();   // You can reuse the object by going back to setAudioSource() steprecorder.release(); // Now the object cannot be reused

要是想实现录屏功能,首先需要向系统申请权限,然后得到系统的反馈,分别创建录屏服务、MediaProjectionManager、MediaRecorder以及创建VirtualDisplay,最后开始录屏。录屏结束后对相关资源进行释放。

下面上代码:

首先是配置权限:

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.CAMERA"/>

然而在实际开发中发生了如下一幕,Permission Deny.这个时候可能是相关的权限没有自动打开,需要手动去应用权限管理中将相关的权限打开,如下:

然后就是写界面XML(界面很简单):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/linearLayout"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"><Buttonandroid:id="@+id/buttonCapture"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginEnd="20dp"android:layout_marginStart="20dp"android:text="截屏"android:textSize="24sp" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"><Buttonandroid:id="@+id/buttonRecord"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginEnd="20dp"android:layout_marginStart="20dp"android:text="录屏"android:textSize="24sp" /></LinearLayout></LinearLayout>

效果如下:

接下来是MainActivity.java(相关说明写在注释中了,直接参考的API,准确一些,现在访问API可方便多了,哈哈哈)

package com.dzjin.screen.screenshotandrecorddemo;import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.projection.MediaProjectionManager;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;public class MainActivity extends AppCompatActivity {private LinearLayout linearLayout=null;private Button buttonRecord=null;private Button buttonCapture=null;private boolean isRecord=false;private int mScreenWidth;private int mScreenHeight;private int mScreenDensity;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getScreenBaseInfo();linearLayout=(LinearLayout)findViewById(R.id.linearLayout);buttonRecord=(Button)findViewById(R.id.buttonRecord);buttonCapture=(Button)findViewById(R.id.buttonCapture);buttonRecord.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if(isRecord){stopScreenRecord();}else{startScreenRecord();}}});buttonCapture.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {capture(linearLayout);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if(requestCode == 1000){if(resultCode == RESULT_OK){//获得录屏权限,启动Service进行录制Intent intent=new Intent(MainActivity.this,ScreenRecordService.class);intent.putExtra("resultCode",resultCode);intent.putExtra("resultData",data);intent.putExtra("mScreenWidth",mScreenWidth);intent.putExtra("mScreenHeight",mScreenHeight);intent.putExtra("mScreenDensity",mScreenDensity);startService(intent);Toast.makeText(this,"录屏开始",Toast.LENGTH_SHORT).show();}else{Toast.makeText(this,"录屏失败",Toast.LENGTH_SHORT).show();}}}//start screen recordprivate void startScreenRecord(){//Manages the retrieval of certain types of MediaProjection tokens.MediaProjectionManager mediaProjectionManager=(MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);//Returns an Intent that must passed to startActivityForResult() in order to start screen capture.Intent permissionIntent=mediaProjectionManager.createScreenCaptureIntent();startActivityForResult(permissionIntent,1000);isRecord=true;buttonRecord.setText(new String("停止录屏"));}//stop screen record.private void stopScreenRecord(){Intent service = new Intent(this, ScreenRecordService.class);stopService(service);isRecord=false;buttonRecord.setText(new String("开始录屏"));Toast.makeText(this,"录屏成功",Toast.LENGTH_SHORT).show();}public void capture(View v){//格式化时间作为截屏文件名SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YY-MM-DD-HH-MM-SS");//在获取外部存储的时候,一定注意添加权限,如果添加权限还不能成功,则手动在应用中开启权限。String filePathName= Environment.getExternalStorageDirectory()+"/"+simpleDateFormat.format(new Date())+".png";//Find the topmost view in the current view hierarcht.View view=v.getRootView();// Enable or disable drawing cache.view.setDrawingCacheEnabled(true);// Calling this method is equivalent to calling buildDrawingCache(false);// In order to force drawing cache to be buuild.view.buildDrawingCache();//Calling this method is equivalent to calling getDrawingCache(false);//Return the Bitmap in which this view drawing is cached.Bitmap bitmap=view.getDrawingCache();try{System.out.println(filePathName);FileOutputStream fileOutputStream=new FileOutputStream(filePathName);//Write a compressed version of bitmap to specified outputStream.bitmap.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);Toast.makeText(this,"Cpature Succeed",Toast.LENGTH_SHORT).show();}catch (Exception e){e.printStackTrace();Toast.makeText(this,"Cpature Failed",Toast.LENGTH_SHORT).show();}}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {// 在这里将BACK键模拟了HOME键的返回桌面功能(并无必要)if (keyCode == KeyEvent.KEYCODE_BACK) {simulateHome();return true;}return super.onKeyDown(keyCode, event);}/*** 获取屏幕基本信息*/private void getScreenBaseInfo() {//A structure describing general information about a display, such as its size, density, and font scaling.DisplayMetrics metrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(metrics);mScreenWidth = metrics.widthPixels;mScreenHeight = metrics.heightPixels;mScreenDensity = metrics.densityDpi;}/*** 模拟HOME键返回桌面的功能*/private void simulateHome() {//Intent.ACTION_MAIN,Activity Action: Start as a main entry point, does not expect to receive data.Intent intent = new Intent(Intent.ACTION_MAIN);//If set, this activity will become the start of a new task on this history stack.intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//This is the home activity, that is the first activity that is displayed when the device boots.intent.addCategory(Intent.CATEGORY_HOME);this.startActivity(intent);}}

录屏ScreenRecordService.java

package com.dzjin.screen.screenshotandrecorddemo;import android.app.Service;
import android.content.Context;
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.media.projection.MediaProjectionManager;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;import java.text.SimpleDateFormat;
import java.util.Date;/*** Created by dzjin on 2018/1/9.*/public class ScreenRecordService extends Service {private int resultCode;private Intent resultData=null;private MediaProjection mediaProjection=null;private MediaRecorder mediaRecorder=null;private VirtualDisplay virtualDisplay=null;private int mScreenWidth;private int mScreenHeight;private int mScreenDensity;private Context context=null;@Overridepublic void onCreate() {super.onCreate();}/*** Called by the system every time a client explicitly starts the service by calling startService(Intent),* providing the arguments it supplied and a unique integer token representing the start request.* Do not call this method directly.* @param intent* @param flags* @param startId* @return*/@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {try{resultCode=intent.getIntExtra("resultCode",-1);resultData=intent.getParcelableExtra("resultData");mScreenWidth=intent.getIntExtra("mScreenWidth",0);mScreenHeight=intent.getIntExtra("mScreenHeight",0);mScreenDensity=intent.getIntExtra("mScreenDensity",0);mediaProjection=createMediaProjection();mediaRecorder=createMediaRecorder();virtualDisplay=createVirtualDisplay();mediaRecorder.start();}catch (Exception e) {e.printStackTrace();}/*** START_NOT_STICKY:* Constant to return from onStartCommand(Intent, int, int): if this service's process is* killed while it is started (after returning from onStartCommand(Intent, int, int)),* and there are no new start intents to deliver to it, then take the service out of the* started state and don't recreate until a future explicit call to Context.startService(Intent).* The service will not receive a onStartCommand(Intent, int, int) call with a null Intent* because it will not be re-started if there are no pending Intents to deliver.*/return Service.START_NOT_STICKY;}//createMediaProjectionpublic MediaProjection createMediaProjection(){/*** Use with getSystemService(Class) to retrieve a MediaProjectionManager instance for* managing media projection sessions.*/return ((MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE)).getMediaProjection(resultCode,resultData);/*** Retrieve the MediaProjection obtained from a succesful screen capture request.* Will be null if the result from the startActivityForResult() is anything other than RESULT_OK.*/}private MediaRecorder createMediaRecorder(){SimpleDateFormat simpleDateFormat=new SimpleDateFormat("YY-MM-DD-HH-MM-SS");String filePathName= Environment.getExternalStorageDirectory()+"/video"+simpleDateFormat.format(new Date())+".mp4";//Used to record audio and video. The recording control is based on a simple state machine.MediaRecorder mediaRecorder=new MediaRecorder();//Set the video source to be used for recording.mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);//Set the format of the output produced during recording.//3GPP media file formatmediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//Sets the video encoding bit rate for recording.//param:the video encoding bit rate in bits per second.mediaRecorder.setVideoEncodingBitRate(5*mScreenWidth*mScreenHeight);//Sets the video encoder to be used for recording.mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);//Sets the width and height of the video to be captured.mediaRecorder.setVideoSize(mScreenWidth,mScreenHeight);//Sets the frame rate of the video to be captured.mediaRecorder.setVideoFrameRate(60);try{//Pass in the file object to be written.mediaRecorder.setOutputFile(filePathName);//Prepares the recorder to begin capturing and encoding data.mediaRecorder.prepare();}catch (Exception e){e.printStackTrace();}return mediaRecorder;}private VirtualDisplay createVirtualDisplay(){/*** name String: The name of the virtual display, must be non-empty.This value must never be null.width  int: The width of the virtual display in pixels. Must be greater than 0.height  int: The height of the virtual display in pixels. Must be greater than 0.dpi    int: The density of the virtual display in dpi. Must be greater than 0.flags    int: A combination of virtual display flags. See DisplayManager for the full list of flags.surface  Surface: The surface to which the content of the virtual display should be rendered, or null if there is none initially.callback    VirtualDisplay.Callback: Callback to call when the virtual display's state changes, or null if none.handler    Handler: The Handler on which the callback should be invoked, or null if the callback should be invoked on the calling thread's main Looper.*//*** DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR* Virtual display flag: Allows content to be mirrored on private displays when no content is being shown.*/return mediaProjection.createVirtualDisplay("mediaProjection",mScreenWidth,mScreenHeight,mScreenDensity,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mediaRecorder.getSurface(),null,null);}@Overridepublic void onDestroy() {super.onDestroy();if(virtualDisplay!=null){virtualDisplay.release();virtualDisplay=null;}if(mediaRecorder!=null){mediaRecorder.stop();mediaRecorder=null;}if(mediaProjection!=null){mediaProjection.stop();mediaProjection=null;}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}

OK,完成,相关的解释直接写在代码中了。

非淡泊无以明志,非宁静无以致远。共勉。

Demo下载地址:http://download.csdn.net/download/dzjin1234/10199546

Android截屏和录屏Demo相关推荐

  1. 安卓java录屏_安卓实现截屏以及录屏功能Demo

    [实例简介]安卓实现截屏以及录屏功能Demo 安卓实现截屏以及录屏功能Demo [实例截图] [核心代码] package com.dzjin.screen.screenshotandrecordde ...

  2. Android中的截屏、录屏、投屏等常用命令和工具

    1:截屏命令screencap adb shell screencap -p /sdcard/screen.png 详细使用可以使用命令adb shell screencap –v查看帮助 对应的编译 ...

  3. android录屏弹窗,android视频截屏手机录屏实现代码

    本文介绍了android视频截屏&手机录屏实现代码,分享给大家,希望对大家有帮助 问题 在android中有时候我们需要对屏幕进行截屏操作,单一的截屏操作好解决可以通过activity的顶层v ...

  4. android视频截屏手机录屏实现

    问题 在android中有时候我们需要对屏幕进行截屏操作,单一的截屏操作好解决可以通过activity的顶层view DecorView获取一个bitmap,得到就是当前activity上面的全部视图 ...

  5. 截屏 远程协助 android,ARDC Android 远程桌面助手 录屏 演示 MD

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? ARDC Android 远程桌面助手 录屏 演示 MD ARDC:Android Remote Displayer a ...

  6. Android 关于禁止应用截屏和录屏

    APP有时候为了保护用户的隐私安全会禁止用户录屏和截屏,录入说视频交友类的app,金融类的app等 可以在app的onCreate方法中添加这么一段代码: @Overrideprotected voi ...

  7. Android截屏、录屏,适配AndroidQ以上

    使用MediaProjectionManager,VirtualDisplay,AudioRecord,MediaCodec以及MediaMuxer等API实现屏幕录制功能.MediaProjecti ...

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

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

  9. android禁止录屏功能,react-native(安卓)项目中禁止截屏与录屏

    一.整个项目中禁止截屏与录屏 在android/app/src/main/java/com/your-app-name/MainActivity.java文件中的onCreate方法中添加如下代码即可 ...

最新文章

  1. 如何评估互阻抗放大器(第 2 部分)
  2. 线程同步 生产者消费者 java_Java线程同步:生产者-消费者 模型(代码示例)
  3. Pytho学习笔记:错误,测试,调试(合)
  4. 用JavaScript fetch API取数据遇到CORS policy问题
  5. 利用F#库canopy进行UI测试
  6. sqlite 复合唯一索引_SQLite 索引(Index)
  7. Integer的常用方法和String类型的常用方法
  8. PHP单次数据库查询实现无限级分类
  9. 软考:软件设计师(历年真题汇总)|希赛网
  10. 中职c语言课程教学标准,C语言课程标准.doc
  11. Linux 多线程同步之哲学家用餐问题分析
  12. 全球红外(IR)LED行业收入预计2028年达到13.699亿美元
  13. 【GAN】生成式对抗网络论文笔记及TF2代码实现
  14. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part3前端搭建与可视化
  15. .Net框架设计(Yanlz+Unity+XR+C#+.Net+框架+框架设计+设计模式+工具可视化+SOA+立钻哥哥+==)
  16. 如何在Chrome中自定义新标签页
  17. canvas实现矩形框,用来进行图片框选
  18. Capture Modules 车载网络报文捕获(监听)模块(低时延、802.1AS时钟同步)
  19. JavaScript-2:初体验JS
  20. 各种时间概念的详细解释 恒星时世界时 协调世界时

热门文章

  1. 前端三剑客 React、Angular、Vue.js 比较
  2. 泛微eoffice10二开入门示例
  3. stm32ad测量范围_用STM32的AD测电压,范围是0~3.3V,但是输入电压可能高于3.3,怎么保护STM32?...
  4. EMA指数滑动平均(Exponential Moving Average)
  5. C++如何实现系统语言切换功能,MessageBox的确认/取消按钮语言显示如何跟程序一致
  6. 2023年美国大学生数学建模竞赛赛题发布【英文原文 中文翻译】
  7. b、B、KB、Kib、MB、MiB、GB、GiB、TB、TiB的区别
  8. 姚舜:北漂后悔一阵子,不北漂后悔一辈子
  9. 通达信量化API接口调用说明
  10. 关于Apache服务器配置SSL证书的那些事(保姆级教程)