当前位置: 首页 > news >正文

一文了解 Android Auto 车载开发~

作者:牛蛙点点申请出战

背景

我的的产品作为一个海外音乐播放器,在车载场景听歌是一个很普遍的需求。在用户反馈中,也有很多用户提到希望能在车上播放音乐。同时车载音乐也可以作为提升用户消费时长一个抓手。

出海产品,主要服务于海外用户。不同于国内的 Android 车载系统,往往是定制的 ROM,国外的 Android 车载也是 Google 一家独大,主要可以分为 Android Auto、Automotive OS。Android Auto 可以理解为是一套将手机应用「投屏」在车载屏幕上的方案,和 iOS 的 CarPlay 类似。而 Automotive OS 则类似于国内的定制 ROM。如果要支持 Automotive OS,那我们可能要重头开发一个适配大屏的 mini 版 app,那样工作量很大。所以我们第一步先从支持 Android Auto 开始

准备知识

Android Auto 支持多种类型的应用,包括导航、媒体、消息应用等。音乐播放器属于媒体应用,因此下面给出的参考仅限于媒体应用。

Android Auto 的适配需要做提前了解做一些准备知识,具体如下:

  • 官方文档

    • 构建车载媒体应用
      教你明白 Android Auto 开发媒体应用的各种概念以及如何开发。这个网址的中文翻译可读性很差,建议直接看英文。另外,如果要开发的是导航类应用而不是媒体应用,那可以直接使用 androidX 的 Car Library
    • 测试 Android Automotive OS 应用
      教你如何使用车机模拟器(DHU)配合手机上的 Android Auto app 来测试 Auto 应用。但是文档里有个坑点,文档里默认你的手机是 Pxiel 系列,Pxiel 系列是自带 Android Auto app 的,但是国产手机基本都没有这个 app,需要自己去下载然后安装在手机上。可以去 这里下载。另外 Android Auto app 第一次启动的时候会安装好几个谷歌服务,华为手机因为 ban 掉了google,这一步在华为手机上会失败。所以华为手机没法用来测试 Android Auto。推荐尽量使用 Pixel 系列手机来测试,避免测试过程中遇到奇奇怪怪的问题。
  • 车载设备

    • 业务功能的测试,一般使用模拟器 DHU 就可以。但是在应用发布之前,我们肯定要在真实设备上充分测试。如果你有带 Android Auto 的真车的话,直接用真车测试就行。但是国内带 Android Auto 的车比较少,大概率是没有真车可供测试的。可以去闲鱼上单独购买一个车载主机(闲鱼搜索「187b主机」即可)。
    • 还有一个坑点,应用没有经过 google play store 分发的话,在真实车机设备上是不会显示的。这个问题官方文档没有明确提到,导致当时我们 debug 的时候莫名其妙的花了很久的时间。
    • 这里顺带提一下,谷歌分发渠道有四个,internal、closed testing、open testing、production,分别对应内部、内测、公测、产品。当然,我们不可能为了测试直接提 play store 的 production 渠道,用 internal 分发渠道用作真机测试就可以了。closed testing 和 open testing 渠道也可以。
  • 质量规范

    • developer.android.google.cn/docs/qualit…
      因为车载场景事关驾驶员生命安全,所以 google 对 Android Auto 应用审核很严格。所有支持 Android Auto 的应用,必须满足上面链接中的质量规范才可能通过 Play Store 的审核。这个规范要求的点很多,坑也不少,后面还会说到。这里面很重要的一点是必须支持语音搜索歌曲起播,这是审核强卡的一个点。
  • 官方 demo

    • 因为文档讲得很晦涩,照着文档大概率是依然很难上手开发的。可以参考 google 官方的音乐播放器 uamp,虽然这个 demo 很简单,但是它也支持 Android Auto,有不懂的开发细节都可以参考这个 demo。
  • Android Auto app(包名为 com.google.android.projection.gearhead

    • 想要把 android auto 连上车机跑起来,必须要在手机上安装 Android Auto app,在 这里 下载。大部分国内的 rom 是不带这个 app 的,要自己手动安装。pixel 系列手机是自带的,可以在设置中搜索到这个应用。

如何开发

基本概念

首先,Android Auto 是不支持自定义 UI 的,你的应用投屏到车机上,UI 展示已经在车机内部写死了,你能做的只是把数据传到车机上。所以支持 Auto 的应用在车机上看起来都差不多。Auto 只允许你在播控界面的自定义操作里添加自定义图标。

其次,整个车机的播放流程涉及到三个部分,播放器应用、android auto app、车机。

另外还有几个概念我们要了解

  • MediaBrowserService
    • 指的就是音乐播放器的 Service。在 Service 里通过覆写 onGetRootonLoadChildren 等方法对外提供车机所需要展示的数据。相当于「媒体生产者」,该生产者由你的 app 的提供。
  • MediaBrowser
    • 展示、消费你从上面的 MediaBrowserService 拿到的数据。手机上的 Android Auto app 内部包含了这个类。这个类会来主动 binds 上面提到的的 MediaBrowserService。相当于「媒体消费者」,就是 Android Auto app。
  • MediaSession
    • MediaSession 就是 app 和车机之间进行交互的桥梁。实际上 app 和车机不是直接连接进行通信。app 是和 Android Auto app 进行 IPC 通信,Android Auto 再和车机进行通信。MediaSession 本质上就是一个对 IPC 的封装。这个封装不仅能和车机通信,还可以和耳机线控等外部设备进行通信。这些外部设备共用一个 MediaSession。

  • MediaItem、MediaMetadata、MediaDescription
    • MediaItem 代表了车机屏幕上的一个媒体元素,比如某一个页面,一首歌,一张专辑等等,在这个类中对应的属性设置成什么,车机上屏幕上就显示什么。
    • MediaMetadata 代表 MediaItem 中各个属性对应的值,用来构造 MediaDescription。MediaItem 持有 MediaDescription 用以描述该媒体元素该如何在车机上展示。
  • BROWSABLE 和 PLAYABLE
    • 这个一个枚举标记,车机上每一个 MediaItem 要么是 BROWSABLE 的,要么是 PLAYABLE 的。
    • PLAYABLE 意味着该 MediaItem 可播,这样当你在车机屏幕上点击该 MediaItem 时,会直接进行播放。这种 MediaItem 一般是歌曲,可直接起播。
    • BROWSABLE 意味着该 MediaItem 是可浏览的,也就是说点击该 MediaItem 时,会加载一个新的媒体集合用于展示。比如专辑、歌单等,点击的时候会进入一个新的页面展示歌曲列表。

上面就是做 Android Auto 开发需要理解的基本的概念,可以理解为一套车机的框架,把手机和车机交互中的各个角色都定义好了。我们的工作就是在这套框架上开发我们的业务。

车机连接手机

  • 真车上和模拟器上都可以参考官方文档 developer.android.com/training/ca…
  • 或者可以下载这个压缩包,运行 main.py 即可。该脚本把上述文档里的操作步骤都集成进去了。
  • 连上以后,音乐自动会从车机上播放,像耳机连上手机之后音频自动从耳机播放一样。不需要额外在代码中设置。

检测连接

  • 这是 auto 开发中的一个坑点。以往有一个方法可以检测手机是否处在车载模式,但是该方法只对 android 12 以下的系统生效,android 12 上无效:
public static boolean isCarUiMode(Context c) {
UiModeManager uiModeManager = (UiModeManager) c.getSystemService(Context.UI_MODE_SERVICE);if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {LogHelper.d(TAG, "Running in Car mode");return true;} else {LogHelper.d(TAG, "Running on a non-Car mode");return false;}
}
  • 官方有一个新的 CarLibrary 「androidx.car.app:app」,这个库中使用 CarConnection 类来检测车机和手机的连接。
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)

