联系我们
简单又实用的WordPress网站制作教学
当前位置:网站首页 > 程序开发学习 > 正文

AIDL 跨进程通信学习实验 API34

作者:访客发布时间:2023-12-24分类:程序开发学习浏览:87


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

前言

考虑到后面有需要到车载或者其他多程序交互的场景,因此我最近也接触了下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了(为了方便)。

image.png

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

启用AIDL

image.png

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

buildFeatures { aidl = true }

创建AIDL文件

image.png

让我们选择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);
}

image.png

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

image.png

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

image.png

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

实现服务端APP

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

image.png

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

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

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

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

下面我创建一个AIDLDemoServer类作为Serviceimage.png

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

image.png

这里我们继承生成接口的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"/>

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

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

实现客户端APP

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

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

绑定服务

image.png

绑定服务的方法类似我们正常在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,我们看看如何获取它。

image.png

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

iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)

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

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

运行结果

image.png

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

传递Bean

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

创建Bean

image.png

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

创建AIDL

image.png

我们需要定义一个新的AIDL

parcelable AIDLMessage;

image.png

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

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

服务端实现

image.png

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

客户端实现

image.png

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

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

image.png

毫无疑问,成功了。

文末

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


标签:通信AIDL


程序开发学习排行
最近发表
网站分类
标签列表