Android 10:android:foregroundServiceType =“ mediaProjection”无法与服务一起使用

如何解决Android 10:android:foregroundServiceType =“ mediaProjection”无法与服务一起使用

媒体投射需要ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION类型的前台服务

我正在尝试使用 MediaProjection API 捕获屏幕,但是我的应用不断崩溃。我尝试过并给出此错误

   java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION

我的服务代码

  class RecordService : Service() {
        private var mServiceHandler: ServiceHandler? = null
        private var mMediaProjection: MediaProjection? = null
        private var mVirtualdisplay: Virtualdisplay? = null
        private var mMediaRecorder: MediaRecorder? = null
        private var resultCode = 0
        private var data: Intent? = null
        private var mScreenStateReceiver: broadcastReceiver? = null
    var isInitialized=false
    
        private inner class ServiceHandler(looper: Looper?) : Handler(looper) {
            override fun handleMessage(msg: Message?) {
                if (resultCode == RESULT_OK) {
                    startRecording(resultCode,data)
                } else {
                }
            }
        }
    
        override fun onCreate() {

            // when the main app is being closed
            val notificationIntent = Intent(this,RecordService::class.java)
            val pendingIntent = PendingIntent.getActivity(this,notificationIntent,0)
            val notification: Notification = Notification.Builder(this)
                .setContentTitle("DataRecorder")
                .setContentText("Your screen is being recorded and saved to your phone.")
                .setSmallIcon(R.drawable.ic_dialog_alert)
                .setContentIntent(pendingIntent)
                .setTicker("Tickertext")
                .build()
            isInitialized=true
            startForeground(ONGOING_NOTIFICATION_ID,notification)
  
            mScreenStateReceiver = MybroadcastReceiver()
            val screenStateFilter = IntentFilter()
            screenStateFilter.addAction(Intent.ACTION_SCREEN_ON)
            screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF)
            screenStateFilter.addAction(Intent.ACTION_CONfigURATION_CHANGED)
            registerReceiver(mScreenStateReceiver,screenStateFilter)
            val thread = HandlerThread(
                "ServiceStartArguments",THREAD_PRIORITY_BACKGROUND
            )
            thread.start()
            val mServiceLooper = thread.looper
            mServiceHandler = ServiceHandler(mServiceLooper)
        }
    
        override fun onStartCommand(intent: Intent,flags: Int,startId: Int): Int {
            Toast.makeText(this,"Starting recording service",Toast.LENGTH_SHORT).show()
            resultCode = intent.getIntExtra(EXTRA_RESULT_CODE,0)
            data = intent.getParcelableExtra(EXTRA_DATA)
            check(!(resultCode == 0 || data == null)) { "Result code or data missing." }
            val msg = mServiceHandler!!.obtainMessage()
            msg.arg1 = startId
            mServiceHandler!!.sendMessage(msg)
            return START_REDELIVER_INTENT
        }
    
        private fun startRecording(resultCode: Int,data: Intent?) {
            val mProjectionManager =
                applicationContext.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as mediaprojectionmanager
            mMediaRecorder = MediaRecorder()
            val metrics = displayMetrics()
            val wm =
                applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            wm.defaultdisplay.getRealMetrics(metrics)
            val mScreenDensity = metrics.densityDpi
            val displayWidth = metrics.widthPixels
            val displayHeight = metrics.heightPixels
            mMediaRecorder!!.setVideoSource(MediaRecorder.VideoSource.SURFACE)
            mMediaRecorder!!.setoutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            mMediaRecorder!!.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            mMediaRecorder!!.setVideoEncodingBitRate(8 * 1000 * 1000)
            mMediaRecorder!!.setVideoFrameRate(15)
            mMediaRecorder!!.setVideoSize(displayWidth,displayHeight)
            val videoDir =
                Environment.getExternalStoragePublicDirectory(DIRECTORY_MOVIES)
                    .absolutePath
            val timestamp = System.currentTimeMillis()
            var orientation = "portrait"
            if (displayWidth > displayHeight) {
                orientation = "landscape"
            }
            val filePathAndName =
                videoDir + "/time_" + timestamp.toString() + "_mode_" + orientation + ".mp4"
            mMediaRecorder!!.setoutputFile(filePathAndName)
            try {
                mMediaRecorder!!.prepare()
            } catch (e: IllegalStateException) {
                e.printstacktrace()
            } catch (e: IOException) {
                e.printstacktrace()
            }
            if(isInitialized){
                mMediaProjection = mProjectionManager.getMediaProjection(resultCode,data!!)
                val surface: Surface = mMediaRecorder!!.surface
                mVirtualdisplay = mMediaProjection!!.createVirtualdisplay(
                    "MainActivity",displayWidth,displayHeight,mScreenDensity,VIRTUAL_disPLAY_FLAG_PRESENTATION,surface,null,null
                )
                mMediaRecorder!!.start()
                Log.v(TAG,"Started recording")
    
            }
           }
    
        companion object {
            private const val TAG = "RECORDERSERVICE"
            private const val EXTRA_RESULT_CODE = "resultcode"
            private const val EXTRA_DATA = "data"
            private const val ONGOING_NOTIFICATION_ID = 23
  
        }
    }

我也确实在清单中添加android:foregroundServiceType="mediaProjection",但是它不起作用。我尝试了其他类似的任务,但问题尚未解决。谢谢

解决方法

您是否将此添加到您的应用清单中?

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
,

终于拿到了钥匙: 您必须首先像下面一样在 onStartCommand 中创建 NotificationChannel ,否则您将 得到“FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION 错误”。

@Override
public int onStartCommand(Intent intent,int flags,int startId) {
    LogUtil.d(TAG," onStartCommand intent = " + intent);
    createNotificationChannel();
    
    //do MediaProjection things that you want
    return START_NOT_STICKY;
}


private void createNotificationChannel() {
    Notification.Builder builder = new Notification.Builder(this.getApplicationContext()); //获取一个Notification构造器
    Intent nfIntent = new Intent(this,MainActivity.class); //点击后跳转的界面,可以设置跳转数据

    builder.setContentIntent(PendingIntent.getActivity(this,nfIntent,0)) // 设置PendingIntent
        .setLargeIcon(BitmapFactory.decodeResource(this.getResources(),R.mipmap.ic_launcher)) // 设置下拉列表中的图标(大图标)
        //.setContentTitle("SMI InstantView") // 设置下拉列表里的标题
        .setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
        .setContentText("is running......") // 设置上下文内容
        .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间

    /*以下是对Android 8.0的适配*/
    //普通notification适配
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        builder.setChannelId("notification_id");
    }
    //前台服务notification适配
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        NotificationChannel channel = new NotificationChannel("notification_id","notification_name",NotificationManager.IMPORTANCE_LOW);
        notificationManager.createNotificationChannel(channel);
    }

    Notification notification = builder.build(); // 获取构建好的Notification
    notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
    startForeground(110,notification);
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?