但是该方法只适合于 android 6-12 的系统,并且我们只想使用连接检测,导入整个库的话未免显得太笨重。

  • 基于上述 CarLibrary 「androidx.car.app:app」的方法,我们把核心代码抽出来即可。具体代码我在 stackoverflow 上贴出来作为一个回答,也被采纳了。对于 android 5 的系统,使用前述的 isCarUiMode 方法即可。

工作原理

如前面 MediaSession 的介绍所述,这个工作过程涉及到车机、android auto app、应用三方。为了叙述方便,后面提到的「车机回调客户端方法」实际上均是中介作用的 Android Auto App 通过 IPC 完成的。

下文中的 PlayerService 指的是应用中用于播放音乐的 Service。

整体的工作流程如下面的时序图所示,后面会逐一解释。

bindService
  • 当我们的车机和手机连接上之后,Android Auto app 就会主动地 bind 我们的 PlayerService。因此 Service 必须声明 android:exported="true" ,这样才可以被外部拉起。同时整个 app 进程也被拉起了。

页面树
  • 整个车机屏幕的 UI 可以看做一个页面树,客户端应用负责把定义各个页面树的节点 ID 和传输节点数据对应的 MediaItem。而车机在拿到这些数据以后就可以渲染屏幕 UI。
  • 车机通过 IPC 回调到客户端代码中的 onGetRoot() 方法和 onLoadChildren() 方法来获取页面 ID 和数据。接下来详细说下这两个方法。
  • 页面树的节点 ID 可以自己定义,只要保证每个节点对应唯一的 ID 即可。
  • 一般来说,叶子节点是 PLAYABLE 类型的 MediaItem,而非叶子节点对应 BROWSABLE 类型的 MediaItem。
