
錄屏工具和源碼下載下傳(gitee.com)
錄屏工具和源碼下載下傳(github.com)
也可掃描二維碼,安裝錄屏工具到手機
錄屏工具下載下傳
截屏、錄屏 功能快速接入:
1、在項目中libs中添加ScreenShot.jar
2、在AndroidManifest.xml中添加存儲權限和Activity聲明
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<activity
android:name="sc.tool.screenshot.ScreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />
3、調用方法:
截屏用法:
(1)初始化請求允許擷取螢幕 ScreenActivity.Init(context);
(2)擷取螢幕圖像 ScreenActivity.GetScreen_pic() 或 直接儲存截屏ScreenActivity.GetScreen();
或 拓展調用接口:ScreenActivity.GetScreen(final long DellayMillionSecond, final int times)
錄屏用法:
(1)初始化請求允許擷取螢幕 ScreenActivity.Init(context);
(2)開始錄屏:ScreenActivity.GetVedio_Start();
(3)停止錄屏:ScreenActivity.GetVedio_Stop();
接入結束
附錄:
截屏、錄屏 調用示例
package sc.screen.demo;
import sc.tool.screenshot.ScreenActivity;
import sc.tool.screenshot.ScreenTool;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
//import sc.tool.screenshot.ScreenActivity.ScreenCallBack;
public class MainActivity extends Activity
{
EditText Interval;
EditText Times;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Interval = (EditText) this.findViewById(R.id.textInterval);
Times = (EditText) this.findViewById(R.id.textTimes);
ScreenActivity.Init(this); // 初始化允許截屏請求
// // 請求允許擷取螢幕,用允許時截屏儲存
// ScreenActivity.Init(this, new ScreenCallBack()
// {
// @Override
// public void Success()
// {
// ScreenActivity.GetScreen(); // 截屏儲存
// }
// });
}
public void ScreeShot(View view)
{
ScreenTool.GetScreen(this); // Activity截屏
Toast.makeText(this, "截屏已儲存", Toast.LENGTH_SHORT).show();
}
public void ScreeShot_Proj(View view)
{
ScreenActivity.GetScreen(); // 投影截屏
Toast.makeText(this, "截屏已儲存", Toast.LENGTH_SHORT).show();
}
public void ScreeShot_Proj_Auto(View view)
{
ScreenActivity.GetScreen(1000, 5); // 投影截屏(延時多次截屏)
}
public void ScreeShot_sustom(View view)
{
try
{
Long inteval = Long.parseLong(Interval.getText().toString());
int times = Integer.parseInt(Times.getText().toString());
ScreenActivity.GetScreen(inteval, times); // 投影截屏(延時多次截屏)
}
catch (Exception ex)
{}
}
public void ScreeRecord(View view)
{
Button btn = (Button) view;
String text = btn.getText().toString().trim();
if (text.equals("開始錄屏(3秒後開始)"))
{
btn.setText("停止錄屏");
ScreenActivity.GetVedio_Start(3000L); // 開始錄屏
}
else if (text.equals("停止錄屏"))
{
btn.setText("開始錄屏(3秒後開始)");
String path = ScreenActivity.GetVedio_Stop(); // 停止錄屏
if (!path.equals(""))
{
Toast.makeText(this, "錄屏已儲存" + "\n" + path, Toast.LENGTH_SHORT).show();
}
}
}
}
截屏、錄屏 實作核心源碼
package sc.tool.screenshot;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.WindowManager;
/* 請在AndroidManifest.xml中添加存儲權限和Activity聲明
*
* 截屏需要權限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<activity
android:name="sc.tool.screenshot.ScreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
android:launchMode="singleTop" />
*/
/* 錄屏需要權限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
*/
/* ScreenActivity說明(封裝MediaProjectionManager,友善擷取螢幕操作 )
*
* 截屏用法:
* 1、初始化請求允許擷取螢幕 ScreenActivity.Init(context);
* 2、擷取螢幕圖像 ScreenActivity.GetScreen_pic() 或 直接儲存截屏
* ScreenActivity.GetScreen(); 拓展調用接口:ScreenActivity.GetScreen(final long DellayMillionSecond, final int times)
*
* 截屏原理:
* 1、通過MediaProjectionManager請求擷取螢幕投影,在使用者允許時擷取螢幕投影,将螢幕投影到虛拟顯示器(虛拟顯示器建立時與ImageReader綁定)
* 2、通過ImageReader讀取投影螢幕
*
*
* 錄屏用法:
* 1、初始化請求允許擷取螢幕 ScreenActivity.Init(context);
* 2、開始錄屏:ScreenActivity.GetVedio_Start();
* 3、停止錄屏:ScreenActivity.GetVedio_Stop();
*
* 錄屏原理:
* 1、通過MediaProjectionManager請求擷取螢幕投影,在使用者允許時擷取螢幕投影,将螢幕投影到虛拟顯示器(虛拟顯示器建立時與MediaRecorder綁定)
* 2、通過MediaRecorder進行螢幕的錄制
* */
/**
* 請求擷取螢幕投影: ScreenActivity.Init(context);
* 截屏: ScreenActivity.GetScreen();
* 開始錄屏: ScreenActivity.GetVedio_Start();
* 停止錄屏: ScreenActivity.GetVedio_Stop();
* */
public class ScreenActivity extends Activity
{
private static Context context_S = null;
/** 截屏初始化(請求使用者允許擷取螢幕) */
public static void Init(Context context)
{
if (isInit) return;
context_S = context;
if (context != null)
{
Intent intent = new Intent(context, ScreenActivity.class);
// intent.setAction("intent.action.sc.ScreenShot");
context.startActivity(intent);
}
}
private static ScreenCallBack call;
/** 截屏初始化(請求使用者允許擷取螢幕),在允許時執行回調 */
public static void Init(Context context, ScreenCallBack initCall)
{
call = initCall;
Init(context);
}
/** 标記是否初始化成功 */
private static boolean isInit = false;
private static MediaProjection Projection;
private static ImageReader ImageR; // 用于截屏
private static MediaRecorder Recorder; // 用于錄屏
private MediaProjectionManager PrManager; // 螢幕投影管理器
public static final int requestCode_Projection = 6556;
private static int W;
private static int H;
private static int D;
// 初始載入螢幕尺寸、分辨率資訊
private void LoadScreenInfo()
{
WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(metrics);
D = metrics.densityDpi;
W = metrics.widthPixels;
H = metrics.heightPixels;
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
try
{
if (Build.VERSION.SDK_INT >= 21)
{
LoadScreenInfo();
PrManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); // 擷取Manager
startActivityForResult(PrManager.createScreenCaptureIntent(), requestCode_Projection); // 請求擷取螢幕顯示
// Toast.makeText(this, "onCreate -> 已執行", Toast.LENGTH_SHORT).show();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == requestCode_Projection)
{
// Toast.makeText(this, "onActivityResult -> 已執行0", Toast.LENGTH_SHORT).show();
if (resultCode == RESULT_OK && data != null)
{
Projection = PrManager.getMediaProjection(Activity.RESULT_OK, data); // 允許擷取螢幕時,擷取投影
isInit = true;
if (call != null) call.Success(); // 執行回調邏輯
// Toast.makeText(this, "onActivityResult -> 已執行1", Toast.LENGTH_SHORT).show();
}
}
// Toast.makeText(this, "onActivityResult -> 已執行2 : " + resultCode, Toast.LENGTH_SHORT).show();
this.finish(); // 權限請求後關閉目前Activity
}
// ==========
// 截屏
// ----------
/** 擷取實時顯示的螢幕圖像 */
public static Bitmap GetScreen_pic()
{
Bitmap pic = null;
if (isInit)
{
try
{
if (ImageR == null)
{
// 根據螢幕尺寸建立ImageReader,用于讀取投影螢幕
// ImageR = ImageReader.newInstance(W, H, PixelFormat.RGB_888, 1); // 格式若不是PixelFormat.RGB_888,在擷取截屏時會報錯給出類型: The producer output buffer
// format 0x03
ImageR = ImageReader.newInstance(W, H, PixelFormat.RGBA_8888, 1);
// 将螢幕投影到虛拟顯示器(虛拟顯示器建立時與ImageReader綁定)
Projection.createVirtualDisplay("screen-mirror", W, H, D, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, ImageR.getSurface(), null, null);
}
Image image = ImageR.acquireLatestImage(); // 通過ImageReader從螢幕投影中讀取最新的圖像
pic = ScreenTool.ToBitmap(image); // 轉化為Bitmap
// boolean isNull = (image == null);
// Toast.makeText(context_S, "startScreenShot -> " + (isNull ? "null" : "非空"), Toast.LENGTH_SHORT).show();
}
catch (Exception ex)
{
ex.printStackTrace();
// Toast.makeText(this, "startScreenShot -> \n" + ex.toString(), Toast.LENGTH_SHORT).show();
}
}
// else Init(context_S); // 若未初始化,則自動初始化請求允許擷取螢幕
return pic;
}
/** 擷取實時顯示的螢幕圖像,自動儲存 */
public static boolean GetScreen()
{
Bitmap pic = GetScreen_pic();
return ScreenTool.SaveScreen(pic);
// return ScreenTool.SaveScreen(context_S, pic);
}
private static int count = 5;
/** 截屏(延時毫秒、截屏次數) */
public static void GetScreen(final long DellayMillionSecond, final int times)
{
count = times;
final Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable r = new Runnable()
{
@Override
public void run()
{
if (count > 0)
{
// Toast.makeText(context_S, "GetScreen" + count, Toast.LENGTH_SHORT).show();
count--;
ScreenActivity.GetScreen();
mainHandler.postDelayed(this, DellayMillionSecond);
}
else mainHandler.removeCallbacks(this);
}
};
if (count > 0) mainHandler.postDelayed(r, DellayMillionSecond);
}
/** 螢幕投影請求回調 */
public static abstract class ScreenCallBack
{
/** 螢幕投影請求成功 */
public abstract void Success();
}
// ==========
// 錄屏
// ----------
/** 記錄最新的錄屏檔案儲存路徑 */
private static String VeidoPath = "";
/** 初始化MediaRecorder,設定錄屏相關參數 */
private static void InitRecorder(MediaProjection Projection)
{
if (Recorder == null)
{
Recorder = new MediaRecorder();
String path = ScreenTool.GetDir() + ScreenTool.NewVedioName(); // 生成視屏檔案路徑
VeidoPath = path;
File vedioFile = new File(path);
if (!vedioFile.getParentFile().exists()) vedioFile.getParentFile().mkdirs();
Recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
Recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
Recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
Recorder.setOutputFile(path);
Recorder.setVideoSize(W, H);
Recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
Recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
Recorder.setVideoEncodingBitRate(5 * W * H); // 根據螢幕分辨率變動
Recorder.setVideoFrameRate(20); // 20幀每秒
try
{
Recorder.prepare();
}
catch (IOException e)
{
e.printStackTrace();
VeidoPath = "";
}
Projection.createVirtualDisplay("MainScreen", W, H, D, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, Recorder.getSurface(), null, null);
}
}
private static boolean isRecordingVedio = false;
/** 開始錄屏 */
public static void GetVedio_Start()
{
if (!isInit) return;
if (!isRecordingVedio)
{
try
{
isRecordingVedio = true;
InitRecorder(Projection);
Recorder.start();
}
catch (Exception e)
{
isRecordingVedio = false;
VeidoPath = "";
e.printStackTrace();
}
}
}
/** 停止錄屏 */
public static String GetVedio_Stop()
{
if (isRecordingVedio)
{
Recorder.stop();
Recorder = null;
isRecordingVedio = false;
}
return VeidoPath;
}
/** 開始錄屏(延時delayMillis毫秒後,開始錄屏)*/
public static void GetVedio_Start(Long delayMillis)
{
Handler handler = new Handler(Looper.getMainLooper());
Runnable r = new Runnable()
{
@Override
public void run()
{
ScreenActivity.GetVedio_Start(); // 開始錄屏
}
};
handler.postDelayed(r, delayMillis);
}
/** 開始錄屏(延時delayMillis毫秒後,開始錄屏; 錄取recordMillions毫秒視屏後自動停止)*/
public static void GetVedio(Long delayMillis, final Long recordMillis)
{
final Handler handler = new Handler(Looper.getMainLooper());
final Runnable rs = new Runnable()
{
@Override
public void run()
{
ScreenActivity.GetVedio_Stop(); // 停止錄屏
}
};
Runnable r = new Runnable()
{
@Override
public void run()
{
ScreenActivity.GetVedio_Start(); // 開始錄屏
handler.postDelayed(rs, recordMillis); // 延時自動停止
}
};
handler.postDelayed(r, delayMillis);
}
}
package sc.tool.screenshot;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.Image;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.Toast;
public class ScreenTool
{
// new Handler(Looper.getMainLooper()).postDelayed(r, 5000);
/** Activity截取螢幕并自動儲存 */
public static boolean GetScreen(Activity activity)
{
Bitmap pic = GetScreen_Pic(activity);
String picPath = GetDir() + NewName();
boolean result = SavePic(pic, picPath);
// Toast.makeText(activity, "截屏已儲存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
return result;
}
/** 基于Activity的截屏(無需申請權限或root,僅能截取到目前Activity界面) */
private static Bitmap GetScreen_Pic(Activity activity)
{
View decorView = activity.getWindow().getDecorView(); // 擷取目前activity所在的最頂層的view--DecorView
// int statusBarHeight = GetStatusBarHeight(activity);
decorView.setDrawingCacheEnabled(true); // 啟用繪圖緩存
decorView.buildDrawingCache(); // 強制建構繪圖緩存(防止上面啟用繪圖緩存的操作失敗)
Bitmap bitmap = decorView.getDrawingCache(); // 擷取繪圖緩存中的 bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight()); // 建立副本作為傳回對象
// // 裁切圖像,去除狀态欄
// int newBmpHeight = bitmap.getHeight() - statusBarHeight; // 最終截取的圖檔的高度(取出狀态欄之後的高度)
// bitmap = Bitmap.createBitmap(bitmap, 0, statusBarHeight, bitmap.getWidth(), newBmpHeight);
// decorView.setDrawingCacheEnabled(false); // createBitmap完成之後一定要置為false,否則短時間内多次截圖時内容不會變化!
return bitmap;
}
/** 擷取Activity狀态欄高度 */
private static int GetStatusBarHeight(Activity activity)
{
View decorView = activity.getWindow().getDecorView(); // 擷取目前activity所在的最頂層的view--DecorView
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
return rect.top;
}
/** 擷取圖像儲存路徑 */
public static String GetDir()
{
String path = "sc/screeenShot/";
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) // 如果SD儲存設備可用
{
path = Environment.getExternalStorageDirectory().getPath() + File.separator + path;
File dir = new File(path);
if (!dir.exists()) dir.mkdirs(); // 建立目錄
}
return path;
}
private static int count = 0;
private static String preTime = "";
/** 生成圖像名稱 */
public static String NewName()
{
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String date = formatter.format(new Date());
DateFormat formatter2 = new SimpleDateFormat("HH.mm.ss");
String time = formatter2.format(new Date());
if (!preTime.equals(time))
{
count = 1;
preTime = time;
}
else count++;
String fileName = date + "_" + time + "_" + count + ".png";
return fileName;
}
/** 生成視屏檔案名稱 */
public static String NewVedioName()
{
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String date = formatter.format(new Date());
DateFormat formatter2 = new SimpleDateFormat("HH.mm.ss");
String time = formatter2.format(new Date());
String fileName = "vedio_" + date + "_" + time + ".mp4";
return fileName;
}
/** 儲存 bitmap到指定的檔案路徑 */
private static boolean SavePic(Bitmap bitmap, String picPath)
{
boolean saveSuccess = false;
if (bitmap != null)
{
try
{
File file = new File(picPath);
File dir = file.getParentFile();
if (!dir.exists()) dir.mkdirs(); // 建立目錄
if (!file.exists()) file.createNewFile(); // 建立新的檔案
FileOutputStream fos = new FileOutputStream(file);
saveSuccess = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); // 根據指定的格式、品質、輸出流 将bitmap儲存到本地,并傳回是否儲存成功
fos.flush();
fos.close(); // 關閉流防止溢出
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
return saveSuccess;
}
/** 儲存 bitmap,自動生成圖像名稱 */
public static boolean SaveScreen(final Context context, Bitmap pic)
{
if (pic == null) return false;
final String picPath = GetDir() + NewName();
boolean result = SavePic(pic, picPath);
// 顯示提示資訊
Runnable r = new Runnable()
{
@Override
public void run()
{
Toast.makeText(context, "截屏已儲存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
}
};
new Handler(Looper.getMainLooper()).post(r);
return result;
}
/** 儲存 bitmap,自動生成圖像名稱 */
public static boolean SaveScreen(Bitmap pic)
{
if (pic == null) return false;
String picPath = GetDir() + NewName();
boolean result = SavePic(pic, picPath);
// Toast.makeText(activity, "截屏已儲存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
return result;
}
/** Image轉化為Bitmap */
public static Bitmap ToBitmap(Image image)
{
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);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
image.close();
return bitmap;
}
// ----------
/** 系統指令截屏,需要root權限 */
public Bitmap captureScreenSystem(Activity activity)
{
// 擷取螢幕大小:
DisplayMetrics metrics = new DisplayMetrics();
WindowManager WM = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
Display display = WM.getDefaultDisplay();
display.getMetrics(metrics);
int height = metrics.heightPixels; // 螢幕高
int width = metrics.widthPixels; // 螢幕的寬
// 擷取顯示方式
int pixelformat = display.getPixelFormat();
PixelFormat localPixelFormat1 = new PixelFormat();
PixelFormat.getPixelFormatInfo(pixelformat, localPixelFormat1);
int deepth = localPixelFormat1.bytesPerPixel; // 位深
byte[] piex = new byte[height * width * deepth];
try
{
Runtime.getRuntime().exec(new String[] { "/system/bin/su", "-c", "chmod 777 /dev/graphics/fb0" });
}
catch (IOException e)
{
e.printStackTrace();
}
try
{
// 擷取fb0資料輸入流
InputStream stream = new FileInputStream(new File("/dev/graphics/fb0"));
DataInputStream dStream = new DataInputStream(stream);
dStream.readFully(piex);
}
catch (Exception e)
{
e.printStackTrace();
}
// 儲存圖檔
int[] colors = new int[height * width];
for (int m = 0; m < colors.length; m++)
{
int r = (piex[m * 4] & 0xFF);
int g = (piex[m * 4 + 1] & 0xFF);
int b = (piex[m * 4 + 2] & 0xFF);
int a = (piex[m * 4 + 3] & 0xFF);
colors[m] = (a << 24) + (r << 16) + (g << 8) + b;
}
// piex生成Bitmap
Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
return bitmap;
}
// ----------
/** 對WebView進行截圖 */
public static Bitmap captureWebView1(WebView webView)
{
Picture snapShot = webView.capturePicture();
Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
snapShot.draw(canvas);
return bmp;
}
// 判斷目前界面顯示的是哪個Activity
public static String getTopActivity(Context context)
{
ActivityManager am = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
// Log.d("ScreenTool", "包名:" + cn.getPackageName()); // 包名
Log.d("ScreenTool", "類名:" + cn.getClassName()); // 包名加類名
return cn.getClassName();
}
}
拍照、錄像