Android 截图最新方案
2023-02-26 本文已影响0人
Taurus_z
使用方式
import android.content.Context;
import android.content.Intent;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class ShotActivity extends AppCompatActivity {
private static final String TAG = ShotActivity.class.getSimpleName();
public static final int REQUEST_MEDIA_PROJECTION = 0x2304;
private Intent mMediaServiceIntent;
private String savedPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shot);
if (mMediaServiceIntent == null) {
mMediaServiceIntent = new Intent(this, MediaService.class);
}
startService(mMediaServiceIntent);
savedPath = this.getExternalFilesDir("screenshot").getAbsoluteFile() + "/" + System.currentTimeMillis() + ".png";
findViewById(R.id.shot).setOnClickListener(v -> {
requestScreenShotPermission();
});
}
public void requestScreenShotPermission() {
MediaProjectionManager mediaMgr = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(mediaMgr.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
}
@Override
protected void onActivityResult(int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_MEDIA_PROJECTION && resultCode == RESULT_OK && data != null) {
getWindow().getDecorView().postDelayed(() -> {
ShootUtil shootUtil = new ShootUtil(ShotActivity.this, resultCode, data);
shootUtil.startScreenShot(savedPath, new ShootUtil.OnShotListener() {
@Override
public void onFinish(String path) {
Log.i(TAG, "onFinish, path = " + path);
}
@Override
public void onError() {
Log.e(TAG, "onError, ");
}
});
}, 100L);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mMediaServiceIntent != null) {
stopService(mMediaServiceIntent);
mMediaServiceIntent = null;
}
}
}
ShootUtil.java 截图工具类
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
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.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
public class ShootUtil {
private static final String TAG = ShootUtil.class.getSimpleName();
public static boolean hasPermission;
private final SoftReference<Context> mRefContext;
private final ImageReader mImageReader;
private final MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private OnShotListener mOnShotListener;
private final int mHeight;
private final int mWidth;
private String mLocalUrl = "";
private String getSavedPath() {
if (TextUtils.isEmpty(mLocalUrl)) {
mLocalUrl = getContext().getExternalFilesDir("screenshot").getAbsoluteFile() + "/" + System.currentTimeMillis() + ".png";
}
return mLocalUrl;
}
public ShootUtil(Context context, int reqCode, Intent data) {
mRefContext = new SoftReference<>(context);
mMediaProjection = getMediaProjectionManager().getMediaProjection(reqCode, data);
WindowManager window = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display mDisplay = window.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
mDisplay.getRealMetrics(metrics);
mWidth = metrics.widthPixels;//size.x;
mHeight = metrics.heightPixels;//size.y;
mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 1);
}
private void virtualDisplay() {
mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror", mWidth, mHeight, Resources.getSystem().getDisplayMetrics().densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mImageReader.getSurface(), null, null);
}
public void startScreenShot(String savedPath, OnShotListener onShotListener) {
mLocalUrl = savedPath;
startScreenShot(onShotListener);
}
public void startScreenShot(OnShotListener onShotListener) {
hasPermission = true;
mOnShotListener = onShotListener;
virtualDisplay();
Handler handler = new Handler();
handler.postDelayed(() -> {
Image image = mImageReader.acquireLatestImage();
new SaveTask().doInBackground(image);
}, 300);
}
public class SaveTask extends AsyncTask<Image, Void, Bitmap> {
@Override
protected Bitmap doInBackground(Image... params) {
if (params == null || params.length < 1 || params[0] == null) {
return null;
}
Image image = params[0];
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();
File fileImage;
if (bitmap != null) {
try {
fileImage = new File(getSavedPath());
if (!fileImage.exists()) {
fileImage.createNewFile();
}
FileOutputStream out = new FileOutputStream(fileImage);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
if (mOnShotListener != null) mOnShotListener.onError();
release();
return null;
}
}
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
}
if (mMediaProjection != null) {
mMediaProjection.stop();
}
if (mOnShotListener != null) {
mOnShotListener.onFinish(getSavedPath());
}
return null;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
}
}
public void release() {
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
}
if (mMediaProjection != null) {
mMediaProjection.stop();
}
}
private MediaProjectionManager getMediaProjectionManager() {
return (MediaProjectionManager) getContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
}
private Context getContext() {
return mRefContext.get();
}
public interface OnShotListener {
void onFinish(String path);
void onError();
}
}
MediaService.java 前台服务
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import androidx.core.app.NotificationCompat;
public class MediaService extends Service {
private final String NOTIFICATION_CHANNEL_ID = "com.tencent.trtc.apiexample.MediaService";
private final String NOTIFICATION_CHANNEL_NAME = "com.tencent.trtc.apiexample.channel_name";
private final String NOTIFICATION_CHANNEL_DESC = "com.tencent.trtc.apiexample.channel_desc";
public MediaService() {
}
@Override
public void onCreate() {
super.onCreate();
startNotification();
}
public void startNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Intent notificationIntent = new Intent(this, MediaService.class);
PendingIntent pendingIntent;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
}
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground))
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Starting Service")
.setContentText("Starting monitoring service")
.setContentIntent(pendingIntent);
Notification notification = notificationBuilder.build();
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription(NOTIFICATION_CHANNEL_DESC);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
startForeground(1, notification); //必须使用此方法显示通知,不能使用notificationManager.notify,否则还是会报上面的错误
}
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
AndroidManifest.xml 文件添加 service
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true">
...
<service
android:name=".MediaService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="mediaProjection" />
</application>