Android 10 在使用MediaProjectionManager录音的时候报错:
java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
错误详细信息如下,看了网上很多相关的解决介绍,但是都没有太多的用处要么就是不是太清楚。这里说下解决的几个关键点,希望对大家有所帮助
2021-09-25 20:17:32.007 4032-4032/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.demo.audiocapture, PID: 4032
java.lang.RuntimeException: Unable to start service com.demo.audiocapture.AudioCaptureService@403e26c with Intent {
cmp=com.demo.audiocapture/.AudioCaptureService (has extras) }: java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4971)
at android.app.ActivityThread.access$3300(ActivityThread.java:260)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2486)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
Caused by: java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
at android.os.Parcel.createException(Parcel.java:2090)
at android.os.Parcel.readException(Parcel.java:2058)
at android.os.Parcel.readException(Parcel.java:2006)
at android.media.projection.IMediaProjection$Stub$Proxy.start(IMediaProjection.java:231)
at android.media.projection.MediaProjection.<init>(MediaProjection.java:75)
at android.media.projection.MediaProjectionManager.getMediaProjection(MediaProjectionManager.java:104)
at com.demo.audiocapture.AudioCaptureService.onStartCommand(AudioCaptureService.java:86)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4951)
at android.app.ActivityThread.access$3300(ActivityThread.java:260)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2486)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8668)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.media.projection.MediaProjectionManagerService$MediaProjection.start(libmapleservices.so:16625028)
at android.media.projection.IMediaProjection$Stub.onTransact(libmapleframework.so:26979796)
at android.os.Binder.execTransactInternal(libmapleframework.so:6246476)
at android.os.Binder.execTransact(libmapleframework.so:6248272)
callee: null 2075/4123
尝试了一下,最终解决。关键点如下(录音的代码不再这里黏贴了): 关键点1我在网上没找到有说明的,或者介绍的也不太清楚,关键点2网上有介绍说明
关键点1:关于通知的调用时机及调用方法
1> NotificationManager 显示通知时,必须要在getMediaProjection方法之前调用
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@RequiresApi(api = Build.VERSION_CODES.Q)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
resultCode = intent.getIntExtra("resultCode", -1);
resultData = intent.getParcelableExtra("data");
Log.i(TAG, "onStartCommand: " + resultCode);
Log.i(TAG, "onStartCommand: " + resultData);
notification();//通知显示可以写到onCreate中。不管是写到onCreate里面还是onStartCommand中,都要写到getMediaProjection方法调用之前
mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, resultData);//必须在通知显示之后调用
Log.i(TAG, "onStartCommand: " + mediaProjection);
AudioPlaybackCaptureConfiguration.Builder builder = new AudioPlaybackCaptureConfiguration.Builder(mediaProjection);
builder.addMatchingUsage(AudioAttributes.USAGE_MEDIA);//多媒体
builder.addMatchingUsage(AudioAttributes.USAGE_ALARM);//闹铃
builder.addMatchingUsage(AudioAttributes.USAGE_GAME);//游戏
audioPlaybackCaptureConfiguration = builder.build();
generateAudioRecord();
return super.onStartCommand(intent, flags, startId);
}
2> 必须使用 startForeground(NOTIFICATION_ID, notification) 显示通知,不能使用notificationManager.notify(NOTIFICATION_ID, notification);
public void notification() {
Log.i(TAG, "notification: " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//Call Start foreground with notification
Intent notificationIntent = new Intent(this, AudioCaptureService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
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")
.setTicker(NOTIFICATION_TICKER)
.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);
//notificationManager.notify(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID, notification); //必须使用此方法显示通知,不能使用notificationManager.notify,否则还是会报上面的错误
}
}
关键点2 权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
关键点3 service配置
清单文件(即AndroidManifest.xml)中配置服务的时候,需要加上 android:foregroundServiceType=“mediaProjection”
<service
android:name=".AudioCaptureService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="mediaProjection"
/>
参考
https://stackoverflow.com/questions/62004735/media-projections-require-a-foreground-service-of-type-serviceinfo-foreground-se
Android notification 适配不同版本
https://developer.android.google.cn/reference/kotlin/android/media/AudioPlaybackCaptureConfiguration
Android require a foreground service of type ServiceInfo.FOREGROUND_SERVICE
MediaProjections in Android Q(Media projections require a foreground service)
AudioPlaybackCapture(Android 10)无法正常工作并录制空声音