安卓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。
相关推荐
咕噜企业签名分发-淼淼2 小时前
App防止恶意截屏功能的方法:iOS、Android和鸿蒙系统的实现方案
android·ios·harmonyos
Digitally3 小时前
如何将文件从电脑传输到安卓设备
android
游戏开发爱好者87 小时前
iOS 26 崩溃日志深度解读,获取方式、系统变动、定位策略
android·macos·ios·小程序·uni-app·cocoa·iphone
一直向钱7 小时前
android 基于okhttp 封装一个websocket管理模块,方便开发和使用
android·websocket·okhttp
小趴菜82278 小时前
安卓人机验证View
android·java·前端
ajassi20009 小时前
开源 java android app 开发(十七)封库--混淆源码
android·java·开源
2501_916008899 小时前
JavaScript调试工具有哪些?常见问题与常用调试工具推荐
android·开发语言·javascript·小程序·uni-app·ecmascript·iphone
2501_9293826510 小时前
AdGuard解锁订阅版高级版 安卓广告拦截器APP v4.11.63 / 4.13.7 Nightly MOD
android
vistaup11 小时前
android studio 无法运行java main()
android·java·android studio