Android 远程调用服务之 AIDL

目录

一、AIDL 是什么?
二、为什么要使用 AIDL?
    1、使用 AIDL 是为了跨进程调用第三方服务?
    2、使用 AIDL 是为了向第三方服务传输数据/参数?
    3、使用 AIDL 是为了获取第三方服务直接或者异步返回的数据?
三、提供哪些文件给客户端?
    1、直接 copy 所有的 .aidl 文件给客户端,并要求客户端保持包结构;
    2、先编译 .aidl 文件,然后把 build 编译后生成的 .java 文件 copy 给客户端,并要求客户端保持包结构;
    3、把 .aidl 文件放在一个单独的 (Android Studio) Module 中,build 编译生成的 .aar 文件 copy 给客户端依赖;
四、AIDL 项目结构
    1、Server 独立工程,AIDL 独立工程,Client 独立工程。
    2、Server + AIDL 独立工程,Client 独立工程。(推荐)
五、案例:Client 跨进程调用 Server 端的 Service 服务,并获取异步处理数据的结果。
    一)、本案例项目结构:
    二)、AidlLib 接口编写:
        1、新建 AIDL Folder
        2、新建 .aidl 文件配置
        3、新建 AIDL 通讯接口文件 IMyTestAidlInterface.aidl
        4、新建 searchKeyWord() 方法中的参数回调接口 IMyTestCallback.aidl
        5、如果需要使用 Java Bean 数据类了,需要怎么处理呢?
        6、最后单独 aidl 代码的 Module 执行 build 编译,把生成的 .aar 文件 copy 给 客户端依赖。
    三)、Server 服务提供方:
        1、修改 Server 的 build.gradle 文件,源码依赖 aidl 的 Module
        2、新建 Service 类 MyService.java
        3、在清单文件中配置 Servcie
    四)、Client 业务调用方:
        1、把 .aar 文件 copy 到 libs 目录中,并配置依赖
        2、在界面上添加一个 TextView
        3、点击 TextView 时 bind 调用远端 Service
        4、创建上面 bindService() 需要的 intent 参数
        5、创建上面 bindService() 需要的 ServiceConnection 参数
        6、创建 callback 对象,提供给 searchKeyWord() 方法参数使用
        7、在清单文件中配置 <queries>
六、测试步骤和效果
    1、 安装 Servcie 类所在的应用
    2、安装客户端应用
    3、启动客户端应用
    4、点击客户端 Activity 的 TextView,异步获取服务端的内容
七、测试环境

​----------------------------------

 Demo 代码:

AIDL_Server_test:https://github.com/mengzhinan/AIDL_Server_test
AIDL_Client_test:https://github.com/mengzhinan/AIDL_Client_test
----------------------------------

正文内容

一、AIDL 是什么?

AIDL 英文全称:Android Interface Definition Language,中文含义:Android 接口定义语言

Android 接口定义语言 (AIDL) 官方文档:Android 接口定义语言 (AIDL)  |  Android 开发者  |  Android Developers

AIDL 是 Android 接口定义语言,是一种代码规范,需要通过编译后生成 .java 文件,然后提供给 Server 和 Client 使用,实现 Android 不同应用之间跨进程通讯。

二、为什么要使用 AIDL?

1、使用 AIDL 是为了跨进程调用第三方服务?

我觉得不一定。不使用 AIDL ,构造好 intent,直接调用 context.startService / context.bindService 调起第三方服务也可以通讯。

2、使用 AIDL 是为了向第三方服务传输数据/参数?

我觉得不一定。在使用 context.startService / context.bindService 方法调用服务时,可以在 intent 中携带参数。

3、使用 AIDL 是为了获取第三方服务直接或者异步返回的数据?

对,我认为是这个。要不然还需要在 .aidl 文件中编写接口方法干嘛,当然是想获取远端 Service 的处理结果,甚至是远端 Service 的异步处理结果。

三、提供哪些文件给客户端?

AIDL 只是一种接口定义语言规范,不是可执行的 Java 代码。编写好 .aidl 文件后,还需要 build 编译才会生成最终的 .java 文件。

