安卓Handler+Messenger实现跨应用通讯

一、服务端的实现

  1. 创建服务端的Service。

    class MessengerService : Service() {
    companion object {
    const val MSG_SAY_HELLO = 1
    const val MSG_GET_DATA = 2
    const val MSG_SEND_DATA = 3
    }

    复制代码
     private val mMessenger = Messenger(IncomingHandler())
    
     inner class IncomingHandler : Handler(Looper.getMainLooper()) {
         override fun handleMessage(msg: Message) {
             when (msg.what) {
                 MSG_SAY_HELLO -> {
                     // 回复消息给客户端
                     val text = msg.data?.getString("text")
                     Log.d("MessengerService", "收到客户端消息: ${text}")
                     val reply = Message.obtain(null, MSG_SAY_HELLO).apply {
                         data = Bundle().apply { putString("reply", "服务端已收到: $text") }
                     }
                     msg.replyTo?.send(reply)
                 }
                 MSG_GET_DATA -> {
                     // 处理获取数据请求
                     val reply = Message.obtain(null, MSG_GET_DATA).apply {
                         data = Bundle().apply { putString("result", "这是服务端的数据") }
                     }
                     msg.replyTo?.send(reply)
                 }
             }
             super.handleMessage(msg)
         }
     }
    
     override fun onCreate() {
         super.onCreate()
         Log.d("MessengerService", "服务创建")
     }
    
     override fun onBind(intent: Intent): IBinder {
         Log.d("MessengerService", "服务绑定")
         return mMessenger.binder
     }
    
     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
         Log.d("MessengerService", "服务启动")
         return START_STICKY // 服务被杀死后自动重启
     }

    }

  2. 在AndroidManifest.xml中注册该Service。

    复制代码
         <service
             android:name=".ui.activity.test.MessengerService"
             android:exported="true">
             <intent-filter>
                 <action android:name="cn.test.partner.MESSENGER_SERVICE" />
             </intent-filter>
         </service>

其中android:exported="true"尤为关键,表示该Service可被"应用外部"启动或交互。

  1. 在Activity中启动Service.

    复制代码
         // 启动MessengerService
         val intent = Intent(this, MessengerService::class.java)
         startService(intent)

二、客户端的实现

1.创建一个MessengerClient去实现和服务端的连接与通讯。

复制代码
class MessengerClient {
    companion object {
        const val MSG_SAY_HELLO = 1
        const val MSG_GET_DATA = 2
        const val MSG_SEND_DATA = 3
    }

    private var mService: Messenger? = null
    private var mReplyMessenger: Messenger? = null
    private var mContext: Context? = null
    private var mServiceConnection: ServiceConnection? = null

    fun init(context: Context) {
        mContext = context
        mReplyMessenger = Messenger(ReplyHandler())
    }

    fun connectToService() {
        val intent = Intent()
        intent.action = "cn.test.partner.MESSENGER_SERVICE"
        intent.setPackage("cn.test.partner") // 服务端应用的包名

        mServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                mService = Messenger(service)
                Log.d("MessengerClient", "连接服务成功")
                // 连接成功后可以发送消息
                sendHelloMessage()
            }

            override fun onServiceDisconnected(name: ComponentName?) {
                mService = null
                Log.d("MessengerClient", "服务连接断开")
            }
        }

        mContext?.bindService(intent, mServiceConnection!!, Context.BIND_AUTO_CREATE)
    }

    fun sendHelloMessage() {
        val msg = Message.obtain(null, MSG_SAY_HELLO)
        msg.replyTo = mReplyMessenger
        msg.data = Bundle().apply {
            putString("text", "客户端发送: 你好服务端!")
        }
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    fun getData() {
        val msg = Message.obtain(null, MSG_GET_DATA)
        msg.replyTo = mReplyMessenger
        msg.data = Bundle().apply {
            putString("query", "need_data")
        }
        try {
            mService?.send(msg)
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
    }

    inner class ReplyHandler : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            val data = msg.data
            // 若服务端放了自定义 Parcelable,需要设置类加载器
            // data.classLoader = MyParcelable::class.java.classLoader
            when (msg.what) {
                MSG_SAY_HELLO -> Log.d("MessengerClient", "服务端回复: ${data.getString("reply")}")
                MSG_GET_DATA -> Log.d("MessengerClient", "服务端数据: ${data.getString("result")}")
            }
            super.handleMessage(msg)
        }
    }

    fun disconnect() {
        mServiceConnection?.let {
            mContext?.unbindService(it)
        }
        mService = null
    }
}
  1. 在AndroidManifest.xml中注册queries

    复制代码
     <queries>
         <!-- 目标服务端应用包名 -->
         <package android:name="cn.test.partner" />
         <!-- 或按组件可见性声明 -->
         <intent>
             <action android:name="cn.test.partner.MESSENGER_SERVICE" />
         </intent>
     </queries>

是 Android 11(API 30)引入的清单节点,用于声明"应用可见的外部应用/组件"。它控制包可见性:没有在 (或其他允许途径)声明的目标应用,PackageManager 查询、隐式 Intent 解析等将不可见或返回空结果。

  1. 在Acitivity中初始化MessengerClient并和服务端进行连接。

    复制代码
     private lateinit var messengerClient: MessengerClient
     
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         
         messengerClient = MessengerClient()
         messengerClient.init(this)
         messengerClient.connectToService()
     }
     
     override fun onDestroy() {
         super.onDestroy()
         messengerClient.disconnect()
     }

三、完整流程

① 启动服务端应用 → MessengerService 自动启动

② 启动客户端应用 → 调用 connectToService()

③ 建立连接 → 客户端绑定到服务端

④ 发送消息 → 客户端发送消息到服务端

⑤ 处理消息 → 服务端处理并回复

⑥ 接收回复 → 客户端接收服务端回复

四、实现结果

  1. 服务端
  1. 客户端

五、注意事项

  1. 服务端的Service在注册时android:exported="true"必不可少。
  2. Android 11+ 若跨应用,请在客户端 Manifest 加 使目标包可见。
  3. Messenger 跨进程不支持通过 obj 传递非 Parcelable 对象,必须用 Bundle(或 arg1/arg2/what)。
  4. Bundle 里只能放基础类型、String、Parcelable、Serializable。自定义对象请实现 Parcelable(@Parcelize)。大对象(如大 Bitmap)会触发 Binder 事务超限(约 1MB),避免放入 Bundle。
相关推荐
黄林晴4 分钟前
Android17 为什么重写 MessageQueue
android
阿巴斯甜21 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker21 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 天前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android