【Android AIDL之详细使用】
Android AIDL之详细使用
- 一级目录
- 概述
- 使用场景
- 语法相关
- 编码实践
- 服务端:
- java文件
- 修改AndroidManifest
- 客户端
- 坑
一级目录
概述
AIDL叫Android接口定义语言,是用于辅助开发者完成Android跨进程编程的工具。
从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板。
设计AIDL这门语言的目的就是为了实现进程间通信。在Android系统中,每个进程都运行在一块独立的内存中,在其中完成自己的各项活动,与其他进程都分隔开来。可是有时候我们又有应用间进行互动的需求,比较传递数据或者任务委托等,AIDL就是为了满足这种需求而诞生的。通过AIDL,可以在一个进程中获取另一个进程的数据和调用其暴露出来的方法,从而满足进程间通信的需求
通常,暴露方法给其他应用进行调用的应用称为服务端,调用其他应用的方法的应用称为客户端,客户端通过绑定服务端的Service来进行交互
使用场景
-
App开发中,webview的优化是个绕不开的,而且与native的相互通信经常会碰到crash情况,webview写到一个单独的进程中,通过aidl通信,就很大程度上避免了这种情况;
-
现在车机开发需求比较大,车机上的app相互通信的情况是比较多的,尤其是与语音的交互,只要需要让语音操作的App都是需要暴露接口给语音模块的;一般的暴露接口都是需要AIDL的方式来暴露;
语法相关
AIDL的语法十分简单,与Java语言基本保持一致,但是需要记住以下几点规则:
-
AIDL文件以 .aidl 为后缀名
-
AIDL支持的数据类型分为如下几种:
- 八种基本数据类型:byte、char、short、int、long、float、double、boolean
- String,CharSequence
- 实现了Parcelable接口的数据类型
- List 类型。List承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
- Map类型。Map承载的数据必须是AIDL支持的类型,或者是其它声明的AIDL对象
- 实现了Parcelable接口的数据类型
-
AIDL文件可以分为两类。一类用来声明实现了Parcelable接口的数据类型,以供其他AIDL文件使用那些非默认支持的数据类型。还有一类是用来定义接口方法,声明要暴露哪些接口给客户端调用,定向Tag就是用来标注这些方法的参数值
-
定向Tag。定向Tag表示在跨进程通信中数据的流向,用于标注方法的参数值,分为 in、out、inout 三种。其中 in 表示数据只能由客户端流向服务端, out 表示数据只能由服务端流向客户端,而 inout 则表示数据可在服务端与客户端之间双向流通。此外,如果AIDL方法接口的参数值类型是:基本数据类型、String、CharSequence或者其他AIDL文件定义的方法接口,那么这些参数值的定向 Tag 默认是且只能是 in,所以除了这些类型外,其他参数值都需要明确标注使用哪种定向Tag。
-
明确导包。在AIDL文件中需要明确标明引用到的数据类型所在的包名,即使两个文件处在同个包名下
编码实践
纸上得来终觉浅,绝知此事要躬行,show your the code;客户端通过绑定服务端的Service的方式来调用服务端的方法,实现模拟登录,获取书籍详情的的功能,实现应用间的数据共享。
服务端:
java文件
先把 service 创建出来
public class AIDLService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}
}
新建一个工程,包名就定义为 com.ze.aidlservice
首先,在应用中需要用到一个 Book 类,而 Book 类是两个应用间都需要使用到的,所以也需要在AIDL文件中声明Book类,为了避免出现类名重复导致无法创建文件的错误,这里需要先建立 BookManager AIDL 文件,之后再创建 Book 类
右键点击app新建一个AIDL文件,命名为 IMyBookManager。

会自动在main目录下生成IMyBookManager aidl文件;

然后我们来定义Book类,包含两个属性,name和price;
public class Book implements Parcelable {private int price;private String name = "";public Book(){}protected Book(Parcel in) {price = in.readInt();name = in.readString();}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int describeContents() {return 0;}public static final Creator<Book> CREATOR = new Creator<Book>() {@Overridepublic Book createFromParcel(Parcel in) {return new Book(in);}@Overridepublic Book[] newArray(int size) {return new Book[size];}};@Overridepublic String toString() {return "\n图书名称:" + name + "\n图书价格:" + price;}@Overridepublic void writeToParcel(Parcel dest, int flags) {dest.writeInt(price);dest.writeString(name);}
}
然后修改IMyBookManager.aidl文件,增加了三个方法,和一个Book的声明,包括服务端需要暴露给客户端一个登录接口,和获取书籍详情,获取书籍价格的方法。

