安卓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。
相关推荐
白云LDC4 小时前
Android Studio新建Vecter asset一直显示Loading icons(转圈圈)的解决办法
android·ide·android studio
Rytter7 小时前
某气骑士 libtprt.so 反 Frida 机制分析与绕过
android·安全·网络安全
alexhilton7 小时前
揭密:Compose应用如何做到启动提升34%
android·kotlin·android jetpack
沐言人生9 小时前
React Native 源码分析1——HybridData 机制深度分析
android·react native
程序员陆业聪10 小时前
跨平台框架全景图:Flutter/KMP/KuiKly/RN的2026年格局
android
码云数智-园园11 小时前
Fibers(纤程)来了:打破阻塞,实现纯PHP下的异步非阻塞IO
android
shaoming377613 小时前
检查系统硬件配置是否满足PyCharm最低要求
android·spring boot·mysql
一起搞IT吧14 小时前
高通Camx功能feature分析之十五:insensor zoom介绍及实现
android·智能手机·相机
aqi0015 小时前
一文读懂 HarmonyOS 6.1 带来的十大重要升级
android·华为·harmonyos·鸿蒙·harmony
秋917 小时前
MySQL 9.7.0 使用详解:新特性、实战与避坑指南
android·数据库·mysql