AIDL 跨进程通信学习实验 API34

前言

考虑到后面有需要到车载或者其他多程序交互的场景,因此我最近也接触了下AIDL这个东西,AIDL在写文本时也是第一次使用,所以我们首要关注实现AIDL要具备什么东西。

需要注意的是,本文可能存在一些错误解释,希望读者阅读时注意甄别,实践出真知,对内容有兴趣的话就快试试看!

什么是AIDL

Android Interface Definition Language(Android接口定义语言),利用AIDL我们可以生成一套IPC通信代码,也就是进程间通信,我们知道一个APP默认情况下是一个进程,因此宏观上说AIDL可以用于不同APP之间的通信。

AIDL是一种模板语法,类似Java的接口,定义后生成的代码就是Java的接口类,内部有实现了IPC通信,但是由于这些代码是重复的,所以安卓贴心的给我们一个模型生成这些代码。

AIDL生成的接口中存在一个Binder的示例,APP可以通过Service来使用它,其他APP绑定这个Service就可以相互通信了。

实验前提

我们模拟2个APP

  • 服务端APP
  • 客户端APP
  • AIDL模块(供其他模块或者APP引入使用)

实操

我们只是要实现这个跨进程通信,因此功能不太重要,我们下面使用各自办法目的只是为了传递数据给通信双方。

实现AIDL模块

我们先创建一个Android项目,这个项目就作为客户端APP了(为了方便)。

接下来我们创建一个模块,对应图上就是aidl-sdk,我们需要在里边去编写AIDL的模板和Bean类。

启用AIDL

在正式开始前我们得在gradle文件里编写下面的配置,不然待会我们没办法创建AIDL文件。

buildFeatures { aidl = true }

创建AIDL文件

让我们选择AIDL-SDK模块,点击新建,找到AIDL,如果你没有配置上面说的选项,那么这里是没办法勾选的哦。

下面我起个名字叫做IMyAidlInterface ,你会发现多了一个aidl的文件夹,其中就有IMyAidlInterface.adil文件。

我们在里边这么写,就实现传递两个数字返回相加结果,怎么说?看上去好像和Java语法很像对不对?不过我发现这里没有提词,有点不太习惯。

java 复制代码
// IMyAidlInterface.aidl
package com.imcys.aidl_sdk;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
  int add(int a, int b);
}

接下来,我们点击Build,不Build这个AIDL文件不会变成接口类。

当我们再次检查时会发现已经生成了对应的Java文件。

这个接口文件里有一个抽象类,这个Stub的构造方法就会给我们一个Binder,后面我们就可以在服务中使用它。

实现服务端APP

我们回到最外层,创建一个新的APP项目模块。

这么做是为了我们待会方便引入写好的AIDL模块,就创建在一个大项目下面了。

不要忘记给这个新建的服务端APP模块引入前面创建的aidl-sdk,不然生成的接口这个模块看不到。

implementation(project(":aidl-sdk"))

还记得吗?我前面说这个AIDL生成的接口中有个Binder,这东西要给服务来用,所以我们直接创建一个项目奥。

下面我创建一个AIDLDemoServer 类作为Service

而onBind方法正好需要一个Binder ,那么我们就直接给他传递生成的Binder,让它来接管服务的通信。

这里我们继承生成接口的Stub类,实现它里边的方法,这些方法实际上就是我们刚刚在模板定义的,注意,下面的三个方法是我后来写在模板的,因此我们暂时不用关注。

我们给add进行了实现,它的功能就是相加就可以了,然后我们把Binder传递给onBind就好。

服务注册

千万别忘记注册我们的服务:

xml 复制代码
    <service
            android:name=".AIDLDemoServer"
            android:enabled="true"
            android:exported="true"
            tools:ignore="ForegroundServicePermission">
            <intent-filter>
                <action android:name="com.imcys.aidldemo.AIDLSERVICE"/>
            </intent-filter>
        </service>

注意我们这里加了一个action,用于绑定时过滤。