上面说过,在进程间通信中真正起作用的并不是 AIDL 文件,而是系统据此而生成的文件,可以在以下目录中查看系统生成的文件。之后需要使用到当中的内部静态抽象类 Stub
创建或修改过AIDL文件后需要重新makeproject下工程,使系统及时生成我们需要的文件;

现在修改 AIDLService供客户端远程绑定了。
public class AIDLService extends Service {MyBookManager bookManager = new MyBookManager();public AIDLService() {Log.d("jackie","service,AIDLService");}@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d("jackie","service,onbind");return bookManager;}public class MyBookManager extends IMyBookManager.Stub{@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {}@Overridepublic String login(String userName, String pwd) throws RemoteException {Log.d("jackie","service,login");if(userName.equalsIgnoreCase("admin") && pwd.equalsIgnoreCase("123456")){return "success";}return "error";}@Overridepublic Book queryByName(String bookName) throws RemoteException {Log.d("jackie","service,queryByName");Book book = new Book();book.setName(bookName);book.setPrice(100);return book;}@Overridepublic String getBookPrice(String name) throws RemoteException {return name+" :30";}}
}
可以看到, onBind 方法返回的就是 IMyBookManager.Stub 对象,实现当中定义的三个方法。
修改AndroidManifest
客户端要能够找到这个Service,可以通过先指定包名,之后再配置Action值或者直接指定Service类名的方式来绑定Service
如果是通过指定Action值的方式来绑定Service,那还需要将Service的声明改为如下所示:
<serviceandroid:name="com.ze.aidlservice.service.AIDLService"android:enabled="true"android:exported="true"android:process=":remote"><intent-filter><action android:name="com.ze.aidlservice.bookService"/><category android:name="android.intent.category.DEFAULT" /></intent-filter></service>
| 标签名 | 含义 |
|---|---|
| android:enabled | 该服务能否被实例化,默认为true |
| android:exported | 其他应用的组件能否和这个服务交互 |
| 导android:process | 设置独立进程,例如 remote 则进程名为 包名:remote |
我们采用配置 Action 的方案。
还有个需要特别需要注意的点:从Android 11 开始 系统对app的可见性进行了保护,只有部分应用可见所有app。如果系统是11以上,需要在AndroidManifest里面声明
<queries><package android:name="com.ze.aidlservice" /><intent><action android:name="com.ze.aidlservice.bookService" /></intent></queries>
客户端
创建新的工程,包名:com.ze.aidlclient;
首先,需要把服务端的AIDL文件以及Book类复制过来,将 aidl 文件夹整个复制到和Java文件夹同个层级下,不需要改动任何代码。

