Android 截屏服务

Posted 泸沽烟火

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 截屏服务相关的知识,希望对你有一定的参考价值。

package com.xxxx.xxxx.xxxx.xxxx.xxxx;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
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.Build;
import android.os.IBinder;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.view.WindowManager;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.xxxx.xxxx.CourseApplication;
import com.xxxx.xxxx.R;
import com.xxxx.xxxx.utils.RxJavaUtil;

import java.nio.ByteBuffer;

/**
 * 截屏
 */
public class ServicesScreenCapture extends Service 
    private static final int NOTIFICATION_ID = 1111;

    public static final String ON_START = "onStartScreenCapture";
    public static final String ON_FINISH = "onFinishScreenCapture";
    public static final String ON_ERROR = "onErrorScreenCapture";

    private int resultCode;
    private Intent resultData;
    private MediaProjectionManager mediaProjectionManager;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) 
        return null;
    

    @Override
    public void onCreate() 
        super.onCreate();
        sendBroadcast(new Intent(ON_START));
        Notification notification = createForegroundNotification();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) 
            startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
         else 
            startForeground(NOTIFICATION_ID, notification);
        
    

    @Override
    public void onDestroy() 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) 
            stopForeground(STOP_FOREGROUND_REMOVE);
         else 
            stopForeground(true);
        
        super.onDestroy();
    

    @SuppressLint("WrongConstant", "RestrictedApi")
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        mediaProjectionManager = (MediaProjectionManager) CourseApplication.CONTEXT.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        resultCode = intent.getIntExtra("code", -1);
        resultData = intent.getParcelableExtra("data");

        RxJavaUtil.runTimer(500, new RxJavaUtil.OnRxRunTimerListener() 
            @Override
            public void onStart() 
            

            @Override
            public void onExecute(Long l) 
            

            @Override
            public void onFinish() 
                MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);

                DisplayMetrics displayMetrics = new DisplayMetrics();
                WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
                windowManager.getDefaultDisplay().getMetrics(displayMetrics);
                int width = displayMetrics.widthPixels;
                int height = displayMetrics.heightPixels;

                ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);

                VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay("screen-mirror",
                        width, height,
                        displayMetrics.densityDpi,
                        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                        imageReader.getSurface(), null, null);

                imageReader.setOnImageAvailableListener(reader -> 
                    Image image = reader.acquireLatestImage();
                    final Image.Plane[] planes = image.getPlanes();
                    final ByteBuffer buffer = planes[0].getBuffer();
                    int w = image.getWidth();
                    int h = image.getHeight();
                    int pixelStride = planes[0].getPixelStride();
                    int rowStride = planes[0].getRowStride();
                    int rowPadding = rowStride - pixelStride * w;
                    Bitmap bitmap = Bitmap.createBitmap(w + rowPadding / pixelStride, h, Bitmap.Config.ARGB_8888);
                    bitmap.copyPixelsFromBuffer(buffer);
                    bitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), false);
                    if (bitmap != null) 
                        MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, System.currentTimeMillis() + "", "welearn");
                        bitmap.recycle();
                    
                    imageReader.close();
                    mediaProjection.stop();
                    virtualDisplay.release();
                    sendBroadcast(new Intent(ON_FINISH));
                    stopSelf();
                , null);
            

            @Override
            public void onError(Throwable e) 
                sendBroadcast(new Intent(ON_ERROR));
                stopSelf();
            
        );

        return super.onStartCommand(intent, flags, startId);
    

    private Notification createForegroundNotification() 
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 唯一的通知通道的id.
        String notificationChannelId = "notification_channel_id_screen_capture";

        // Android8.0以上的系统,新建消息通道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
            //用户可见的通道名称
            String channelName = "ScreenCapture";
            //通道的重要程度
            int importance = NotificationManager.IMPORTANCE_NONE;
            NotificationChannel notificationChannel = new NotificationChannel(notificationChannelId, channelName, importance);
            notificationChannel.setDescription("截屏");
            notificationChannel.enableLights(false);
            notificationChannel.enableVibration(false);
            if (notificationManager != null) 
                notificationManager.createNotificationChannel(notificationChannel);
            
        

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, notificationChannelId);
        //通知小图标
        builder.setSmallIcon(R.drawable.icon);
        //通知标题
        builder.setContentTitle("截屏");
        //通知内容
        builder.setContentText("截屏");
        //设定通知显示的时间
        builder.setWhen(System.currentTimeMillis());
        //设定启动的内容
//        Intent activityIntent = new Intent(this, NotificationActivity.class);
//        PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//        builder.setContentIntent(pendingIntent);

        //创建通知并返回
        return builder.build();
    

Manifest添加

        <service
            android:name=".activity.classroomactivities.signin.ServicesScreenCapture"
            android:enabled="true"
            android:foregroundServiceType="mediaProjection" />

注册调用

一。
if (screenCaptureReceiver == null) 
    screenCaptureReceiver = new ScreenCaptureReceiver(activity);
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(ServicesScreenCapture.ON_START);
    intentFilter.addAction(ServicesScreenCapture.ON_FINISH);
    intentFilter.addAction(ServicesScreenCapture.ON_ERROR);
    activity.registerReceiver(screenCaptureReceiver, intentFilter);


Intent intent = ((MediaProjectionManager) activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE)).createScreenCaptureIntent();
activity.startActivityForResult(intent, SignInActivity.REQUEST_CODE_SCREEN_CAPTURE);

二。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) 
    if (requestCode == SignInActivity.REQUEST_CODE_SCREEN_CAPTURE) 
        //开启截屏服务
        Intent service = new Intent(activity, ServicesScreenCapture.class);
        service.putExtra("code", resultCode);
        service.putExtra("data", data);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
            activity.startForegroundService(service);
         else 
            activity.startService(service);
        
    

广播监听

    private static class ScreenCaptureReceiver extends BroadcastReceiver 
        private final WeakReference<SignInActivity> activity;

        public ScreenCaptureReceiver(SignInActivity activity) 
            this.activity = new WeakReference<>(activity);
        

        @Override
        public void onReceive(Context context, Intent intent) 
            SignInActivity activity = this.activity.get();
            if (activity != null) 
                switch (intent.getAction()) 
                    case ServicesScreenCapture.ON_START:
                        break;
                    case ServicesScreenCapture.ON_FINISH:
                        Common.showShortToast(activity, "截屏完成,请在相册中查看");
                        break;
                    case ServicesScreenCapture.ON_ERROR:
                        Common.showShortToast(activity, "截屏失败");
                        break;
                
            
        
    

 

以上是关于Android 截屏服务的主要内容,如果未能解决你的问题,请参考以下文章

Android 截屏服务

Android 截屏服务

Android截屏、录屏工具

从surfaceflinger历史变更谈截屏

android中怎么用代码实现截屏

Android 截屏方式