安卓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。
相关推荐
灯火不休➴10 分钟前
安卓 ContentProvider 详解:跨应用数据共享的核心方案
android
沐怡旸41 分钟前
【底层机制】【Android】Android 系统的启动流程
android
limuyang244 分钟前
【http3/quic】cronet 已经原生集成在Android内啦!还不快来开开眼!
android·http·google
乌萨奇也要立志学C++1 小时前
【Linux】Ext系列文件系统 从磁盘结构到文件存储的原理剖析
android·linux·缓存·1024程序员节
宋发元3 小时前
IPhone 17 Pro Max拍摄专业画质视频教程
android·gradle·iphone
出门吃三碗饭4 小时前
如何在LLM大语言模型上微调来优化数学推理能力?
android·人工智能·语言模型
shaominjin1235 小时前
Android访问OTG文件全解析:从连接到操作的完整指南Android系统访问U盘的实现机制与操作指南
android
游戏开发爱好者88 小时前
HTTPS 内容抓取实战 能抓到什么、怎么抓、不可解密时如何定位(面向开发与 iOS 真机排查)
android·网络协议·ios·小程序·https·uni-app·iphone
Tom4i10 小时前
Android 系统的进程模型
android
介一安全10 小时前
【Frida Android】基础篇9:Java层Hook基础——Hook构造函数
android·网络安全·逆向·安全性测试·frida