那么,应该提供哪些文件给调用端(客户端)呢?

1、直接 copy 所有的 .aidl 文件给客户端,并要求客户端保持包结构;

2、先编译 .aidl 文件,然后把 build 编译后生成的 .java 文件 copy 给客户端,并要求客户端保持包结构;

3、把 .aidl 文件放在一个单独的 (Android Studio) Module 中,build 编译生成的 .aar 文件 copy 给客户端依赖;

四、AIDL 项目结构

从上面的信息了解到,可以以多种形式向客户端提供 .java 文件。同时发现,如果提供 .aar 包的话,连 .aidl 文件的包结构都不用关心。

.aidl 文件独立 Module 的方式也有两种,我更倾向于第二种:

1、Server 独立工程,AIDL 独立工程,Client 独立工程。

新建一个 AIDL 的工程,然后新建一个 Module,把所有的 .aidl 文件和必要的 .java 数据传输文件放在改 Module 中,build 编译产出 .aar 文件。

最后把 .aar 文件提供给 Server 和 Client 依赖使用。

测试时,只需要运行 Server 和 Client 的 app Module 即可,AIDL 工程的 app Module 不需要安装在测试机中。

2、Server + AIDL 独立工程,Client 独立工程。(推荐)

在 Server 工程中,新建一个 Module 专门用于存放某业务的 .aidl 文件,build 编译产出 .aar 文件。

Server 与 AIDL 之间直接使用 Module 方式源码依赖就可以了,Client 与 AIDL 之间还是使用 .aar 包方式依赖。

五、案例:Client 跨进程调用 Server 端的 Service 服务,并获取异步处理数据的结果。

一)、本案例项目结构:

二)、AidlLib 接口编写:

1、新建 AIDL Folder

aidl 目录下存放所有的 .aidl 文件,java 目录下存放所有的 .java 文件。

建议 aidl 和 java 目录的包名一致。如果坚决不想保持一致,那数据类 Java Bean 的包结构必须保持一致,比如: UserData.java 和 UserData.aidl 文件。

2、新建 .aidl 文件配置

如果 AIDL File 选项是灰色的不可点击,则需要在该 Module 下的 build.gradle 文件中添加配置 aidl = true,如:

android {。。。// 添加 aidl foldersourceSets {getByName("main") {aidl {srcDirs("src/main/aidl")}}}buildFeatures {// 如果 aidl 目录未变色/无法新建 aidl 文件,则需要配置这个aidl = true}
}
3、新建 AIDL 通讯接口文件 IMyTestAidlInterface.aidl

计划在客户端调用 searchKeyWord() 方法,并传入 IMyTestCallback 回调接口。

等到服务端处理完数据后,调用 IMyTestCallback 回调接口向客户端传回数据。

// IMyTestAidlInterface.aidl
package com.fffffff.aidllib;// Declare any non-default types here with import statements
import com.fffffff.aidllib.IMyTestCallback;interface IMyTestAidlInterface {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void searchKeyWord(int anInt, String aString, IMyTestCallback myCallback);int addNum(int a, int b);
}
4、新建 searchKeyWord() 方法中的参数回调接口 IMyTestCallback.aidl

等待远端 Server 的 Service 处理完数据后,主动调用该接口的 onXXX() 方法回传数据。

// IMyTestCallback.aidl
package com.fffffff.aidllib;// Declare any non-default types here with import statements
import com.fffffff.aidllib.UserData;interface IMyTestCallback {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void onResult(String msg, in UserData userData);void onFailure(String error);
}
5、如果需要使用 Java Bean 数据类了,需要怎么处理呢?

首先,在 java 目录下新建 Java 类 UserData.java ,然后实现序列化接口 Parcelable。

如果 UserData 参数设置了 out 或者 inout 标签的话,还需要实现如下方法:

//    /**
//     * 参数方向为 out or inout 时,才需要此方法
//     * 手动添加此方法
//     *
//     * @param in in
//     */
//    public void readFromParcel(Parcel in) {
//        percentage = in.readInt();
//        msg = in.readString();
//    }

