车载应用开发基础:Android Automotive 应用限制、多窗口与分屏策略、安全与权限模型
好,我们进入车载应用开发的核心环节。说实话,很多从手机端转过来的开发者,第一次接触 Automotive 都会有点懵——怎么这个不能用、那个被限制了?别急,今天我就带你把这些「坑」一个个填平。
一、Android Automotive 的应用限制
车载系统和手机系统最大的区别是什么?安全。你想想看,手机卡顿顶多被用户骂两句,车载系统卡顿或者崩溃,那可是要出大事的。所以 Google 在 Automotive 上加了很多「紧箍咒」。
1.1 哪些应用类型被限制?
我个人习惯把 Automotive 的应用分成三类:
- 系统级应用:比如 Launcher、SystemUI、Settings,这些是 OEM 定制的核心
- 车载核心应用:比如地图、音乐、电话,这些是驾驶场景刚需
- 第三方应用:通过 Google Play 或其他渠道安装的普通应用
嗯,这里要注意——第三方应用的限制是最多的。我在项目中遇到过,某知名音乐 App 想在车载上做全屏沉浸式播放界面,结果发现根本跑不起来。为什么?因为 Automotive 默认禁止了非系统应用的 SYSTEM_ALERT_WINDOW 权限。
核心限制清单:
- 禁止使用
SYSTEM_ALERT_WINDOW(悬浮窗) - 禁止使用
REQUEST_INSTALL_PACKAGES(静默安装) - 禁止使用
BIND_NOTIFICATION_LISTENER_SERVICE(通知监听) - 禁止使用
MANAGE_EXTERNAL_STORAGE(外部存储管理) - 禁止使用
REQUEST_DELETE_PACKAGES(卸载应用)
1.2 为什么要有这些限制?
说白了,就是怕应用「作妖」。你想想看,如果某个第三方应用弹了个悬浮窗,刚好挡住了导航的关键路口提示,那后果不堪设想。Google 在 PackageManager 里加了一层过滤,所有非系统应用在安装时就会被标记,运行时再检查权限。
我曾经调试过一个案例:某地图 App 在手机上能正常显示悬浮导航,移植到 Automotive 上就闪退。查了半天,原来是 AndroidManifest.xml 里声明了 SYSTEM_ALERT_WINDOW,而 Automotive 直接把这个权限给禁了。解决方案?要么改成系统应用,要么用 CarAppFocusManager 来管理窗口焦点。
二、多窗口与分屏策略
车载屏幕越来越大,12.3寸、15.6寸甚至更大的都有。但屏幕大不代表你可以随便用——驾驶场景下,信息呈现必须「克制」。
2.1 Automotive 的窗口管理架构
Android Automotive 的窗口管理,说白了就是 WindowManager 加上一层车载特有的 CarWindowManager。我画了一张图,帮你理清这个关系:
你看,CarWindowManager 夹在应用和原生窗口管理器之间,它负责做「策略决策」。比如:当前是驾驶模式还是停车模式?导航窗口应该占多大面积?这些都由它说了算。
2.2 分屏策略实战
Automotive 支持两种分屏模式:
| 模式 | 说明 | 典型场景 |
|---|---|---|
| 并排分屏 | 左右各一个应用,比例可调 | 导航 + 音乐 |
| 画中画 | 小窗口悬浮在主应用之上 | 导航 + 视频通话 |
我建议你在开发时,优先考虑 并排分屏。为什么?因为画中画虽然酷,但容易遮挡关键信息。我记得有一次,某 OEM 的客户坚持要用画中画显示导航,结果在高速上小窗口把限速提示给挡住了——嗯,后来他们乖乖改成了并排分屏。
避坑指南: 我曾经在适配分屏时踩过一个坑——onMultiWindowChanged 回调在 Automotive 上触发时机和手机不一样。手机是窗口变化后立即回调,而 Automotive 会等动画完成后再回调。解决方案是监听 CarWindowManager 的 onWindowFocusChanged 来替代。
2.3 如何让你的应用支持分屏?
其实很简单,在 AndroidManifest.xml 里声明:
<activity
android:name=".MainActivity"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout">
</activity>
但光声明还不够。你需要在代码里处理 onMultiWindowChanged,动态调整 UI 布局。比如导航应用在分屏模式下,应该把地图放大、把搜索栏缩小。
三、安全与权限模型
车载系统的安全模型,比手机严格得多。我甚至觉得,Google 把 Automotive 的权限模型设计得有点像「军事化管理」。
3.1 权限分级
Automotive 把权限分成四个等级:
- 普通权限:安装时自动授予,比如
INTERNET - 危险权限:运行时弹窗询问,比如
ACCESS_FINE_LOCATION - 签名权限:只有同签名的应用才能获取,比如
BIND_CAR_SERVICE - 特权权限:只有系统应用才能获取,比如
CONTROL_CAR_CLUSTER
注意: 在 Automotive 上,危险权限的弹窗会被系统拦截。你想想看,如果导航到一半突然弹个权限请求框,司机还得伸手去点——这太危险了。所以 Google 规定,所有危险权限必须在应用首次启动时集中申请,或者通过设置页面静默授权。
3.2 车载特有的权限
除了 Android 原生权限,Automotive 还加了一批车载专属权限:
| 权限名 | 用途 | 等级 |
|---|---|---|
android.car.permission.CAR_INFO |
读取车辆基本信息(VIN、速度等) | 签名 |
android.car.permission.CAR_MILEAGE |
读取里程数据 | 签名 |
android.car.permission.CAR_ENERGY |
读取能源信息(电量、油耗) | 签名 |
android.car.permission.CAR_CONTROL_AUDIO_VOLUME |
控制音量 | 特权 |
android.car.permission.CAR_CONTROL_CLUSTER |
控制仪表盘显示 | 特权 |
我建议你在开发车载应用时,尽量使用签名权限。为什么?因为特权权限需要 OEM 签名,普通第三方应用根本拿不到。而签名权限,只要你跟系统用同一个签名,就能获取。
3.3 权限申请的最佳实践
嗯,这里我要分享一个我自己的经验。很多开发者喜欢在 onCreate 里一股脑申请所有权限,这在 Automotive 上是大忌。为什么?因为用户可能正在开车,突然弹出一堆权限请求,他只能靠边停车来处理。
正确的做法是:
- 延迟申请:等到真正需要某个功能时,再申请对应的权限
- 集中申请:如果必须申请多个权限,放在同一个页面一次性处理
- 提供说明:在申请前,先告诉用户「为什么需要这个权限」
我曾经接手过一个项目,第三方音乐 App 在启动时一口气申请了 8 个权限,结果用户直接给了差评。后来我们改成按需申请,用户满意度提升了 30%。
3.4 安全模型的核心:隔离与沙箱
Automotive 的安全模型,说白了就是「隔离」两个字。每个应用运行在自己的沙箱里,不能访问其他应用的数据。系统服务通过 CarService 暴露接口,应用只能通过 Car 类来调用。
举个例子,你想获取当前车速:
// 错误做法:直接读取系统属性
String speed = SystemProperties.get("car.speed"); // 这行代码会报 SecurityException
// 正确做法:通过 CarService
Car car = Car.createCar(context);
CarInfoManager infoManager = (CarInfoManager) car.getCarManager(Car.CAR_INFO_SERVICE);
float speed = infoManager.getVehicleSpeed();
你看,所有对车辆硬件的访问,都必须经过 CarService。这层封装不仅保证了安全,也让 OEM 可以灵活控制哪些应用能访问哪些数据。
核心要点总结:
- 第三方应用受限严重,系统应用才是「亲儿子」
- 分屏优先用并排模式,画中画慎用
- 权限申请要「按需、延迟、集中」
- 所有车辆数据访问必须通过 CarService
好了,这一章的内容就到这里。记住,车载开发的核心思维是「安全第一,体验第二」。你设计的每一个功能,都要先问自己:这个功能在司机开车时会不会造成干扰?如果会,那就重新设计。