You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 11(API30)下Service无法接收自定义广播的技术问询

Android 11下跨应用自定义广播通信问题

我正在用Kotlin开发适配Android 11(API级别30)的应用,现有两个需要互相通信的应用:Service应用(S,包名com.company.product.service)和GUI应用(G,包名com.company.product.app)。计划通过自定义广播实现通信:S发送广播,G接收后执行逻辑并回复广播。目前S发送的广播G能正常接收,但G回复的广播S收不到,双方实现机制一致,想问Service接收广播是否存在特殊限制?

S应用代码

ComConstants:

package com.company.product.service.com

class MediaConstants
{
    companion object
    {
        const val MY_ACTION = "com.company.product.MY_ACTION"
        const val MY_ACTION_RESPONSE = "com.company.product.MY_ACTION_RESPONSE"
    }
}

MainActivity:

package com.company.product.service

// imports

class MainActivity : AppCompatActivity()
{
    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)

        val i = Intent(this, MainService::class.java)
        startForegroundService(i)
        finish()
    }
}

MainService:

package com.company.product.service

// imports

class MainService : Service()
{
    ...
    private var myActionResponseReceiver = MyActionResponseReceiver(this)
    
    override fun onCreate()
    {
        super.onCreate()
        registerReceivers()
    }
    override fun onDestroy()
    {
        super.onDestroy()
        unregisterReceivers()
    }
    
    private fun registerReceivers()
    {
        registerReceiver(myActionResponseReceiver, IntentFilter(MY_ACTION_RESPONSE))
    }
    private fun unregisterReceivers()
    {
        unregisterReceiver(myActionResponseReceiver)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int
    {
        // 处理TCP连接的代码...
        sendBroadcast()
        // 其他代码
    }

    fun sendBroadcast()
    {
        val intent = Intent(MY_ACTION)
        intent.putExtra(/* 键值对 */)
        sendBroadcast(intent)
    }
}

MyActionResponseReceiver:

package com.company.product.service.receivers

// imports

class MyActionResponseReceiver(): BroadcastReceiver()
{
    override fun onReceive(context: Context?, intent: Intent?)
    {
        Log.i("MyTag", "收到广播: ${intent?.action}")
    }
}

G应用代码

ComConstants:

package com.company.product.app.com

class MediaConstants
{
    companion object
    {
        const val MY_ACTION = "com.company.product.MY_ACTION"
        const val MY_ACTION_RESPONSE = "com.company.product.MY_ACTION_RESPONSE"
    }
}

MainActivity:

package com.company.product.app

// imports

class MainActivity : AppCompatActivity()
{
    private var myActionReceiver = MyActionReceiver()

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        // 视图相关代码

        registerReceivers()
    }    
    override fun onDestroy()
    {
        super.onDestroy()
        unregisterReceivers()
    }
    
    private fun registerReceivers()
    {
        registerReceiver(myActionReceiver, IntentFilter(MY_ACTION))
    }
    private fun unregisterReceivers()
    {
        unregisterReceiver(myActionReceiver)
    }
}

MyActionReceiver:

package com.company.product.app.receivers

class MyActionReceiver(): BroadcastReceiver()
{
    override fun onReceive(context: Context?, intent: Intent?)
    {
        Log.i("MyTag", "收到广播: ${intent?.action}")
        // 业务逻辑代码
        sendResponseBroadcast()
    }

    fun sendResponseBroadcast()
    {
        val intent = Intent(MY_ACTION_RESPONSE)
        intent.setComponent(ComponentName("com.company.product.app", "com.company.product.service/.receivers.MyActionResponseReceiver"))
        intent.putExtra(/* 键值对 */)
        sendBroadcast(intent)
    }
}

问题原因及解决方案

1. ComponentName参数完全错误

G应用发送回复广播时,setComponent的两个参数都写错了:

  • 第一个参数是目标应用包名,必须填S应用的com.company.product.service,而非G自身的包名
  • 第二个参数是接收器的全类名,正确格式是com.company.product.service.receivers.MyActionResponseReceiver,不需要加/.前缀

同时原代码里调用sendBroadcast()没有传入Context,会导致运行异常,需要用onReceive方法提供的上下文来发送。修正后的代码:

fun sendResponseBroadcast(context: Context?) {
    val intent = Intent(MY_ACTION_RESPONSE)
    val component = ComponentName(
        "com.company.product.service",
        "com.company.product.service.receivers.MyActionResponseReceiver"
    )
    intent.component = component
    intent.putExtra(/* 键值对 */)
    context?.sendBroadcast(intent)
}

// 在onReceive中调用
override fun onReceive(context: Context?, intent: Intent?) {
    Log.i("MyTag", "收到广播: ${intent?.action}")
    // 业务逻辑代码
    sendResponseBroadcast(context)
}

2. Android 11的隐式广播限制

API 30开始,系统对后台应用(包括后台Service)接收隐式广播做了严格限制,即使是显式广播也需要注意两点:

  • 确保S应用的Service是前台服务:你已经调用了startForegroundService,但必须在Service的onCreate方法中调用startForeground()展示前台通知,否则Service会被系统强制杀死,接收器自然收不到消息。
  • 若使用隐式广播,需要通过自定义权限保护:
    1. 在S应用的AndroidManifest.xml中声明签名级权限:
      <permission
          android:name="com.company.product.permission.MY_BROADCAST"
          android:protectionLevel="signature" />
      
    2. 两个应用都在Manifest中申请该权限:
      <uses-permission android:name="com.company.product.permission.MY_BROADCAST" />
      
    3. 发送广播时指定权限:
      context?.sendBroadcast(intent, "com.company.product.permission.MY_BROADCAST")
      
    4. 注册接收器时绑定权限:
      registerReceiver(myActionResponseReceiver, IntentFilter(MY_ACTION_RESPONSE), "com.company.product.permission.MY_BROADCAST", null)
      

3. 确认接收器注册状态

在S应用的registerReceivers和unregisterReceivers方法中添加日志,确认接收器是否在Service启动时正常注册,且未被提前注销。


内容的提问来源于stack exchange,提问作者Jon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:34:59