13、应用开发基础:AAOS应用架构、Car App Library、MediaSession 与 CarMediaService

好,咱们进入第十三章。说实话,到了这里,才算真正开始写车机上的应用。

前面我们聊了系统架构、服务、权限,那些都是基础设施。现在要动手了,你可能会发现——嗯?怎么和手机开发不太一样?

没错,AAOS 的应用开发,有它自己的一套规矩。我当年第一次在车机上写音乐应用,照着手机那套 MediaSession 写完,一跑,直接黑屏。后来才知道,少了 Car App Library 的壳,系统根本不认你。

这一章,我们就来拆解这三块核心:AAOS 应用架构Car App LibraryMediaSession 与 CarMediaService。搞懂它们,你的应用才能在车机上站稳脚跟。

AAOS 应用开发核心知识体系 AAOS 应用架构 Car App Library MediaSession 核心要点 • 分层架构:UI / Service / Provider • 生命周期与车载场景绑定 • 多窗口与分屏适配 核心要点 • 预置 UI 组件(Task、Pane) • 统一导航与搜索栏 • 适配驾驶安全约束 核心要点 • 媒体状态管理 • 与 CarMediaService 通信 • 支持语音与方向盘控制 三者关系 Car App Library 提供 UI 框架 → 应用通过 MediaSession 管理媒体状态 → CarMediaService 负责与系统媒体管道交互

13.1 AAOS 应用架构:别拿手机那套硬套

AAOS 的应用架构,说白了就是「分层 + 约束」。为什么要有约束?因为开车的时候,你不能让用户像玩手机一样随便点。安全第一。

我个人习惯把 AAOS 应用分成三层:

  • UI 层:基于 Car App Library 的组件,比如 Task、Pane。这些组件天然支持驾驶模式下的交互限制。
  • Service 层:后台服务,比如媒体播放、导航计算。这部分要独立于 UI 生命周期。
  • Provider 层:数据提供,比如 ContentProvider 或 CarProvider。用于跨应用共享数据。

嗯,这里要注意:千万不要在 UI 层做耗时操作。我在项目中遇到过,有人把媒体解码直接写在 Activity 里,结果一切歌,界面卡死,用户狂按屏幕——系统直接判定为「不安全操作」,把应用杀了。

核心原则:AAOS 应用的 UI 必须响应驾驶状态。当车辆行驶时,系统会限制触摸交互的复杂度。你的应用必须适配这种「受限模式」。

13.2 Car App Library:车机应用的脚手架

Car App Library 是什么?它是 Google 提供的一套 UI 组件库,专门为车载环境设计。你想想看,如果每个车机应用都自己写导航栏、搜索栏、列表,那得乱成什么样?

Car App Library 帮你搞定了这些:

  • CarToolbar:统一的顶部操作栏,支持返回、搜索、菜单。
  • Task:一个可滚动的列表容器,支持分页和分组。
  • Pane:分屏布局的基础单元,支持左右或上下分栏。
  • CarNavigationView:底部导航栏,用于切换应用内模块。

我记得第一次用 Car App Library 时,最让我惊讶的是它的「驾驶模式适配」。你不需要手动判断车辆是否在行驶,库会自动降低列表的滚动灵敏度、放大触摸目标、隐藏复杂交互元素。省了我不少事。

小技巧:如果你需要自定义 UI,尽量继承 Car App Library 的基类,而不是直接写原生 View。这样能保证你的应用在未来的系统版本中依然兼容。

13.3 MediaSession:媒体应用的心脏

MediaSession 不是 AAOS 独有的,但在车机上,它的地位被放大了。为什么?因为车机上的媒体控制,不只是点屏幕——还有方向盘按键、语音指令、甚至手势。

MediaSession 的核心职责就两个:

  1. 对外暴露媒体状态:当前播放的歌曲、进度、封面、是否可快进等。
  2. 接收外部控制指令:播放、暂停、下一首、快进、语音搜索等。

来看一个最简单的 MediaSession 初始化代码:

MediaSessionCompat mediaSession = new MediaSessionCompat(context, "MyMediaSession");
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                      MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
    @Override
    public void onPlay() {
        // 开始播放
    }
    @Override
    public void onPause() {
        // 暂停播放
    }
    @Override
    public void onSkipToNext() {
        // 下一首
    }
});
mediaSession.setActive(true);

