任何人都可以提供一个将生成 ForegroundServiceStartNotAllowedException 的示例吗?

use*_*721 5 android

Android 12 添加了对从某些后台任务启动的 ForegroundService 的限制。我有一个使用多个 ForegroundServices 的应用程序,其中一些不属于例外情况。但是,当构建在 Android 12 Beta 4 设备上运行时,针对 API 31 的构建并未遇到任何问题或 ForegroundServiceStartNotAllowedException。

任何人都可以提供一个示例来解决在构建 API 31 目标后出现的问题吗?

Ben*_*nyP 1

在 gradle 中:

compileSdkVersion 31
buildToolsVersion "31.0.0"
targetSdkVersion 31
Run Code Online (Sandbox Code Playgroud)

在清单中:

 <service android:name=".MyForegroundService"
          android:exported="false"/>
       
<service android:name=".MyService"
         android:exported="false"/>

<receiver android:name=".MyBroadcastReceiver"
          android:exported="true">
              <intent-filter>
                  <action android:name="com.sdk12.foreground.ACTION"/>
              </intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)

接收者:

class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("tag", "onReceive()");
        val myServiceIntent = Intent(context, MyForegroundService::class.java)
            Handler(Looper.getMainLooper()).postDelayed({ 
                try {
                    ContextCompat.startForegroundService(context,myServiceIntent)
                } catch (ex : ForegroundServiceStartNotAllowedException){
                    Log.d("tag","ForegroundServiceStartNotAllowedException")
                }
            }, 5000)
        }
}
Run Code Online (Sandbox Code Playgroud)

前台服务:

class MyForegroundService : Service() {
    private lateinit var br: BroadcastReceiver

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        br = MyBroadcastReceiver()
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply {
            addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED)
        }
        registerReceiver(br, filter)

    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        val channelId = createNotificationChannel("channel1","My Background Service")

        val pendingIntent: PendingIntent =
            Intent(this, MainActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE)
            }

        val notificationBuilder = Notification.Builder(this, channelId )
        val notification = notificationBuilder.setOngoing(true)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("title")
            .setContentText("contentText")
            .setCategory(Notification.CATEGORY_SERVICE)
            .setContentIntent(pendingIntent)
            .setForegroundServiceBehavior(Notification.FOREGROUND_SERVICE_IMMEDIATE)
            .build()

        startForeground(1, notification)

        return START_STICKY

    }

    override fun onDestroy() {
        unregisterReceiver(br)
        super.onDestroy()
    }

    private fun createNotificationChannel(channelId: String, channelName: String): String {
        val chan = NotificationChannel(
            "channel1",
            channelName, NotificationManager.IMPORTANCE_NONE
        )
        chan.lightColor = Color.BLUE
        chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
        chan.importance = NotificationManager.IMPORTANCE_HIGH
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(chan)
        return channelId
    }
}
Run Code Online (Sandbox Code Playgroud)

我的服务:

class MyService : Service() {
    private lateinit var br: BroadcastReceiver

    override fun onBind(intent: Intent): IBinder? {
        return null
    }

    override fun onCreate() {
        super.onCreate()
        br = MyBroadcastReceiver()
        val filter = IntentFilter("com.sdk12.foreground.ACTION")
        registerReceiver(br, filter)

    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        return START_STICKY
    }

    override fun onDestroy() {
        unregisterReceiver(br)
        super.onDestroy()
    }
}
Run Code Online (Sandbox Code Playgroud)

触发服务:

startService(Intent(this, MyService::class.java))
Run Code Online (Sandbox Code Playgroud)

将您的应用程序发送到后台并从 adb 调用:

adb shell am broadcast -a com.sdk12.foreground.ACTION -f 0x01000000
Run Code Online (Sandbox Code Playgroud)

这将确保您处于后台可能有更简单的方法,但我发现这是最容易理解的