免杀扩展

让我们的服务成为前台服务,降低系统杀掉的情况,这个安卓13有一些权限调整,需要你指定前台服务的类型。

xml 复制代码
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>

服务概览 | Background work | Android Developers (google.cn)

具体看上面地址,我这里就不做这一步了。

实现客户端APP

同样的,我们给APP引入前面创建的aidl-sdk,不然生成的接口这个模块看不到。

implementation(project(":aidl-sdk"))

绑定服务

绑定服务的方法类似我们正常在APP内绑定服务,但是由于不在一个APP我们需要指定包名和这个服务的具体类。

kotlin 复制代码
    private fun bindAIDLServer() {

        val intent = Intent()
        intent.setAction("com.imcys.aidldemo.AIDLSERVICE")
        intent.setComponent(
            ComponentName(
                "com.imcys.aidldemo.server",
                "com.imcys.aidldemo.server.AIDLDemoServer"
            )
        )
        val suc = bindService(intent, serviceConnection, BIND_AUTO_CREATE)
        Log.i(TAG, "bindToService: $suc")
        
    }

注意我们这里用了setAction,是因为服务端APP注册服务时指定了action。

这块需要传一个ServiceConnection,我们看看如何获取它。

我们看到它也返回了IBinder,很巧的是,生成的IMyAidlInterface中有一个转换的方法。

iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)

非常巧妙,我们获取到了iMyAidlInterface,现在我们调用iMyAidlInterface的方法就会和服务端APP进行通信了。

让我们运行看看,注意不要在onServiceConnected执行iMyAidlInterface,因为那是主线程,我这块只是为了演示。

运行结果

可以看到,我们成功了,返回结果是30,它将10和20加在了一起,这样我们就实现了跨进程通信。

传递Bean

这是拓展内容,有兴趣的可以看看。

创建Bean

我们在aidl-sdk模块创建bean包,在里边创建一个AIDLMessage,由于AIDL不能直接传输它,因此我们需要序列化,这里谷歌推荐的是Parcelable,这个实现大家可以在网上找一下。

创建AIDL

我们需要定义一个新的AIDL

parcelable AIDLMessage;

但是不要忘记,我们得在之前的AIDL中定义一个方法来使用它,现在假设它是返回类型。

注意,我们得导入它的包,和正常导包的写法是一样的。

服务端实现

Service的实现是简单的,我们相当于new一个AIDLMessage出去。

客户端实现

Log.i(TAG, "特别序列化${iMyAidlInterface.buildAIDLMessage(1, "备注").msg}")

我们在客户端调用一下,看看运行结果。

毫无疑问,成功了。

文末

本文内容可能并不完全正确,希望帮助到了大家,有问题可以在评论区告诉我,另外最近掘金在投年度创作者榜单,希望大家可以投我一票。

相关推荐
MiyamuraMiyako1 小时前
从 0 到发布:Gradle 插件双平台(MavenCentral + Plugin Portal)发布记录与避坑
android
NRatel1 小时前
Unity 游戏提升 Android TargetVersion 相关记录
android·游戏·unity·提升版本
叽哥4 小时前
Kotlin学习第 1 课:Kotlin 入门准备:搭建学习环境与认知基础
android·java·kotlin
风往哪边走4 小时前
创建自定义语音录制View
android·前端
用户2018792831674 小时前
事件分发之“官僚主义”?或“绕圈”的艺术
android
用户2018792831674 小时前
Android事件分发为何喜欢“兜圈子”?不做个“敞亮人”!
android
Kapaseker6 小时前
你一定会喜欢的 Compose 形变动画
android
QuZhengRong6 小时前
【数据库】Navicat 导入 Excel 数据乱码问题的解决方法
android·数据库·excel
zhangphil7 小时前
Android Coil3视频封面抽取封面帧存Disk缓存,Kotlin(2)
android·kotlin
程序员码歌14 小时前
【零代码AI编程实战】AI灯塔导航-总结篇
android·前端·后端