这段代码看着简单,但坑不少。我曾经犯过一个错:忘记在 onDestroy 里释放 MediaSession。结果应用退出了,系统还认为它在播放,方向盘按键依然能控制它——但实际已经崩溃了。嗯,血泪教训。

警告:MediaSession 的生命周期必须与你的媒体 Service 绑定,而不是与 Activity 绑定。Activity 可能因为驾驶模式切换而被销毁,但媒体播放不能停。

13.4 CarMediaService:连接系统媒体管道的桥梁

CarMediaService 是 AAOS 特有的服务。它负责把 MediaSession 的状态同步到系统层面,比如仪表盘、HUD、甚至后排娱乐屏。

说白了,MediaSession 是你的应用内部的心脏,CarMediaService 是连接心脏和全身血管的桥梁。没有它,你的媒体状态只能在应用内看到,系统其他部分根本不知道你在播什么。

使用 CarMediaService 的典型流程:

  1. 应用创建一个 MediaSession。
  2. 应用通过 CarMediaService 的 API 注册这个 MediaSession。
  3. 系统将 MediaSession 的信息广播给所有需要媒体信息的模块(比如仪表盘)。
  4. 当用户通过方向盘按下「下一首」,系统通过 CarMediaService 将指令转发给 MediaSession。

来看一个注册的示例:

Car car = Car.createCar(context);
CarMediaService mediaService = (CarMediaService) car.getCarManager(Car.CAR_MEDIA_SERVICE);
if (mediaService != null) {
    mediaService.registerMediaSession(mediaSession.getSessionToken());
}

这里有个细节:Car 对象的创建是异步的。我见过有人直接在 onCreate 里调用 getCarManager,结果返回 null。正确的做法是等 Car 连接成功后再操作。

避坑指南:我曾经在项目里把 Car 对象创建放在 Application 的 onCreate 中,想着全局复用。结果发现不同进程的 Car 对象不能共享。如果你的媒体 Service 运行在独立进程,记得在每个进程里单独创建 Car 实例。

13.5 三者如何协作:一个完整的媒体播放场景

我们来串一下整个流程。假设用户点击了音乐应用中的「播放」按钮:

  1. Car App Library 的 UI 组件(比如 Task 中的列表项)被点击。
  2. 点击事件触发 MediaSession 的 Callback,调用 onPlay()。
  3. MediaSession 更新内部状态(播放中、当前曲目、进度等)。
  4. CarMediaService 感知到 MediaSession 状态变化,同步给系统媒体管道。
  5. 仪表盘显示当前播放信息,方向盘按键可以控制播放。

你看,每一步都有明确的职责划分。UI 只管展示和交互,MediaSession 只管状态和指令,CarMediaService 只管系统级同步。各司其职,出了问题也好排查。

我个人习惯在调试时,先检查 MediaSession 是否 active,再检查 CarMediaService 是否注册成功。80% 的问题都出在这两步。

调试技巧:用 adb shell dumpsys media_session 可以查看当前所有 MediaSession 的状态。用 adb shell dumpsys car_service 可以查看 CarMediaService 的注册情况。这两个命令我几乎每天都要用。

13.6 总结

这一章我们聊了 AAOS 应用开发的三个核心模块:

  • AAOS 应用架构:分层设计,UI 层必须适配驾驶模式。
  • Car App Library:提供预置 UI 组件,帮你快速搭建符合车载规范的应用界面。
  • MediaSession 与 CarMediaService:一个管内部状态,一个管系统同步,两者缺一不可。

说实话,这三个东西单独拎出来都不难,难的是把它们组合在一起,还要考虑驾驶安全、多窗口、语音控制这些车机特有的场景。但只要你理解了它们各自的职责和协作方式,剩下的就是熟练度的问题了。

一句话总结:Car App Library 搭骨架,MediaSession 管心跳,CarMediaService 通全身。记住这个比喻,你就能在 AAOS 上写出健壮的媒体应用。


公众号:蓝海资料掘金营,微信deep3321