更多关于 in、out 和 inout 标签的用法,请继续查阅资料,我也不太了解。

第二步,还需要在 aidl 目录下编写 UserData.java 的 UserData.aidl 描述文件

注意,文件中 parcelable 的 p 是小写的。

6、最后单独 aidl 代码的 Module 执行 build 编译,把生成的 .aar 文件 copy 给 客户端依赖。

三)、Server 服务提供方:

1、修改 Server 的 build.gradle 文件,源码依赖 aidl 的 Module

2、新建 Service 类 MyService.java

因为客户端想要获取服务端的计算结果,所以要使用 bindService 方式调用服务。

因此服务端需要实现 onBind(Intent intent)() 方法,并返回 binder 对象,使客户端能够调用到 aidl 定义的方法。

onBind(Intent intent)() 方法需要返回一个 IBinder 对象,刚好 IMyTestAidlInterface.Stub 抽象类实现了 IBinder 接口:

package com.fffffff.aidlserver;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.annotation.Nullable;
import com.fffffff.aidllib.IMyTestAidlInterface;
import com.fffffff.aidllib.IMyTestCallback;
import com.fffffff.aidllib.UserData;public class MyService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {return new IMyTestAidlInterface.Stub() {@Overridepublic void searchKeyWord(int i, String s, IMyTestCallback iMyTestCallback) throws RemoteException {UserData userData = new UserData();userData.percentage = i;userData.msg = s;iMyTestCallback.onResult("服务端处理完毕", userData);}@Overridepublic int addNum(int a, int b) throws RemoteException {return a + b;}};}
}

注意:

IMyTestAidlInterface.Stub.searchKeyWord() 方法没有直接返回值,而是使用异步的方式回传数据。

当数据处理完毕后,调用 IMyTestCallback 接口的 onResult() 方法回传数据。

3、在清单文件中配置 Servcie

注意配置:

是否启用此 Service 类:android:enabled="true" 

是否允许其他进程调用此服务:android:exported="true" 

自己定义一个 Action,不重复就行:<action android:name="com.fffffff.aidlserver.action.MY_SERVICE_CENTER" />

四)、Client 业务调用方:

1、把 .aar 文件 copy 到 libs 目录中,并配置依赖

2、在界面上添加一个 TextView

3、点击 TextView 时 bind 调用远端 Service
tvShow.setOnClickListener {tvShow.isClickable = false// 点击 TextView 绑定服务val intent = BindServerUtil.buildIntent3()this.applicationContext?.bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
4、创建上面 bindService() 需要的 intent 参数

调用 servcie 的 intent 方式很多。

→ setComponent() 方式:

@JvmStatic
fun buildIntent1(): Intent {val intent = Intent()// setComponent() 方式intent.component = ComponentName("com.fffffff.aidl_server_test", "com.fffffff.aidlserver.MyService")return intent
}

→ setClassName() 方式:

@JvmStatic
fun buildIntent2(): Intent {val intent = Intent()// setClassName() 方式intent.setClassName("com.fffffff.aidl_server_test", "com.fffffff.aidlserver.MyService")return intent
}

→ setAction() 方式:

@JvmStatic
fun buildIntent3(): Intent {val intent = Intent()// setAction() 方式intent.action = "com.fffffff.aidlserver.action.MY_SERVICE_CENTER"intent.setPackage("com.fffffff.aidl_server_test")return intent
}

注意:

上面提到的包名为,数据提供方(服务端)的可执行 Module 的包名,比如常见的 App Module,不是 Service 类所在的子 Module 的包名。

上面提到的 Service 全类名为,Service 类实际所在的包名 + 类名称。

上面提到的 Action 为,数据提供方(服务端)中 Service 类清单文件中定义的 Action 值。

上面三种方法,推荐使用第三方方法 action 的方式。因为你不确定服务端以后会不会对代码重构,如果修改 Service 的类名或包名了呢。

5、创建上面 bindService() 需要的 ServiceConnection 参数

ServiceConnection 是一个接口,直接 new 一个实现类传入到 bindService() 方法中。

在 onServiceConnected() 抽象方法中,使用 IMyTestAidlInterface.Stub.asInterface(IBinder) 方法把 service: IBinder? 参数转换为 IMyTestAidlInterface 类型。即服务端 Service 中返回的 binder 对象。

// 服务绑定成功/失败的回调
private val connection: ServiceConnection = object : ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {tvShow.text = "连接成功"try {iMyTestAidlInterface = IMyTestAidlInterface.Stub.asInterface(service)val callback = createBinderCallback()iMyTestAidlInterface?.searchKeyWord(404, "wuhan", callback)} catch (e: Exception) {tvShow.text = "连接失败 error = ${e.message}"e.printStackTrace()}}override fun onServiceDisconnected(name: ComponentName?) {tvShow.text = "连接断开"}
}

