安卓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。
相关推荐
hunterandroid15 小时前
Android WebView JSBridge 治理实战:从线上白屏崩溃到协议化通信
android·前端
一个用户名i15 小时前
【Compose 系列】第 1 篇:认识 Compose,为什么要学它
android·android jetpack
极客猴子16 小时前
iPhone实时转写软件推荐:会议录音功能真实体验
android·人工智能·飞书
达令哥16 小时前
告别 ARouter!基于 Google 官方 Navigation 3 + KSP 打造 Compose 时代的双轨制路由框架
android·前端
YF021116 小时前
Android App启动与权限管控
android
嘟哩DuliDuli17 小时前
AI 短剧生成为什么要有角色库、场景库和镜头卡
android·人工智能·安全·ai·软件工程
NINO18 小时前
深度解析 Android ANR:从标准分析流程到 NativePollOnce 疑难破局
android
阿巴斯甜19 小时前
AppFunctions 完整介绍
android
蜡台19 小时前
Jetpack Compose 从入门到精通
android·前端·kotlin·compose·jepack
toooooop819 小时前
踩坑:PHP7.2导出Excel正常,升级7.3文件损坏需修复
android·excel