当前位置: 首页 > news >正文

安卓AIDL跨应用通讯的实现

一、 服务端的实现

  1. 在项目的app/src/main 目录下创建 aidl 文件夹,目录结构应该与您的Java包结构一致,例如:app/src/main/aidl/com/hfyang/applicationtest/。

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f99d61479e5d4ff7b965f486ceb9947b.png

  1. 在app的build.gradle中添加aidl配置。
    buildFeatures {aidl true}sourceSets {main {aidl.srcDirs = ['src/main/aidl']}}
  1. 创建IPartnerService.aidl接口。
package com.hfyang.applicationtest;import com.hfyang.applicationtest.PartnerData;
import com.hfyang.applicationtest.IPartnerCallback;// 主要服务接口
interface IPartnerService {// 注册回调void registerCallback(IPartnerCallback callback);// 注销回调void unregisterCallback(IPartnerCallback callback);// 发送数据到服务端void sendData(in PartnerData data);// 获取服务状态boolean isServiceConnected();// 执行远程操作String executeCommand(String command, String params);
}
  1. 创建IPartnerCallback.aidl接口。
package com.hfyang.applicationtest;import com.hfyang.applicationtest.PartnerData;// 回调接口
interface IPartnerCallback {void onDataReceived(in PartnerData data);void onError(String error);
}
  1. 创建PartnerData.aidl用于包装数据,AIDL 只需声明 parcelable PartnerData;,真正的 Parcelable 类只在服务端实现即可。
    注:src/main/aidl 目录只给 .aidl 文件用,放 Kotlin/Java 类不会被编译,也不会参与打包。
package com.hfyang.applicationtest;// Parcelable类声明
parcelable PartnerData;
  1. 创建Parcelable类PartnerData的具体实现。
package com.hfyang.applicationtestimport android.os.Parcel
import android.os.Parcelabledata class PartnerData(var id: String = "",var message: String = "",var timestamp: Long = 0L,var data: Map<String, Any>? = null
) : Parcelable {constructor(parcel: Parcel) : this(parcel.readString() ?: "",parcel.readString() ?: "",parcel.readLong(),parcel.readHashMap(String::class.java.classLoader) as? Map<String, Any>)override fun writeToParcel(parcel: Parcel, flags: Int) {parcel.writeString(id)parcel.writeString(message)parcel.writeLong(timestamp)parcel.writeMap(data)}override fun describeContents(): Int = 0companion object CREATOR : Parcelable.Creator<PartnerData> {override fun createFromParcel(parcel: Parcel): PartnerData = PartnerData(parcel)override fun newArray(size: Int): Array<PartnerData?> = arrayOfNulls(size)}
}

上述创建完成后,执行Rebuild即可在build/generated/aidl_source_output_dir下生成对应的文件。
在这里插入图片描述

  1. 服务端PartnerService的实现。
