6、Car API 开发实战:获取车辆信息(车速、里程)、控制车辆功能(空调、车窗)
好,咱们进入实战环节了。前面几章讲了那么多理论,什么 CarService、VHAL、Property 的,说实话,光看不动手,很容易忘。我自己带新人时有个习惯——先让他们把车跑起来,哪怕只是模拟器里的车。今天我们就来写点真东西:怎么拿到车速和里程,怎么控制空调和车窗。
你想想看,车载应用和手机应用最大的区别是什么?手机应用是用户主动操作的,而车载应用很多时候是「被动响应」的。比如车速变了,地图要自动缩放;里程到了保养点,系统要弹提醒。这些背后,全靠 Car API 在撑。
6.1 认识 Car API 的核心接口
在 Android Automotive 里,所有车辆相关的操作都通过 Car 这个入口类来获取。拿到 Car 对象后,再通过它拿到各种 Manager。比如:
Car.getCarInfoManager()—— 获取车辆信息(VIN、车速、里程等)Car.getCarHvacManager()—— 控制空调Car.getCarWindowManager()—— 控制车窗(注意,这个不是手机上的 WindowManager)
嗯,这里要注意:不是所有车厂都实现了全部 Manager。我在项目中遇到过,某款车型的空调控制走的是私有协议,根本没走标准的 HVAC API。所以开发前,最好先确认一下车辆支持哪些 Property。
核心原则:Car API 是「读」和「写」的抽象层。读用 getProperty(),写用 setProperty()。但为了方便,Google 封装了更高层的 Manager 接口。
6.2 获取车速和里程
车速和里程属于 VehiclePropertyIds 里的标准属性。车速是 PERF_VEHICLE_SPEED,里程是 ODOMETER。获取方式有两种:
6.2.1 主动读取(一次性的)
如果你只是想在某个时刻看一眼当前车速,用 getProperty() 就行:
Car car = Car.createCar(context);
CarInfoManager infoManager = (CarInfoManager) car.getCarInfoManager();
// 获取车速(单位:m/s,需要转成 km/h)
float speedMs = infoManager.getProperty(
VehiclePropertyIds.PERF_VEHICLE_SPEED, 0);
float speedKmh = speedMs * 3.6f;
// 获取总里程(单位:km)
float odometer = infoManager.getProperty(
VehiclePropertyIds.ODOMETER, 0);
但说实话,这种「拉取」方式在车载场景里不太常用。为什么?因为车速是实时变化的,你总不能开个定时器每秒去拉一次吧?那样既浪费资源,又可能错过中间的变化。
6.2.2 订阅监听(推荐方式)
我个人习惯用 CarPropertyManager 的 registerCallback() 来订阅变化。这样车速一变,系统就会主动通知你:
CarPropertyManager propertyManager =
(CarPropertyManager) car.getCarPropertyManager();
propertyManager.registerCallback(
new CarPropertyEventCallback() {
@Override
public void onEvent(CarPropertyEvent event) {
if (event.getPropertyId() ==
VehiclePropertyIds.PERF_VEHICLE_SPEED) {
float speed = (float) event.getValue();
// 更新 UI 或做其他处理
}
}
@Override
public void onError(int propertyId, int zone) {
// 处理错误
}
},
VehiclePropertyIds.PERF_VEHICLE_SPEED,
CarPropertyManager.SENSOR_RATE_NORMAL
);
小技巧:注册回调时,SENSOR_RATE_NORMAL 是 5Hz,也就是每秒回调 5 次。如果你做的是仪表盘,可能需要 SENSOR_RATE_FAST(10Hz)。但别用 FASTEST,那玩意儿每秒 100 次,CPU 扛不住。
6.3 控制空调
空调控制走的是 CarHvacManager。这个 Manager 封装了温度、风量、模式、AC 开关等操作。我直接上代码:
CarHvacManager hvac = (CarHvacManager) car.getCarHvacManager();
// 设置驾驶位温度 22°C(注意:单位是 0.1°C,所以 220 = 22.0°C)
hvac.setTemperature(
CarHvacManager.ZONE_DRIVER,
220f
);
// 开启 AC
hvac.setAcOn(CarHvacManager.ZONE_DRIVER, true);
// 设置风量(0-6 档)
hvac.setFanSpeed(CarHvacManager.ZONE_DRIVER, 3);
// 设置吹风模式(吹脸)
hvac.setAirDistribution(
CarHvacManager.ZONE_DRIVER,
CarHvacManager.AIR_DISTRIBUTION_FACE
);
这里有个坑,我曾经踩过:Zone 的概念。有些车是双区空调,有些是四区。你设置驾驶位温度时,一定要传对 Zone ID。如果传错了,可能副驾没反应,或者两边一起变。
注意:不是所有空调属性都支持「设置」。比如有些车的 AC 开关是只读的,只能读不能写。建议在设置前先调用 isPropertyAvailable() 检查一下。
6.4 控制车窗
车窗控制稍微特殊一点。它不属于 HVAC,而是走 CarWindowManager。不过底层还是通过 VHAL 的 WINDOW_POS 属性来实现的。
CarWindowManager windowManager =
(CarWindowManager) car.getCarWindowManager();
// 获取车窗位置(0 = 完全关闭,100 = 完全打开)
int pos = windowManager.getWindowPosition(
CarWindowManager.WINDOW_DRIVER_LEFT
);
// 设置车窗位置(打开到 50%)
windowManager.setWindowPosition(
CarWindowManager.WINDOW_DRIVER_LEFT,
50
);
嗯,这里要注意:车窗控制通常有安全限制。比如行驶中不允许完全打开车窗,或者后排车窗只能降到一半。这些限制是车厂在 VHAL 层实现的,你调用 API 时如果被拒绝了,会返回一个错误码。
避坑指南:我曾经在某个项目里,发现车窗控制偶尔失效。查了半天,原来是车辆在「儿童锁」模式下,后排车窗被硬件锁死了。API 调用成功了,但硬件没响应。所以,控制车窗前最好先检查一下车辆状态。
6.5 整体架构图
说了这么多,咱们用一张图来梳理一下整个调用链路。从 App 到硬件,中间经过了哪些层:
从图里可以清楚看到,App 不直接跟硬件打交道。所有请求都经过 CarService 和 VHAL 这两层。这样做的好处是:车厂可以自由替换底层硬件,只要 VHAL 接口不变,上层 App 完全不用改。
6.6 实战中的注意事项
最后,我总结几个实战中容易踩的坑:
- 权限问题:控制车辆功能需要
android.car.permission.CAR_CONTROL_AUDIO_SETTINGS等权限。别忘了在 Manifest 里声明,并且是系统级权限。 - 线程问题:Car API 的回调默认在主线程。如果你在回调里做耗时操作,记得切到子线程。
- 模拟器支持:Android Studio 的 Automotive 模拟器支持部分 Property。但车窗和空调可能没有真实响应。建议用实车或硬件在环(HIL)测试。
- 属性 ID 的兼容性:不同 Android 版本,某些 Property ID 可能被废弃或新增。开发时注意 targetSdkVersion 和对应的 API 文档。
我的习惯:每次拿到一辆新车,我会先写一个「车辆能力探测」工具。把支持的所有 Property 都读一遍,看看哪些可读、哪些可写。这样后面开发时心里有底,不会出现「明明 API 调了,车却没反应」的尴尬。
好了,这一章的内容就到这里。代码不多,但都是实打实能跑起来的。你可以在模拟器上试试,或者找一辆开发车验证一下。记住,车载开发的核心就是「读」和「写」,把这两个基本功练扎实了,后面再复杂的场景也不怕。
公众号:蓝海资料掘金营,微信deep3321