有了服务端的 IMyTestAidlInterface 对象,就可以直接调用服务端实现的接口方法了。

此处调用 searchKeyWord() 方法,并传入回调接口,类似于网络请求的成功与失败的 callback 接口。

6、创建 callback 对象,提供给 searchKeyWord() 方法参数使用

小心,有坑,巨坑

searchKeyWord() 方法需要 IMyTestCallback 类型的对象作为参数,那么是直接 new 一个 IMyTestCallback 的实现类吗?不是啊,坑坑坑

而是需要 new 一个 IMyTestCallback.Stub 类型的实现类对象:

/*** 客户端的回调接口需要 new IMyTestCallback.Stub 的实现类,* 而不是 new IMyTestCallback 的实现类。*/
private fun createBinderCallback(): IMyTestCallback.Stub {return object : IMyTestCallback.Stub() {override fun onResult(p0: String, p1: UserData?) {tvShow.text = "$p0:\n" + "UserData = $p1\nint = ${p1?.percentage}\nmsg = ${p1?.msg}"}override fun onFailure(p0: String?) {tvShow.text = "获取失败 = $p0"}}
}

最后,在回调 callback 中获取服务端 Service 返回的数据,设置到 TextView 中。

7、在清单文件中配置 <queries>

如果只是上面的内容及配置,在高版本的 Android 系统中运行是无法调起远端 Service 的,因为 Android 11 版本对手机已安装应用的包可见行做了限制。

如果不配置的话,则客户端应用无法发现服务端应用,导致无法调起。

配置如下:

包可见行定义有两种方式。

-> 定义 action 可见。

即只对服务端某个 Service 的 action 配置可见。配置好后,客户端就可以通过 action 隐私启动绑定服务端的 Service 了。

<!-- 定义某个 app 的某个 action 可见 -->
<intent><action android:name="com.fffffff.aidlserver.MY_SERVICE_CENTER" />
</intent>

-> 定义应用的包名可见。

即针对某个应用的包名可见。

拿本例说,不是服务端的 aidl Module 的包名,也不是服务端的 Service 类所在的 Module 的包名。而是 Service 类所在的可运行的 Module,即 app Module 的包名。

<!-- 定义某个 app 应用的包名可见 -->
<package android:name="com.fffffff.aidl_server_test" />

六、测试步骤和效果

1、 安装 Servcie 类所在的应用

注意:杀死服务端 app,无需提前启动服务端

2、安装客户端应用

3、启动客户端应用

TextView 显示默认的内容

4、点击客户端 Activity 的 TextView,异步获取服务端的内容

客户端已经成功获取服务端返回的数据了。

>>>>>>>> 完毕 <<<<<<<

七、测试环境

当前测试环境的详情如下:

Android Studio 版本:Android Stuido Giraffe | 2022.3.1 Patch 1

Gradle::8.0

JDK:17

TargetSDK:33

模拟器版本:Pixel 7 Pro API 33

tip:

一开始不要使用真机测试,尤其是定制化的手机,比如小米/华为等。我的 Demo 在小米/华为手机上,一直无法调起服务端 Service,网上查阅资料说是手机系统做限制了,禁止关联启动。

使用 Google 模拟器测试,就可以成功调起。

Demo 代码:

AIDL_Server_test:https://github.com/mengzhinan/AIDL_Server_test
AIDL_Client_test:https://github.com/mengzhinan/AIDL_Client_test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/160774.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