package com.hfyang.applicationtestimport android.app.Service
import android.content.Intent
import android.os.IBinder
import android.os.RemoteCallbackList
import android.os.RemoteException
import android.util.Log
import java.util.concurrent.Executorsclass PartnerService : Service() {private val TAG = "PartnerService"private val callbacks = RemoteCallbackList<IPartnerCallback>()private var isConnected = falseprivate val binder = object : IPartnerService.Stub() {override fun registerCallback(callback: IPartnerCallback?) {callbacks.register(callback)isConnected = true}override fun unregisterCallback(callback: IPartnerCallback?) {callbacks.unregister(callback)if (callbacks.registeredCallbackCount == 0) {isConnected = false}}override fun sendData(data: PartnerData?) {// 处理接收到的数据data?.let {// 通知所有注册的回调notifyCallbacksAsync(it)processReceivedData(it)}}override fun isServiceConnected(): Boolean = isConnectedoverride fun executeCommand(command: String?, params: String?): String {return when (command) {"getStatus" -> "Service is running""getData" -> "Data from service"else -> "Unknown command"}}}override fun onBind(intent: Intent?): IBinder = binderprivate fun processReceivedData(data: PartnerData) {// 处理业务逻辑println("Received data: ${data.message}")Log.d(TAG, "processReceivedData: $data")}private fun notifyCallbacksAsync(data: PartnerData) {// 使用线程池执行通知操作,避免阻塞主线程Executors.newSingleThreadExecutor().submit {notifyCallbacks(data)}}private fun notifyCallbacks(data: PartnerData) {val count = callbacks.beginBroadcast()try {for (i in 0 until count) {try {callbacks.getBroadcastItem(i).onDataReceived(data)} catch (e: RemoteException) {e.printStackTrace()}}} finally {callbacks.finishBroadcast()}}override fun onDestroy() {super.onDestroy()callbacks.kill()}
}
  1. 在AndroidManifest.xml中注册Service声名。
        <serviceandroid:name=".PartnerService"android:enabled="true"android:exported="true"android:process=":remote"><intent-filter><action android:name="com.hfyang.applicationtest.PartnerService" /></intent-filter></service>

二、客户端的实现

  1. 将服务端的aidl文件及其路径复制一份到客户端的main后,执行Rebuild,生成对应的文件。此时生成的文件会找不到com.hfyang.applicationtest.PartnerData这个具体的实现类,只需在java目录下创建一个即可。

在这里插入图片描述
如果需要,亦可将aidl部分直接打包成aar使用,也不会存在该问题。

  1. 客户端PartnerClient的实现。
package com.hfyang.clientimport android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.os.RemoteException
import com.hfyang.applicationtest.IPartnerCallback
import com.hfyang.applicationtest.IPartnerService
import com.hfyang.applicationtest.PartnerData
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launchclass PartnerClient(private val context: Context) {private var remote: IPartnerService? = null@Volatile var isConnected = falseprivate setprivate val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())private val connection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {remote = IPartnerService.Stub.asInterface(service)isConnected = truetry { remote?.registerCallback(callback) } catch (_: RemoteException) { }onConnected?.invoke()}override fun onServiceDisconnected(name: ComponentName?) {isConnected = falseremote = nullonDisconnected?.invoke()}}private val callback = object : IPartnerCallback.Stub() {override fun onDataReceived(data: PartnerData?) {if (data != null) coroutineScope.launch { onData?.invoke(data) }}override fun onError(error: String?) {if (error != null) coroutineScope.launch { onError?.invoke(error) }}}var onConnected: (() -> Unit)? = nullvar onDisconnected: (() -> Unit)? = nullvar onData: ((PartnerData) -> Unit)? = nullvar onError: ((String) -> Unit)? = nullfun bindByAction() {val intent = Intent("com.hfyang.applicationtest.PartnerService").apply {setPackage("com.hfyang.applicationtest") // 服务端包名}context.bindService(intent, connection, Context.BIND_AUTO_CREATE)}fun bindByComponent() {val intent = Intent().apply {component = ComponentName("com.hfyang.applicationtest","com.hfyang.applicationtest.PartnerService")}context.bindService(intent, connection, Context.BIND_AUTO_CREATE)}fun unbind() {try { remote?.unregisterCallback(callback) } catch (_: RemoteException) { }runCatching { context.unbindService(connection) }isConnected = falseremote = nullcoroutineScope.cancel()}fun send(data: PartnerData) {if (!isConnected) returntry { remote?.sendData(data) } catch (_: RemoteException) { }}fun exec(command: String, params: String = ""): String? {if (!isConnected) return nullreturn try {remote?.executeCommand(command, params)} catch (_: RemoteException) {null}}
}
  1. 在AndroidManifest.xml的注册queries。
    <queries><!-- 目标服务端应用包名 --><package android:name="com.hfyang.applicationtest" /><!-- 或按组件可见性声明 --><intent><action android:name="com.hfyang.applicationtest.PartnerService" /></intent></queries>
  1. 在Activity中实现连接。
    private val TAG = "MainActivity"private lateinit var partnerClient: PartnerClientoverride fun onCreate(savedInstanceState: Bundle?) {partnerClient = PartnerClient(this).apply {onConnected = {// 连接成功后发送一条消息send(PartnerData(id = "1",message = "hello",timestamp = System.currentTimeMillis()))}onData = { data ->Log.d(TAG, "processReceivedData: $data")}onError = { err ->// 处理错误}}// 二选一:按 action 绑定或按 component 绑定
//        partnerClient.bindByAction()partnerClient.bindByComponent()}override fun onDestroy() {super.onDestroy()partnerClient.unbind()}

三、注意事项

  1. 禁止跨进程 UI 操作:服务端Service 进程仅负责数据处理,主进程通过回调接收结果后,必须用 runOnUiThread 或 Handler(Looper.getMainLooper()) 确保 UI 操作在主线程执行。
  2. 避免直接依赖:服务端Service 与主进程通过明确定义的 IPC 协议通信,杜绝硬编码 UI 逻辑到 Service 中。
  3. 避免阻塞 Binder 线程:客户端AIDL 回调方法(onDataReceived/onError)应快速执行,禁止在其中执行耗时操作(如网络请求、数据库写入),否则会阻塞 Binder 线程池。
  4. 线程安全:客户端即使切换到主线程,仍需注意共享数据的线程安全(如使用 @Synchronized 或 Lock 处理多线程读写)。
  5. 内存泄漏防护:客户端无论使用 Handler 还是协程,都需在 unbind() 时清理资源(如 Handler.removeCallbacksAndMessages(null) 或协程取消)。
http://www.dtcms.com/a/466901.html

相关文章:

  • 如何做一个花店小程序,搭建一个小程序多少钱
  • 电商网站公司木兰网
  • 网站投放广告教程怎么创建官网主页
  • 线性表—链式描述
  • PTA6-11 拆分实数的整数与小数部分(C)
  • 重庆工业网站建设黄冈做网站价格
  • 行政单位门户网站建设方案惠州公众号开发公司
  • 有网络网站打不开自建网站需要哪些技术
  • 建设工程材料网站江西省宜春市建设局网站
  • 网站seo优化徐州百度网络网站的中英文翻译是怎么做的
  • 【LeetCode】61. 旋转链表
  • 整站seo优化哪家好电商设计网站培训
  • 【GD32】启动过程-程序计数器(PC)
  • 茶艺实训室:为学习者打造专业茶艺实操平台
  • 机械设计网站推荐贵州建设监理网站培训通知栏
  • 常州网站制作策划手机制作网站主页软件
  • 淘宝天猫优惠券网站怎么做工作啦
  • H3C 实现ACL 访问控制
  • 【北京迅为】iTOP-4412精英版使用手册-第三十七章 Hello_Driver_Module
  • 1 建设好自媒体门户网站网站备案要几天
  • GESP C++等级认证三级13-操作string2-2
  • 富连网网站开发数字营销成功案例
  • 我的网站 dedecms网站开发模式分为
  • 【附代码】Jupyter 多进程调用 seaborn 并保留格式
  • 正规手机网站建设平台之梦一个系统做多个网站
  • 服务器数据恢复—Raid5多盘掉线,存储如何“起死回生”?
  • 郑州网站推广价vue.js合作做网站么
  • [嵌入式系统-85]:GPU内部结构
  • 珠海网站建设哪个平台好wordpress的html
  • 网站开发佛山南京微信网站建设