onGetRoot()
override fun onGetRoot(clientPackageName: String,clientUid: Int,rootHints: Bundle?
): MediaBrowserServiceCompat.BrowserRoot
  • onGetRoot 是车机和手机交互的入口方法,只要车机和手机连接上了,就会回调这个方法。在这个方法中,需要构造一个 BrowserRoot 返回,作为车机页面树的根节点。整个页面树构造 BrowserRoot 需要传入 rootId。
  • clientPackageName – 是唤起客户端是包名,一般来说是 Android Auto App,包名是 com.google.android.projection.gearhead。但是有时候通过语音搜索播歌唤起客户端,包名就是 com.google.android.googlequicksearchbox,是 google 语音助手。通过这个参数可以过滤你认为有效的包名。
  • 其他两个参数一般用不上。
onLoadChildren()
override fun onLoadChildren(parentMediaId: String,result: Result<List<MediaItem>>
)
  • onLoadChildren 方法一旦被回调,说明在车机上真正开始加载手机客户端对应的车机页面树了。所以这个方法可以认为是车机端的 launch 点,可以用这个方法统计车机 DAU。
  • parentMediaId – 之前我们会在 onGetRoot 中返回了 rootId,接下来车机会回调 onLoadChildren, rootId 就会作为该方法的 parentMediaId 传入,代表在此次 onLoadChildren 方法回调中我们需要加载 parentMediaId 对应的页面树节点对应的 List,也就是页面树中该节点的子节点。
  • 加载好了子节点后,以 List 的形式,通过 result.sendResult(List) 方法将结果返回给车机。

整体的页面树如上所示。当在车机上点击蓝色子节点时,会回调 onLoadChildren 加载下一级子节点。当点击绿色叶子节点时,会回调 onPlayFromMediaId 方法进行起播。下面详细介绍。

MediaSession.Callback
  • MediaSession.Callback 是用户在车机上进行起播、播控以及语音搜索等操作的回调。该抽象类中包含了一系列的回调方法。下面介绍一些重要的回调方法。
  • 通过 mediaSession.setCallback 方法设置回调。
public abstract static class Callback { public boolean onMediaButtonEvent(Intent mediaButtonEvent) {}// 线控耳机回调public void onPlay() {} // 播放public void onPause() {} // 暂停public void onPlayFromMediaId(String mediaId, Bundle extras) {} // 起播public void onPlayFromSearch(String query, Bundle extras) {} // 语音搜索public void onSkipToQueueItem(long id) {} // 切到播放队列中的某一首歌public void onSkipToNext() {} // 切到下一首public void onSkipToPrevious() {} // 切到上一首public void onCustomAction(String action, Bundle extras) {} // 自定义操作....
}
MediaSession.setPlaybackState
  • 当我们执行了上述回调后,如何通知车机进行播放页的 UI 更新呢?这时候就需要调用 MediaSession.setPlaybackState 方法来通知车机更新 playback 的状态和 UI。PlaybackState,顾名思义,就是车机播放状态,所以改变这个状态意味着车机播控页 UI 也会更新。
  • 该方法具体如何使用可以参考 UMAP demo 和官方文档,这里不展开了。
onPlayFromMediaId
  • 上面我们说到,当用户在车机屏幕上点击歌曲起播时,就会回调该方法,并将构建页面树时赋予的 id 作为 mediaId 参数传入。因此,在该方法中我们需要调用客户端的起播歌曲的方法来起播。
onPlay 和 onPause
  • 这两个方法对应车机上的播放和暂停操作。
