Android开发

Android实时获取屏幕流
贵鬼2024-10-16发布
87 0

在AndroidManifest.xml文件中添加权限

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

在Activity中请求屏幕录制权限

public void buildMediaProjection(Activity activity){
  mediaProjectionManager = (MediaProjectionManager)activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);    
  Intent intent = mediaProjectionManager.createScreenCaptureIntent();    
  activity.startActivityForResult(intent, REQUEST_MEDIA_PROJECTION);
}

在Activity的onActivityResult方法中启动Server

public boolean onActivityResult(Context context, int resultCode, Intent data){
  Log.e(TAG,"=====onActivityResult=====");    
  Intent screenshotService = new Intent(context, ScreenshotService.class);    
  screenshotService.putExtra("resultCode",resultCode);    
  screenshotService.putExtra("data",data);    
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    Log.e(TAG,"以前端服务方式启动,startForegroundService");        
    context.startForegroundService(screenshotService);   
  }else{
    context.startService(screenshotService);    
  }
  return true;
}

ScreenshotService类

public class ScreenshotService extends Service {

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e(TAG,"=====onStartCommand=====");    
    //触发通知    
    createNotification();  
  
    try {
        int resultCode = intent.getIntExtra("resultCode",-1);        
        Intent data = intent.getParcelableExtra("data");

        //mediaProjectionManager从Activity中获取的,可以使用静态变量保存        
        MediaProjection mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
        
        WindowManager windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);                
        this.screenshotServer(mediaProjection,windowManager);    
    }catch (Exception e){
        LogTools.error(TAG,e.getMessage(),e);    
    }
    return super.onStartCommand(intent, flags, startId);
  }

  /**
  * 持续截图
  */
  public void screenshotServer(MediaProjection mediaProjection, WindowManager windowManager){
    DisplayMetrics displayMetrics = new DisplayMetrics();    
    windowManager.getDefaultDisplay().getMetrics(displayMetrics);    
    int dpi = displayMetrics.densityDpi;    
    Point point = new Point();    
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        windowManager.getDefaultDisplay().getRealSize(point);    
    }else{
        windowManager.getDefaultDisplay().getSize(point);    
    }

    int width = point.x;    
    int height = point.y;    
    LogTools.info(TAG,"压缩前:width:" + width + ",height:" + height + ",dpi:" + dpi);    
    width = (int)(width * 0.5);    
    height = (int)(height * 0.5);    
    dpi = (int)(dpi * 0.5);
    
    //创建一个虚拟显示对象
    ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);    
    VirtualDisplay virtualDisplay = mediaProjection.createVirtualDisplay("screen",width,height,dpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,        imageReader.getSurface(),null,null);    
    this.isRun.set(true);  
  
    new Thread(){
      public void run(){
        #连续获取屏幕截图
        while (isRun.get()) {
          Image image = null;                
          ByteArrayOutputStream byteArrayOutputStream = null;                
            try {
              image = imageReader.acquireLatestImage();                    
              if (image != null) {
                // 将 Image 转化为 Bitmap 对象                        
                Image.Plane[] planes = image.getPlanes();                         
                int width = image.getWidth();                        
                int height = image.getHeight();                        
                ByteBuffer buffer = planes[0].getBuffer();                        
                int pixelStride = planes[0].getPixelStride();                        
                int rowStride = planes[0].getRowStride();                        
                int padding = rowStride - pixelStride * width;                        
                Bitmap bitmap = Bitmap.createBitmap(width + padding / pixelStride, height, Bitmap.Config.ARGB_8888);                                        bitmap.copyPixelsFromBuffer(buffer);                        
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); 
                       
                byteArrayOutputStream = new ByteArrayOutputStream();                        
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);                        
                byte[] byteArray = byteArrayOutputStream.toByteArray();                        
                LogTools.info(TAG, "录屏图片大小:" + (byteArray.length / 1024) + "KB");                        
                String base64Img = java.util.Base64.getEncoder().encodeToString(byteArray);   
                     
                //保存图片base64Img                       
                
                byteArrayOutputStream.close();                        
                bitmap.recycle();                        
                image.close();                    
            }

            Thread.sleep(1000);                
          }catch (Exception e){
            LogTools.error(TAG,e.getMessage(),e);                
          }
       }

       try {
         imageReader.close();            
       }catch (Exception e){}

       try{
         virtualDisplay.release();            
       }catch (Exception e){}

       try {
         mediaProjection.stop();            
       }catch (Exception e){}

       LogTools.info(TAG,"录屏线程结束");        
      }
    }.start();
  }

  /**
   * 发送通知
   */
  private void createNotification(){
    Notification.Builder builder = new Notification.Builder(this.getApplicationContext());
    builder.setContentText("录屏服务");
    builder.setWhen(System.currentTimeMillis());

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        builder.setChannelId(channelId);
        NotificationManager notificationManager = (NotificationManager)this.getSystemService(NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel(channelId,channelId,NotificationManager.IMPORTANCE_LOW);
        notificationManager.createNotificationChannel(channel);
    }

    Notification notification = builder.build();
    notification.defaults = Notification.DEFAULT_SOUND;
    startForeground(notificationId,notification);
  }
}