户外运动盛行,运动品牌如何利用软文推广脱颖而出?

全民健康意识的提升和城市居民对亲近自然的渴望带来户外运动的盛行&#xff0c;这也使运动品牌的市场保持强劲发展势头&#xff0c;那么在激烈的市场竞争中&#xff0c;运动品牌应该如何脱颖而出呢&#xff1f;下面就让媒介盒子告诉你&#xff01; 一、 分享户外运动干货 用户…

【微信小程序开发】布局(附有首页布局案例)

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于小程序的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.弹性布局以及相关样式 1.什么是flex布…

jmeter 解决查看结果树响应内容中文乱码问题

jmeter 解决查看结果树响应内容中文乱码问题 查看结果树中&#xff0c;接口响应内容中&#xff0c;包含中文&#xff0c;显示乱码&#xff1b; 临时解决方法&#xff0c;添加BeanShell 后置处理程序&#xff0c;添加内容prev.setDataEncoding("utf-8"); 运行压测…

【22】c++设计模式——>外观模式

外观模式定义 为复杂系统提供一个简化接口&#xff0c;它通过创建一个高层接口(外观)&#xff0c;将多个子系统的复杂操作封装起来&#xff0c;以便客户端更容易使用。 简单实现 #include<iostream>// 子系统类 class SubsystemA { public:void operationA() {std::co…

Linux 的常用命令大全

常用命令 ls:查看目录与文件pwd:显示当前目录cd:切换目录绝对路径与相对路径touch:创建空文件tab :补全ctrl c :重新输入cat:查看文件内容mkdir:创建目录rm:删除cp:拷贝mv:移动或重命名文件和目录man:帮助命令lessheadtailvim:文本编辑grep:搜索指定文本模式或正则表达式ps:显…

Cisdem Video Player for mac(高清视频播放器) v5.6.0中文版

Cisdem Video Player mac是一款功能强大的视频播放器&#xff0c;适用于 macOS 平台。它可用于播放不同格式的视频文件&#xff0c;并具有一些实用的特性和功能。 Cisdem Video Player mac 中文版软件特点 多格式支持&#xff1a;Cisdem Video Player 支持几乎所有常见的视频格…

Apache DolphinScheduler 官方发布3.2.0版本!大数据调度【重磅更新】

今天&#xff0c;Apache DolphinScheduler 3.2.0 版本在万众期待中终于发布了&#xff01;在之前的预告中&#xff0c;包括《重磅预告&#xff01;Apache DolphinScheduler 3.2.0 新功能“剧透”》、《3.2.0 版本预告&#xff01;Apache DolphinScheduler API 增强相关功能》、…

在 rider 里用配置 Perforce(P4)的注意事项

整个配置界面里&#xff0c;关键就配2处位置&#xff0c;但是都有些误导性。 1是连接形参的4个参数都得填&#xff0c;字符集看你项目的要求&#xff0c;这里工作区其实指的是你的工作空间&#xff0c;还不如显示英文的 Workspace 呢&#xff0c;搞得我一开始没填&#xff0c;…

设计模式_迭代器模式

迭代器模式 介绍 设计模式定义案例迭代器模式行为型&#xff1a;关注对象与行为的分离 提供了一种统一的方式来访问多个不同的集合两个集合&#xff1a;使用了不同的数据存储方式 学生 和 警察 查询显示出集合的内容 &#xff0c;使用相同的代码 问题堆积在哪里解决办法不同…

安达发|AI算法全方位打造制造业AI智能化工厂的超级大脑

随着科技的不断进步&#xff0c;人工智能已经成为了我们生活中不可或缺的一部分。在制造业中&#xff0c;AI技术也正在发挥着越来越重要的作用。而APS系统&#xff0c;则是AI技术在制造业中的一个重要应用。 那么&#xff0c;什么是APS系统呢&#xff1f;简单来说&#xff0c;A…

AI 悄然变天:这家平台为何能俘获众多明星大模型「芳心」?

