安卓5.0及以上提供了支持截屏和录屏的API
布局如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/mainFrame"
android:layout_height="match_parent">
<Button android:layout_width="100dp"
android:text="录屏"
android:id="@+id/butview"
android:layout_gravity="center"
android:layout_height="60dp"/>
<Button android:layout_width="100dp"
android:text="截屏"
android:layout_marginTop="100dp"
android:id="@+id/capout"
android:layout_gravity="center"
android:layout_height="60dp"/>
<ImageView
android:id="@+id/img"
android:layout_margin="60dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
主代码如下:
package com.example.leixiansheng.testactivity;
import android.Manifest;
import android.app.Activity;
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.IBinder;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
Button mButton, mCapButton;
ImageView mImageView;
private MediaProjectionManager projectionManager;
private MediaProjection mediaProjection;
private ScreenService recordService;
private static int RECORD_REQUEST_CODE = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mButton = (Button) findViewById(R.id.butview);
mCapButton = (Button) findViewById(R.id.capout);
mImageView = (ImageView) findViewById(R.id.img);
askPermission();
Intent intent = new Intent(this, ScreenService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//######## 录屏逻辑 ########
if (recordService.isRunning()) {
recordService.stopRecord();
mButton.setText("录屏");
} else {
//这里是请求录屏权限
Intent captureIntent = projectionManager
.createScreenCaptureIntent();
startActivityForResult(captureIntent, RECORD_REQUEST_CODE);
}
}
});
mCapButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent in = new Intent(MainActivity.this, CapoutActivity.class);
startActivity(in);
}
});
}
private void askPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 102);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 103);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 104);
}
Intent intent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
intent = projectionManager.createScreenCaptureIntent();
startActivityForResult(intent, 101);//正常情况是要执行到这里的,作用是申请捕捉屏幕
} else {
Toast.makeText(this, "Android版本太低,无法使用该功能",Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {
//######## 录屏逻辑 ########
mediaProjection = projectionManager
.getMediaProjection(resultCode, data);
recordService.setMediaProject(mediaProjection);
recordService.startRecord();
mButton.setText("结束");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
/**
* 绑定ScreenService
*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
ScreenService.RecordBinder binder = (ScreenService.RecordBinder) service;
recordService = binder.getRecordService();
recordService
.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
mButton.setEnabled(true);
mButton.setText(recordService.isRunning() ? "结束" : "开始");
}
@Override
public void onServiceDisconnected(ComponentName arg0) {}
};
}
ScreenService 记得Mainfest中注册
package com.example.leixiansheng.testactivity;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* 项目名称:
* 类描述: 录屏服务类
*/
public class ScreenService extends Service {
private MediaRecorder mediaRecorder;
private VirtualDisplay virtualDisplay;
private boolean running;
private int width = 720;
private int height = 1080;
private int dpi;
private ImageReader mImageReader;
private MediaProjection mediaProjection;
@Override
public IBinder onBind(Intent intent) {
return new RecordBinder();
}
@Override
public void onCreate() {
super.onCreate();
running = false;
mediaRecorder = new MediaRecorder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public void setMediaProject(MediaProjection project) {
mediaProjection = project;
}
public boolean isRunning() {
return running;
}
public void setConfig(int width, int height, int dpi) {
this.width = width;
this.height = height;
this.dpi = dpi;
}
/**
* 开始录屏
*
* @return true
*/
public boolean startRecord() {
if (mediaProjection == null || running) {
return false;
}
initRecorder();
createVirtualDisplay();
mediaRecorder.start();
running = true;
return true;
}
/**
* 结束录屏
*
* @return true
*/
public boolean stopRecord() {
if (!running) {
return false;
}
running = false;
mediaRecorder.stop();
mediaRecorder.reset();
virtualDisplay.release();
mediaProjection.stop();
return true;
}
public void setMediaProjection(MediaProjection mediaProjection) {
this.mediaProjection = mediaProjection;
}
/**
* 初始化ImageRead参数
*/
public void initImageReader() {
if (mImageReader == null) {
int maxImages = 2;
mImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, maxImages);
createImageVirtualDisplay();
}
}
/**
* 创建一个录屏 Virtual
*/
private void createVirtualDisplay() {
virtualDisplay = mediaProjection
.createVirtualDisplay("mediaprojection", width, height, dpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder
.getSurface(), null, null);
}
/**
* 创建一个ImageReader Virtual
*/
private void createImageVirtualDisplay() {
virtualDisplay = mediaProjection
.createVirtualDisplay("mediaprojection", width, height, dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader
.getSurface(), null, null);
}
/**
* 初始化保存屏幕录像的参数
*/
private void initRecorder() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(
getSavePath() + System.currentTimeMillis() + ".mp4");
mediaRecorder.setVideoSize(width, height);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
mediaRecorder.setVideoFrameRate(30);
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获取一个保存屏幕录像的路径
*
* @return path
*/
public String getSavePath() {
if (Environment.getExternalStorageState()
.equals(Environment.MEDIA_MOUNTED)) {
String rootDir = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" +
"ScreenRecord" + "/";
File file = new File(rootDir);
if (!file.exists()) {
if (!file.mkdirs()) {
return null;
}
}
return rootDir;
} else {
return null;
}
}
/**
* 请求完权限后马上获取有可能为null,可以通过判断is null来重复获取。
*/
public Bitmap getBitmap() {
Bitmap bitmap = cutoutFrame();
if (bitmap == null) {
getBitmap();
}
return bitmap;
}
/**
* 通过底层来获取下一帧的图像
*
* @return bitmap
*/
public Bitmap cutoutFrame() {
Image image = mImageReader.acquireLatestImage();
if (image == null) {
return null;
}
int width = image.getWidth();
int height = image.getHeight();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
Bitmap bitmap = Bitmap.createBitmap(width +
rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
return Bitmap.createBitmap(bitmap, 0, 0, width, height);
}
public class RecordBinder extends Binder {
public ScreenService getRecordService() {
return ScreenService.this;
}
}
}
CapoutActivity
package com.example.leixiansheng.testactivity;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
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.ImageView;
/**
* 项目名称:
* 类描述:截屏
*/
public class CapoutActivity extends Activity {
Button mButton;
ImageView mImageView;
private MediaProjectionManager projectionManager;
private MediaProjection mediaProjection;
private ScreenService recordService;
private static int RECORD_REQUEST_CODE = 5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_capout);
projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mButton = (Button) findViewById(R.id.butview);
mImageView = (ImageView) findViewById(R.id.img);
Intent intent = new Intent(this, ScreenService.class);
bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
Intent captureIntent = projectionManager.createScreenCaptureIntent();
startActivityForResult(captureIntent, RECORD_REQUEST_CODE);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//######## 截屏逻辑 ########
Bitmap bitmap = recordService.getBitmap();
mImageView.setImageBitmap(bitmap);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) {
//######## 截屏逻辑 ########
mediaProjection = projectionManager.getMediaProjection(resultCode, data);
recordService.setMediaProject(mediaProjection);
recordService.initImageReader();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mServiceConnection);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
ScreenService.RecordBinder binder = (ScreenService.RecordBinder) service;
recordService = binder.getRecordService();
recordService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi);
mButton.setEnabled(true);
mButton.setText(recordService.isRunning() ? "结束" : "开始");
}
@Override
public void onServiceDisconnected(ComponentName arg0) {}
};
}