前语
考虑到后边有需求到车载或者其他多程序交互的场景,因而我最近也接触了下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语法很像对不对?不过我发现这儿没有提词,有点不太习惯。
// 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就好。
服务注册
千万别忘掉注册咱们的服务:
<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有一些权限调整,需求你指定前台服务的类型。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
详细看上面地址,我这儿就不做这一步了。
完成客户端APP
同样的,咱们给APP引进前面创立的aidl-sdk,不然生成的接口这个模块看不到。
implementation(project(":aidl-sdk"))
绑定服务
绑定服务的办法类似咱们正常在APP内绑定服务,可是由于不在一个APP咱们需求指定包名和这个服务的详细类。
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}")
咱们在客户端调用一下,看看运转成果。
毫无疑问,成功了。
文末
本文内容可能并不完全正确,期望帮助到了咱们,有问题能够在谈论区告诉我,另外最近在投年度创作者榜单,期望咱们能够投我一票。