onSkipToNext 和 onSkipToPrevious
  • 这两个方法对应车机上的切下一首和切上一首操作。
onSkipToQueueItem
  • 在车机上切换到当前队列里的某一首歌,会回调该方法。传入对应的歌曲 id。
  • 在队列切歌之前,需要先给车机构造队列。调用 mediaSessionCompat.setQueue(List) 即可。
onPlayFromSearch(String query, Bundle extras)
  • 当我们在车内使用语音助手起播歌曲时,比如说 「播放周杰伦的夜曲」,会回调该方法。并且将语音内容识别成文字,分词后将 「周杰伦 夜曲」 通过入参 query 传入。这样我们拿到 query 字符串后,调用客户端的搜索服务就可以获得搜索的歌曲结果,并将该结果起播即可。
onCustomAction(String action, Bundle extras)
  • 当你想在车机播控界面添加其他自定义的操作,比如收藏歌曲、单曲循环等,就会用到这个方法。
  • 首先需要在构造 PlaybackState 的时候传入你定义的自定义操作,通过 PlaybackStateBuilder.addCustomAction(CustomAction action) 方法完成。构造 aciton 时需要传入唯一的标识字符串。在刷新了 PlaybackState 之后,在车机的播控界面就会出现自定义的操作按钮。
  • 当在车机屏幕点击了自定义操作按钮后,会回调 onCustomAction 方法,入参 action 就是唯一标识字符串,根据该字符串来区分不同的自定义操作。

开发中的坑

Android Auto 在国内渗透率不高,所以大部分开发者对这个东西很陌生,我也是。并且很多国产 ROM 系统层就不支持 Android Auto。作为国内业界少数 Android Auto 的应用,在开发过程中经历了资料匮乏、机型兼容、审核被拒等很多坑。这里把之前开发踩坑的经历分享出来。

图标缓存

车机界面每个 tab 的 icon 在设置完之后是会有在车机里缓存的。如果修改了 icon 样式,一定要改掉对应的 drawable 的 id,不然车机会从缓存中取图片,icon 修改不生效。

机型不兼容

很多国产的 rom 对 Android Auto 的支持有问题。具体表现有:

  • 无法安装 GMS 导致无法使用 Android Auto App,以华为系手机为代表。
  • 可以安装并且运行 Android Auto App,但是一旦连上 DHU 测试的时候,DHU 就一直黑屏,无法正常运行。亲测小米 11 、vivo S15 机型有该问题。
  • 可以连接 DHU,可以正常运行,但是使用 debug 包在测试的时候,DHU 上不会显示应用。只有使用 GP 商店分发的包才能显示出来。 部分 vivo 手机有这个问题。

所以,最好使用 pixel 这样的原生系统进行测试。

GP 分发

当我们在 DHU 上测完,想使用真实车机进行测试的时候,却发现真车上不显示我们的应用。正如之前所述,在真车上测试,需要经过 GP 分发的包才行,没有经过 GP 分发过的包,即使是 release 包也不行。这个坑当时困扰了我们很久,最后我们也是靠猜测才猜出原因。后来我们和 google 官方进行沟通,也确认了这一点。但是坑爹的是,google 文档里完全没有提及这一点。

语音搜索

语音搜索这个功能,在 DHU 上经常莫名其妙地不好用。具体有

  • 识别不出语音,语音助手回复 「对不起,我没有听懂」
  • 识别成别的应用,比如无论你怎么说 「使用 xxx 播放音乐」,它都回复 「好的,我来让 youtube music 播放音乐」,然后打开 youtube music 播放音乐
  • 语音说完没有任何反应。比如你说 「播放音乐」,在语音助手的对话框消失后就没有任何反应了,也没有回复,也不会打开应用播放。
  • 识别率差。我们的应用名,经常会识别错。但是像 Spotify、微信等应用名,识别率很高。怀疑是 google 语音助手对特定应用名识别做了优化。 上面这些坑是在做语音搜索功能时经常遇到的。QA 在测的过程中也会经常遇到并且反馈 bug 给我。但大部分时候都是语音助手抽风。

如何判断到底是 bug 还是语音助手抽风呢,可以用同样的语音去试下其他应用,比如 spotify 和 YT music。如果也有同样的问题,那么可以认为是语音助手又抽风了。

审核