整个AI领域&#xff0c;GPT-4 发布无疑成为载入 AI 史册的大事件。但其还留下来一些发展空间&#xff0c;其不可能把所有的事情都做完。比如&#xff0c;涉及小数、分数的运算&#xff0c;GPT-4 可能给不出正确答案&#xff08;其多位乘法运算准确率仅为 4.3%&#xff09;。 可…

spring java 动态获取consul K/V

spring java 动态获取consul K/V 1.springConsul配置kv路径 spring:cloud:consul:enabled: ${CONSUL_ENABLED:true}host: ${CONSUL_HOST:localhost}port: ${CONSUL_PORT:8500}config:prefix: ${CONSUL_CONFIG_PREFIX:config} #consul kv前缀fail-fast: ${CONFIG_FAIL_FAST:fa…

ORA-12541:TNS:no listener 无监听程序

问题截图 解决方法 1、删除Listener 新建一个新的 2、主机为服务器ip 3、设置数据库环境 只需要设置实例名不需要设置路径 4、服务命名 一样设置为ip 服务名与监听名一直 eg&#xff1a;orcl

Sketch macOS 支持m1 m2 Sketch 2023最新中文版

SketchUp Pro 2023是一款功能强大的三维建模软件&#xff0c;适用于建筑设计师、室内设计师、工程师和其他创意专业人士。以下是SketchUp Pro 2023的一些主要特点和功能&#xff1a; 三维建模&#xff1a;SketchUp Pro 2023允许用户以直观的方式创建三维模型。通过简单的绘图工…

aidl的注意事项

该篇继承自上一篇&#xff0c;上一篇也有一部分的注意事项&#xff0c;这一篇把其他的情况列出 一 客户段和服务端的aidl文件下的package名字要是一样的 二 server中的 manifest中的package名字&#xff0c;这个与上面两个包不能相同&#xff0c;不然在客户端设置intent的pa…

Java每日笔试题错题分析(6)

Java每日笔试题错题分析&#xff08;6&#xff09; 一、错题知识点前瞻第1题第2题第3题第4题 二、错题展示及其解析第1题第2题第3题第4题 一、错题知识点前瞻 第1题 被动引用&#xff08;免初始化&#xff09; 提示&#xff1a; 第2题 本题考查的含义&#xff0c;对于两个引用…

在全志R128上启用USB ADB以及无线ADB配置方法

首先在FreeRTOS的环境下&#xff0c;选择r128_c906_pro&#xff1a; source envsetup.sh lunch_rtos r128s2_pro_c906USB ADB的配置比较常规&#xff0c;注意以下几个驱动的勾选 usb device驱动adb gadget驱动adbd应用 运行menuconfig&#xff0c;选择对应的驱动以及软件包&…

基于YOLO算法的单目相机2D测量(工件尺寸和物体尺寸)三

1.简介 1.1 2D测量技术 基于单目相机的2D测量技术在许多领域中具有重要的背景和意义。 工业制造&#xff1a;在工业制造过程中&#xff0c;精确测量是确保产品质量和一致性的关键。基于单目相机的2D测量技术可以用于检测和测量零件尺寸、位置、形状等参数&#xff0c;进而实…

天锐绿盾透明加密、半透明加密、智能加密这三种不同加密模式的区别和适用场景——@德人合科技-公司内部核心文件数据、资料防止外泄系统

由于企事业单位海量的内部数据存储情况复杂&#xff0c;且不同公司、不同部门对于文件加密的需求各不相同&#xff0c;单一的加密系统无法满足多样化的加密需求。天锐绿盾企业加密系统提供多种不同的加密模式&#xff0c;包括透明加密、半透明加密和智能加密&#xff0c;用户可…

【网络安全 --- win10系统安装】win10 系统详细安装过程(提供资源)

一&#xff0c;资源下载 百度网盘镜像下载地址链接&#xff1a; 百度网盘 请输入提取码百度网盘为您提供文件的网络备份、同步和分享服务。空间大、速度快、安全稳固&#xff0c;支持教育网加速&#xff0c;支持手机端。注册使用百度网盘即可享受免费存储空间https://pan.ba…