注意:Book类所在的包名要与服务的的包名相同。
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".FirstFragment"><Buttonandroid:id="@+id/btnConnection"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="140dp"android:layout_marginTop="52dp"android:text="连接服务测试"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:layout_marginLeft="140dp" /><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="56dp"android:layout_marginLeft="56dp"android:layout_marginTop="156dp"android:text="账户:"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><TextViewandroid:id="@+id/textView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="4dp"android:layout_marginLeft="4dp"android:layout_marginTop="52dp"android:text="密码:"app:layout_constraintStart_toStartOf="@+id/textView2"app:layout_constraintTop_toBottomOf="@+id/textView2" /><EditTextandroid:id="@+id/etName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ems="10"android:hint="用户名"android:inputType="textPersonName"app:layout_constraintBottom_toBottomOf="@+id/textView2"app:layout_constraintStart_toEndOf="@+id/textView2"app:layout_constraintTop_toTopOf="@+id/textView2" /><EditTextandroid:id="@+id/etPwd"android:layout_width="wrap_content"android:layout_height="wrap_content"android:ems="10"android:hint="密码"android:inputType="textPassword"app:layout_constraintBottom_toBottomOf="@+id/textView3"app:layout_constraintStart_toStartOf="@+id/etName"app:layout_constraintTop_toTopOf="@+id/textView3" /><Buttonandroid:id="@+id/btnLogin"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="160dp"android:layout_marginLeft="160dp"android:layout_marginTop="40dp"android:text="登录"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView3" /><TextViewandroid:id="@+id/tvBookInfo"android:scrollbarStyle="outsideInset"android:layout_width="303dp"android:layout_height="141dp"android:layout_marginTop="36dp"android:gravity="start|top"android:text="查询到的图书信息:"android:textSize="16dp"android:maxLines="5"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.555"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/etBookName" /><TextViewandroid:id="@+id/textView5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="60dp"android:text="书名:"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/btnLogin"android:layout_marginLeft="16dp" /><Buttonandroid:id="@+id/btnQuery"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"android:layout_marginLeft="20dp"android:text="查询"app:layout_constraintBottom_toBottomOf="@+id/textView5"app:layout_constraintStart_toEndOf="@+id/etBookName"app:layout_constraintTop_toTopOf="@+id/textView5"app:layout_constraintVertical_bias="0.517" /><EditTextandroid:id="@+id/etBookName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="4dp"android:layout_marginLeft="4dp"android:ems="10"android:hint="输入要查询的书名"android:inputType="textPersonName"app:layout_constraintBottom_toBottomOf="@+id/textView5"app:layout_constraintStart_toEndOf="@+id/textView5"app:layout_constraintTop_toTopOf="@+id/textView5"app:layout_constraintVertical_bias="0.538" /></androidx.constraintlayout.widget.ConstraintLayout>
核心代码:
public class FirstFragment extends Fragment {private FragmentFirstBinding binding;private boolean islogin=false;private IMyBookManager bookManager = null;private ServiceConnection conn = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {Log.d("jackie","client,onServiceConnected");bookManager = IMyBookManager.Stub.asInterface(service);Toast.makeText(getContext(), "服务连接成功!", Toast.LENGTH_SHORT).show();}@Overridepublic void onServiceDisconnected(ComponentName name) {Log.d("jackie","client,onServiceDisconnected");bookManager = null;}};@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {binding = FragmentFirstBinding.inflate(inflater, container, false);return binding.getRoot();}private void connect() {binding.btnConnection.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.d("jackie","client,btnConnection click");if (bookManager != null) {Log.d("jackie","client,btnConnection click bookManager != null");Toast.makeText(getContext(), "服务连接成功!", Toast.LENGTH_SHORT).show();} else {Log.d("jackie","client,btnConnection click bookManager == null");Intent intent = new Intent();intent.setAction("com.ze.aidlservice.bookService");intent.setPackage("com.ze.aidlservice");
// intent.setComponent(new ComponentName("com.yunzhou.aidlserver", "com.yunzhou.aidlserver.MyAidlService"));
// intent.setComponent(new ComponentName("com.ze.aidlservice","com.ze.aidlservice.Service.AIDLService"));
// getContext().bindService(intent, conn, Context.BIND_AUTO_CREATE);boolean isConnet = getContext().bindService(intent, conn, Context.BIND_AUTO_CREATE);Log.d("jackie","isConnet:::"+isConnet);}}});binding.btnLogin.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(bookManager == null){Toast.makeText(getContext(), "还没有绑定服务!", Toast.LENGTH_SHORT).show();return;}if(binding.etName.getText().toString().isEmpty() || binding.etPwd.getText().toString().isEmpty()){Toast.makeText(getContext(), "用户名或密码不能为空!", Toast.LENGTH_SHORT).show();return;}try {String resStr = bookManager.login(binding.etName.getText().toString(),binding.etPwd.getText().toString());if(resStr.compareToIgnoreCase("success") == 0){islogin=true;Toast.makeText(getContext(), "登录成功!", Toast.LENGTH_SHORT).show();} else{Toast.makeText(getContext(), "登录失败!", Toast.LENGTH_SHORT).show();throw new RemoteException("登录失败");}} catch (RemoteException e) {e.printStackTrace();Toast.makeText(getContext(), "登录失败!", Toast.LENGTH_SHORT).show();}}});binding.btnQuery.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(bookManager == null && islogin ){Toast.makeText(getContext(), "请先绑定服务并登录!", Toast.LENGTH_LONG).show();return;}if(binding.etBookName.getText().toString().isEmpty()){Toast.makeText(getContext(), "请输入您要查找的图书!", Toast.LENGTH_LONG).show();return;}try {Book book = bookManager.queryByName(binding.etBookName.getText().toString());String price = bookManager.getBookPrice("jackie");if(book != null){binding.tvBookInfo.append(book.toString());// binding.tvBookInfo.append(price);} else{throw new RemoteException("查询失败!");}} catch (RemoteException e) {e.printStackTrace();binding.tvBookInfo.append("查询失败!");}}});}public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);connect();}@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;}}
测试结果:



我们说一下定向tag:
AIDL 定义的接口文件,使用 in、out、inout 方向标签表明数据流向:
原始类型、String、IBinder 参数以及 AIDL 生成的接口参数 只能 用 in 修饰,可以不显式地写出来。
其他类型参数,主要是 Parcel 类型和 List、Map 类型,支持 out、inout,必须显式写出来。
大家只要自己试一下这些参数,并 Build 生成下 Java 文件,就可以发现它们的区别:
- in:Proxy 端流向 Stub 端,Proxy 端将数据写入 Parcel,通过 BinderDriver 后,Stub 端从 Parcel 中读取。
- out:Stub 端流向 Proxy 端,Proxy 端不传递此参数,Stub 端创建实例,执行方法后,将更新后的参数写入 Parcel,Proxy 端从 Parcel 中先读取 Reply,再读取更新后的参数。
- inout:Proxy 端写入,Stub 端读取后,执行方法,将更新后的参数传回,Proxy 再读取更新后的参数。
可以参考「Android Binder」AIDL中的 in / out 到底是啥?
坑
最后在强调一下:
从Android 11 开始 系统对app的可见性进行了保护,只有部分应用可见所有app。如果系统是11以上,需要在AndroidManifest里面声明queries,要不然客户端会拉不起服务。
讲到这里基本使用已经讲完,喜欢的点赞支持!
相关文章:
【Android AIDL之详细使用】
Android AIDL之详细使用一级目录概述使用场景语法相关编码实践服务端:java文件修改AndroidManifest客户端坑一级目录 概述 AIDL叫Android接口定义语言,是用于辅助开发者完成Android跨进程编程的工具。 从某种意义上说AIDL其实是一个模板,因…...
ASP.NET MVC | 简介
目录 前提 1.教程 2.MVC 编程模式 最后 前提 在学习学过很多课程,但是最主要学的还是ASP.NET MVC这门课程,工作也是用的ASP.NET MVC,所以写一点ASP.NET MVC的东西,大家可以来看看,我自己不会的时候也不用找别的地方…...
95后刚毕业2、3年就年薪50W,才发现,打败我们的不是年龄····
一刷朋友圈,一读公众号,一打开微博,甚至是一和朋友聊天,这些让人焦虑的话题总会铺天盖地的袭来: Ta刚毕业半年,就升职加薪当上了测试主管 (同样是一天24小时,为什么同龄人正在抛弃…...
动态分析和静态分析最主要的区别是什么?
动态分析和静态分析主要的区别是什么? 动态分析和静态分析的主要区别是是否考虑时间因素。 动态分析(dynamic analysis)是相对于静态分析来讲的,动态分析是只改变一下自变量,因变量相应的做出的改变,动态改…...
WebUI 学习笔记
WebUI 学习笔记 背景此插件主要用于在数字孪生方向做 UI 显示的效果。比如一些温度曲线需要显示出来,可以直接用插件,配合html 文件,直接显示出来。 准备工作我们采用4.27 版本进行开发;...
C# 中常见的设计模式附带代码案例
设计模式是一套被广泛应用于软件设计的最佳实践,它们可以帮助开发者解决特定的问题,提高代码的可重用性、可读性和可维护性。本文将介绍 C# 中常见的几种设计模式,并提供相应的示例代码。 工厂模式 工厂模式是一种创建型设计模式,…...
秋招面试问题整理之机器学习篇
文章目录随机森林在决策树的哪些方面做出了改进随机森林里每棵树的权重不一定会变成什么模型方差和偏差,正则化解决的是方差大还是偏差大的问题正则化的方法总结了解VC维吗svd了解吗随机森林在决策树的哪些方面做出了改进 回答思路: 随机森林和决策树有…...
SuperMap超图使用简单笔记
1 需求: 项目使用的是openlayer和Cesium,现在需要使用超图的图层,和引入实景公路功能。 2 使用过程中出现一下疑问点记录如下 : 超图: 北京超图软件股份有限公司是全球第三大、亚洲最大的地理信息系统(G…...
从0探索NLP——神经网络
从0探索NLP——神经网络 1.前言 一提人工智能,最能想到的就是神经网络,但其实神经网络只是深度学习的主要实现方式。 现在主流的NLP相关任务、模型大都是基于深度学习也就是构建神经网络实现的,所以这里讲解一下神经网络以及简单的神经网络…...
计算机操作系统和进程
✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 ✨每日一语:心平能愈三千疾,心静可通万事理。 目 录🐬一. 操作系统🍦1. 操作系统是什么?🍨2. 操作系统的两个…...
JAVA服务端实现页面截屏(附代码)
JAVA服务端实现页面截屏适配需求方案一、使用JxBrowser使用步骤:方案二、JavaFX WebView使用步骤:方案三、Headless Chrome使用步骤:综上方案对比记录我的一个失败方案参考适配需求 有正确完整的地址url;通过浏览器能打开该url对…...
Java入门要知道!
首先我们都知道的是Java是一门面向对象的编程语言,不仅吸收了C语言的各种优点,还摒弃了C里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向…...
[6/101] 101次软件测试面试之经典面试题剖析
01、自我介绍答:大家好,我是一名软件测试工程师,但我更喜欢称自己为“软件bug捕手”。我相信,软件测试工程师的使命就是让软件更加健壮、更加可靠、更加美好。我们就像是一群“特警”,在黑暗的代码中寻找漏洞和缺陷&am…...
电脑c盘满了变成红色了怎么清理,清理c盘详细攻略
我们的电脑当用了一段时间之后,其实自然而然的就会有一点点卡,其实这是因为我们的电脑c盘满了,所以会造成卡顿是正常的,今天我们就来聊一聊电脑c盘满了变成红色了怎么清理? 一.电脑c盘为啥会满 软件安装:当…...
现在的00后,实在是太卷了
现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天,原来这位小老弟家里条…...
RocketMQ概述
RocketMQ入门学习MQ概述MQ简介MO用途限流削峰异步解耦数据收集常见的MQ产品ActiveMQRabbitMQKafkaRocketMQ对比MQ常见协议JMSSTOMPAMOPMQTTMQ概述 MQ简介 MQ,Message Queue,是一种提供消息队列服务的中间件,也称为消息中间件,是…...
解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题
解决Ubuntu22.04.1上安装ch34x串口驱动报 Key was rejected by service 需要签名的问题问题官网下载解压驱动包编译安装给驱动签名再来载入模块(设备驱动程序)问题 Ubuntu22.04.1 Linux版本5.19.0-32-generic 运行Qt串口通信 m_serialPort->open(QIO…...
[python入门㊿] - python如何打断点
目录 ❤ 什么是bug(缺陷) ❤ python代码的调试方式 ❤ 使用 pdb 进行调试 测试代码示例 利用 pdb 调试 退出 debug debug 过程中打印变量 停止 debug 继续执行程序 debug 过程中显示代码 使用函数的例子 对函数进行 debug 在调试的时候动态改变值 ❤ 使用 PyC…...
CCNP350-401学习笔记(501-550题)
501、Refer to the exhibit. What is the effect of the configuration? A. The device will allow users at 192.168.0.202 to connect to vty lines 0 through 4 using the password ciscotestkey B. The device will allow only users at 192 168.0.202 to connect to vty …...
音箱上8键触摸芯片绿芯GTC08L完美替换启攀微
由工采网代理提供的韩国GreenChip电容式触摸芯片-GTC08L是GreenTouch5CTM电容式触摸传感器系列之一;可以在发动机运行下进行8通道电容传感;对电磁兼容、电磁干扰、温湿度变化、电压干扰、温度漂移、湿度漂移等都有较强的抗干扰能力。不会对CS, RS,EFT&am…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