Google 商店对车载应用的审核标准很高。详见 质量规范,其中对车载应用需要满足什么样的条件做了严格的要求。对于音乐类应用,有几点容易忽视的需要格外关注:

  • 必须支持语音搜索播歌功能。google 认为,用户在开车时不能分散注意力,所以必须提供语音搜索播歌的功能,让用户可以开车的同时按下方向盘上的麦克风按钮,直接语音控制歌曲的播放。如果这个功能没满足,应用不能过审。

  • 歌曲播放时,如果手机上碰到阻塞,比如出需要手动关闭的广告、出弹窗、请求权限,必须让用户转到手机上处理时,这时候必须要在车机屏幕上提示用户。这时可以使用错误提示的 API 来做提示。

  • 添加特定的 Intent Filter
<activity ...><intent-filter><action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

一定要在启动 Acitivity 里面添加这个 intent-filter,用来兼容古老版本的 android 手机语音播歌。可以参考

这个点其实在 google 官方文档里有提,但是没有明确说必须要有,只是建议添加。但是如果不加的话,应用审核会被拒绝。所以这里也是个坑点。

总之,成为一名Android车载开发工程师需要深厚的技术功力,同时他们需要不断学习并更新专业知识和技能,以应对未来Android车载应用市场的不断变化,并更好地实现车载应用的创新和发展。

针对车载Android 开发所需要学习的内容,整理了以下的知识路线

路线有了,那自然参考的学习文档笔录也不会少,大家可以参考:https://qr18.cn/F05ZCM

Android 车载学习手册:

  • 第一章——Android Auto概述
  • 第二章——开发汽车媒体应用
  • 第三章——构建 Android Auto即时通信应用
  • 第四章——构建车载导航和地图的注点应用
  • 第五章——构建 Android Automotive OS 视频应用

相关文章:

一文了解 Android Auto 车载开发~

作者&#xff1a;牛蛙点点申请出战 背景 我的的产品作为一个海外音乐播放器&#xff0c;在车载场景听歌是一个很普遍的需求。在用户反馈中&#xff0c;也有很多用户提到希望能在车上播放音乐。同时车载音乐也可以作为提升用户消费时长一个抓手。 出海产品&#xff0c;主要服务…...

Pixel4 安卓源码及内核修改编译教程 | 基于Android12 AOSP

之前整理了 Pixel4上的源码过程&#xff0c;下载的话大家可以去镜像网站下载&#xff0c;可以节约很多时间。 实验设备&#xff1a;Ubuntu18.04 32G2T Pixel4 文章目录 一、安卓源码下载1.准备下载环境&#xff08;1&#xff09;安装Python 3.9&#xff08;2&#xff09;安装g…...

如何做好Code Review

本文主要从我们为什么需要CR&#xff1f;CR面临哪些挑战&#xff1f;CR的最佳实践几个方面分析&#xff0c;希望可以给读者一些参考。 为什么需要CR&#xff1f; 代码质量 定性来看&#xff0c;大家都认可Code Review&#xff08;后文简称CR&#xff09;能显著改善代码质量&…...

Unity技术框架集合、Unity技术栈汇总

