赞
踩
安卓截屏需要一个前台服务(需要权限)
开启前台服务需要显示一个通知(需要设置标题栏,文字等)
1.开启相关权限:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name=".service.ScreenRecorderService"
android:exported="false"
android:foregroundServiceType="mediaProjection"
tools:ignore="Instantiatable" />
2.在Activity里判断权限&&启动服务并且使用MediaProjectionManager开启截屏:
3.在onActivityResult()里面对图像数据进行处理:
相关代码如下:
Activity: //启动MediaService服务
fun StartMediaService() { if (isstartservice) { startService(Intent(this, MediaService::class.java)) isstartservice = false } } val REQUEST_MEDIA_PROJECTION = 10001 private var mediaProjectionManager: MediaProjectionManager? = null // 申请截屏权限 private fun getScreenShotPower() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager if (mediaProjectionManager != null) { val intent = mediaProjectionManager!!.createScreenCaptureIntent() startActivityForResult(intent, REQUEST_MEDIA_PROJECTION) } } } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) override fun onActivityResult(requestCode: Int, resultCode: Int, @Nullable data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_MEDIA_PROJECTION && data != null) { // val mediaProjection = mediaProjectionManager!!.getMediaProjection(RESULT_OK, data) // val bitmap = screenShot(mediaProjection) // val bs = getBitmapByte(bitmap) // //对图片进行处理逻辑 例如可以保存本地、进行图片分享等等操作 // Log.e("WWW", "EEE" + bitmap) // binding.img.setImageBitmap(bitmap) } } 处理图片: @RequiresApi(api = Build.VERSION_CODES.KITKAT) fun screenShot(mediaProjection: MediaProjection): Bitmap? { val wm1 = this.windowManager val width = wm1.defaultDisplay.width val height = wm1.defaultDisplay.height Objects.requireNonNull(mediaProjection) @SuppressLint("WrongConstant") val imageReader: ImageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 60) var virtualDisplay: VirtualDisplay? = null if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { virtualDisplay = mediaProjection.createVirtualDisplay( "screen", width, height, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null ) } SystemClock.sleep(1000) //取最新的图片 val image: Image = imageReader.acquireLatestImage() // Image image = imageReader.acquireNextImage(); //释放 virtualDisplay,不释放会报错 virtualDisplay!!.release() return image2Bitmap(image) } //将Image转为Bitmap @RequiresApi(api = Build.VERSION_CODES.KITKAT) fun image2Bitmap(image: Image?): Bitmap? { if (image == null) { println("image 为空") return null } val width: Int = image.getWidth() val height: Int = image.getHeight() val planes: Array<Image.Plane> = image.planes val buffer: ByteBuffer = planes[0].buffer val pixelStride: Int = planes[0].pixelStride val rowStride: Int = planes[0].rowStride val rowPadding = rowStride - pixelStride * width val bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888) bitmap.copyPixelsFromBuffer(buffer) //截取图片 // Bitmap cutBitmap = Bitmap.createBitmap(bitmap,0,0,width/2,height/2); //压缩图片 // Matrix matrix = new Matrix(); // matrix.setScale(0.5F, 0.5F); // System.out.println(bitmap.isMutable()); // bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false); image.close() return bitmap } // 位图转 Byte private fun getBitmapByte(bitmap: Bitmap?): ByteArray { val out = ByteArrayOutputStream() // 参数1转换类型,参数2压缩质量,参数3字节流资源 bitmap!!.compress(Bitmap.CompressFormat.PNG, 100, out) try { out.flush() out.close() } catch (e: IOException) { e.printStackTrace() } return out.toByteArray() } Service: package com.allynav.iefa.service import android.R import android.app.* 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 /** *@author zd *@time 2023/4/10 9:35 *@description : * **/ class MediaService : Service() { private val NOTIFICATION_CHANNEL_ID = "com.tencent.trtc.apiexample.MediaService" private val NOTIFICATION_CHANNEL_NAME = "com.tencent.trtc.apiexample.channel_name" private val NOTIFICATION_CHANNEL_DESC = "com.tencent.trtc.apiexample.channel_desc" override fun onCreate() { super.onCreate() startNotification() } fun startNotification() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //Call Start foreground with notification val notificationIntent = Intent(this, MediaService::class.java) val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0) val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) .setLargeIcon( BitmapFactory.decodeResource( getResources(), R.drawable.alert_dark_frame ) ) .setSmallIcon(R.drawable.alert_dark_frame) .setContentTitle("Starting Service") .setContentText("Starting monitoring service") .setContentIntent(pendingIntent) val notification: Notification = notificationBuilder.build() val channel = NotificationChannel( NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT ) channel.description = NOTIFICATION_CHANNEL_DESC val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.createNotificationChannel(channel) startForeground( 1, notification ) //必须使用此方法显示通知,不能使用notificationManager.notify,否则还是会报上面的错误 } } override fun onBind(intent: Intent?): IBinder { throw UnsupportedOperationException("Not yet implemented") } }
使用完毕释放资源,关闭服务!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。