引擎技术尝试 [Animancer-Pro] (https://assetstore.unity.com/packages/tools/animation/animancer-pro-116514) (基于Playable的简单强大的动画解决方案)[ProBuilder/UModeler] (https://assetstore.unity.com/packages/tools/modeling/umodeler-80868) (快速关卡原型构建…...

安卓SDK开发的一些疑问

目前&#xff0c;公司需要开发一套iOS和安卓的sdk&#xff0c;主要包含蓝牙管理、网络请求、倒计时等方案执行、蓝牙数据交互等功能。之前没有过开发安卓sdk的经历&#xff0c;写个笔记用以记录。 现在iOS sdk已经写了一部分&#xff0c;安卓开发我也习惯从iOS的角度类比来开发…...

【基础类】—三栏页面布局的方案和优缺点

一、假设高度已知&#xff0c;中间宽度自适应&#xff0c;三栏&#xff08;列&#xff09;布局的方案有哪些&#xff1f; float浮动、absolute绝对定位、flex弹性盒子、table表格布局、grid网格布局 浮动 float <style>* {margin: 0;padding: 0;}.container {width: 1…...

OPENCV C++(四)形态学操作+连通域统计

形态学操作 先得到一个卷积核 Mat kernel getStructuringElement(MORPH_RECT,Size(5,5)); 第一个是形状 第二个是卷积核大小 依次为腐蚀 膨胀 开运算 闭运算 Mat erodemat,dilatemat,openmat,closemat;morphologyEx(result1, erodemat, MORPH_ERODE, kernel);morphologyEx…...

tomcat上部署jpress

一.确保有jdk&#xff0c;tomcat和mysql环境 二.新建jpress数据库&#xff0c;新建jpress用户并赋予所有权限 三.将jpress的war上传到tomcat/apache-tomcat-8.5.70/webapps&#xff0c;具体根据你的实际tomcat安装路径为准&#xff0c;上传完成后他会自己解包 四.到浏览器完…...

篇十:外观模式:简化复杂系统

篇十&#xff1a;“外观模式&#xff1a;简化复杂系统” 开始本篇文章之前先推荐一个好用的学习工具&#xff0c;AIRIght&#xff0c;借助于AI助手工具&#xff0c;学习事半功倍。欢迎访问&#xff1a;http://airight.fun/。 另外有2本不错的关于设计模式的资料&#xff0c;分…...

linux gcc __attribute__

__attribute__ 1. 函数属性1.1 __attribute__((noreturn))1.2 __attribute__((format))1.3 __attribute__((const)) 2. 变量属性2.1. __attribute__((aligned))2.2. __attribute__((packed)) 3. 类型属性 __attribute__ 是 GCC 编译器提供的一种特殊语法&#xff0c;它可以用于…...

【SpringCloud】RabbitMQ基础

1.初识MQ 1.1.同步和异步通讯 微服务间通讯有同步和异步两种方式&#xff1a; 同步通讯&#xff1a;就像打电话&#xff0c;需要实时响应。 异步通讯&#xff1a;就像发邮件&#xff0c;不需要马上回复。 两种方式各有优劣&#xff0c;打电话可以立即得到响应&#xff0c;…...

css, resize 拖拉宽度

效果如下&#xff1a; 可直接复制预览查看属性值: 关键样式属性&#xff1a; resize: horizontal; overflow-x: auto; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content…...

Python识别抖音Tiktok、巨量引擎滑块验证码识别

由于最近比较忙&#xff0c;所以本周搞了一个相对简单的验证码&#xff0c;就是抖音Tiktok的滑块验证码&#xff0c;这也是接到客户的一个需求。这种验证码通常在电脑端登录抖音、巨量引擎的的时候出现。 首先看一下最终的效果&#xff1a; 验证码识别过程 1、利用爬虫采集图…...

EvilBox One靶场笔记

EvilBox: One靶场笔记 信息收集 先fscan找主机192.168.1.102 namp扫端口 开放80,22端口 然后扫目录 └─$ gobuster dir -r -u http://192.168.1.102/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,bak,html在扫secret目录&#xff0c;找…...

shell脚本中的export无效

写了一段shell脚本&#xff1a; #!/bin/bash source Tools/simulation/gazebo-classic/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default export ROS_PACKAGE_PATH$ROS_PACKAGE_PATH:$(pwd) export ROS_PACKAGE_PATH$ROS_PACKAGE_PATH:$(pwd)/Tools/simulation/gazebo…...

前沿分享-鱼形机器人

可能并不太前沿了&#xff0c;是21年底的新闻了&#xff0c;但是看见了就顺便发一下吧。 大概就是&#xff0c;通过在pH响应型水凝胶中编码不同的膨胀速率而构建了一种环境适应型变形微机器人,让微型机器人直接向癌细胞输送药物从而减轻药物带来副作用。 技术原理是&#xff0c…...

摄像机终端IP地址白名单配置流程

海康摄像头配置白名单流程 1.登录海康摄像机前端 2.进入配置-系统-安全管理-IP地址过滤 3.IP地址过滤方式选择“允许” 4.点击添加按钮输入对应的IP地址或者IP网段 5.最后勾选启用IP地址过滤&#xff0c;然后保存 大华摄像头配置白名单流程 1.登录大华摄像机前端 2.进入设…...

Glibc—查看版本

方式1&#xff1a;直接查看ldd版本 ldd --versionldd (Buildroot) 2.30 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICU…...

C++物理引擎Box2D的下载,编译,VS2013配置环境

文章目录 网站和下载地址编译工具:编译box2dhelloworld测试网站和下载地址 https://box2d.org/ 下载地址 https://hub.nuaa.cf/erincatto/box2d/tags 编译工具: 1.VS2013 2.cmake 下载地址 https://cmake.org/ 编译box2d 下载box2d源码2.4.0,解压。在box2d-2.4.0目录下…...

STL容器详解——map容器

一、map容器介绍 作为关联式容器的一种&#xff0c;map 容器存储的都是 pair 对象&#xff0c;也就是用 pair 类模板创建的键值对。其中&#xff0c;各个键值对的键和值可以是任意数据类型&#xff0c;包括 C 基本数据类型&#xff08;int、double 等&#xff09;、使用结构体…...

VR全景在建筑工程行业能起到哪些作用?

在建筑工程领域&#xff0c;数字化技术为行业的发展起到巨大的推动作用&#xff0c;虽然建筑施工行业主要是依赖于工人劳动力和施工设备&#xff0c;但是VR全景在该行业中方方面面都能应用&#xff0c;从设计建模到项目交付&#xff0c;帮助建筑师以及项目方更好的理解每个环节…...

P1257 平面上的最接近点对

题目 思路 详见加强加强版 代码 #include<bits/stdc.h> using namespace std; #define int long long const int maxn4e510; pair<int,int> a[maxn]; int n; double d1e16; pair<int,int> vl[maxn],vr[maxn]; void read() { cin>>n;for(int i1;i<…...

8月1日上课内容 第一章web基础与http协议

dns与域名 网络是基于tcp/ip协议进行通信和连接的 应用层--传输层---网络层----数据链路层-----物理层 ip地址&#xff0c;我们每一台主机都有一个唯一的地址标识(固定的ip地址)&#xff0c;区分用户和计算机通信。 ip地址:32位二进制数组成的&#xff0c;不方便记忆 192.168.…...

Gson 添加数据默认值问题记录

问题&#xff1a;在用Gson add(key&#xff08;string类型&#xff09;&#xff0c;value&#xff08;必须是JsonElement子类&#xff09;&#xff09;时发现&#xff0c;value 传了 "" 空字符串&#xff08;非null&#xff09;&#xff0c;默认解析后返回null&#…...

利用Arthas+APM监控进行Java性能深度定位

大家可能都用过APM监控&#xff0c;包括开源的Skywalking、商用的卓豪&#xff08;ZOHO&#xff09;ManageEngine APM应用性能监控、以及云监控产品如听云&#xff08;Server监控&#xff09;&#xff0c;这些APM监控产品大大方便了我们实时监控应用性能&#xff0c;并实现性能…...

【BASH】回顾与知识点梳理(十一)

【BASH】回顾与知识点梳理 十一 十一. 八至十章知识点总结及练习11.1 总结11.2 练习情境模拟题一&#xff1a;透过 grep 搜寻特殊字符串&#xff0c;并配合数据流重导向来处理大量的文件搜寻问题。情境模拟题二&#xff1a;使用管线命令配合正规表示法建立新指令与新变量。 该系…...

vue2-diff算法

1、diff算法是什么&#xff1f; diff算法是一种通过同层的树节点进行比较的高效算法。 其有两个特点&#xff1a; 比较只会在同层级进行&#xff0c;不会跨层级进行。 在diff比较的过程中&#xff0c;循环从两边向中间比较。 diff算法在很多场景中都有应用&#xff0c;在vue中&…...

SpringBoot使用redis作为缓存的实例

目录 什么是缓存&#xff1f; 缓存的作用&#xff1f; 缓存的成本&#xff1f; 实际项目中的应用 代码展示 什么是缓存&#xff1f; 缓存就是数据交换的缓冲区&#xff08;称作Cache [ kʃ ] &#xff09;&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高。 缓…...

vue3使用vue3-seamless-scroll插件

1、局部引入 import vueSeamlessScroll from "vue-seamless-scroll"; 2、注册 components: { vueSeamlessScroll, }, 3、使用 <vue3-seamless-scroll :list"list1" class"scroll" step"0.2"><div class"item"…...

QT开发学习相关笔记

QT中配置文件读取 QT中使用的config文件为&#xff1a;xxx.ini文件,基本格式如下&#xff1a; 使用 QSetting&#xff08;QT自带类&#xff09;中的相关接口实现设置配置文件数据&#xff0c;或者读取数据。 读取配置文件路径设置如下&#xff0c;其中 iniPath为设置路径 ne…...