车载网络与连接:CarNetworkService、CarBluetoothManager、CarProjectionManager、Wi-Fi 热点

各位同学,今天我们来聊聊车载系统里最“接地气”的部分——网络与连接。

说实话,这部分内容在开发中往往被低估。很多人觉得不就是连个网、连个蓝牙嘛,有什么难的?但我在项目中踩过的坑告诉我,恰恰是这些“基础功能”,最容易让用户骂娘。你想想看,用户开车时连不上蓝牙,导航没法用,那体验得多糟糕。

所以今天,我带你把这几个核心服务彻底搞明白。

9.1 CarNetworkService:车载网络的“交通警察”

CarNetworkService 是车载网络连接的总调度。它管理着蜂窝网络、Wi-Fi、以太网等物理链路,并负责向应用层提供统一的网络状态。

我个人习惯把 CarNetworkService 看作一个“交通警察”。它不负责具体的网络收发数据,但它知道哪条路通了、哪条路堵了、哪条路是收费的。

9.1.1 核心职责

  • 网络状态监听:实时监测蜂窝、Wi-Fi、以太网的连接状态
  • 网络评分与切换:根据信号强度、带宽、延迟等指标,自动选择最优网络
  • 网络策略下发:向系统服务和应用广播网络变化事件

关键点:CarNetworkService 不直接处理 TCP/IP 数据包,它只做“网络管理”层面的工作。真正的数据传输,还是走 Android 原生的 ConnectivityManager。

9.1.2 代码示例:监听网络状态变化

// 注册 CarNetworkService 回调
CarNetworkService networkService = car.getCarManager(Car.CAR_NETWORK_SERVICE);
networkService.registerNetworkPolicyListener(new CarNetworkService.NetworkPolicyListener() {
    @Override
    public void onNetworkPolicyChanged(int networkType, int policy) {
        // networkType: CarNetworkService.NETWORK_TYPE_CELLULAR / WIFI / ETHERNET
        // policy: CarNetworkService.POLICY_ALLOW / DENY / METERED
        Log.d("CarNetwork", "网络类型: " + networkType + " 策略: " + policy);
    }
});

嗯,这里要注意:回调是在 binder 线程里触发的,别在里面做耗时操作。我曾经见过一个同事直接在回调里写数据库,结果 ANR 了。

9.1.3 网络评分机制

CarNetworkService 内部有一套评分算法。它会根据以下维度给每个可用网络打分:

维度 权重 说明
信号强度 30% RSSI 或 RSRP 值
带宽 25% 实测吞吐量
延迟 20% ping 延迟
计费属性 15% 是否按流量计费
稳定性 10% 历史断连频率

评分最高的网络会被设为“默认网络”。应用层通过 ConnectivityManager 获取的,就是这个默认网络。

我的经验:在车载场景下,Wi-Fi 的评分往往会被调低。因为车辆在行驶中,Wi-Fi 信号极不稳定。我曾经遇到过一辆车在高速上自动切到路边餐馆的 Wi-Fi,结果导航卡了十分钟。后来我们在评分算法里加了一条“移动速度超过 30km/h 时,Wi-Fi 评分直接减半”。

9.2 CarBluetoothManager:蓝牙连接的“管家”

CarBluetoothManager 是车载蓝牙连接的核心服务。它管理着手机配对、免提通话、蓝牙音乐、电话本同步等功能。

说白了,它就是 Android 原生 BluetoothAdapter 的“车载增强版”。

9.2.1 核心功能

  • 设备配对与连接:支持多设备同时连接(比如一部手机打电话,另一部放音乐)
  • Profile 管理:HFP(免提)、A2DP(音乐)、AVRCP(控制)、PBAP(电话本)
  • 连接优先级:根据用户设置或历史记录,决定先连哪台设备

9.2.2 代码示例:获取已配对设备列表

CarBluetoothManager btManager = car.getCarManager(Car.CAR_BLUETOOTH_SERVICE);
List<CarBluetoothDevice> pairedDevices = btManager.getPairedDevices();
for (CarBluetoothDevice device : pairedDevices) {
    Log.d("CarBT", "设备: " + device.getName() + " 地址: " + device.getAddress());
    // 检查当前连接的 Profile
    boolean isHfpConnected = btManager.isProfileConnected(device, CarBluetoothDevice.PROFILE_HFP);
    boolean isA2dpConnected = btManager.isProfileConnected(device, CarBluetoothDevice.PROFILE_A2DP);
}

避坑指南:我曾经在项目里遇到一个诡异的问题——手机连上车机后,音乐播放卡顿。查了两天才发现,是因为 A2DP 和 HFP 同时连接时,蓝牙模块的带宽被 HFP 占用了。解决方案是:在播放音乐时,暂时降低 HFP 的采样率。

9.2.3 多设备连接策略

车载场景下,多设备连接是常态。CarBluetoothManager 支持以下策略:

  • 主设备优先:用户指定的主设备拥有最高优先级
  • 按 Profile 分配:一部设备连 HFP,另一部连 A2DP
  • 自动切换:主设备断开后,自动连接次优设备

我个人建议,在 UI 上给用户一个“设备管理”界面,让用户能手动调整优先级。别全自动,用户会没安全感的。

9.3 CarProjectionManager:手机投屏的“桥梁”

CarProjectionManager 是 Android Automotive OS 里专门管理手机投屏的服务。它支持 Android Auto、Apple CarPlay 等协议。

说白了,它就是车机与手机之间的“翻译官”。手机发来的指令,它翻译成车机能理解的;车机的屏幕,它映射给手机去渲染。

9.3.1 核心流程

  1. 发现与配对:通过 USB 或 Wi-Fi 发现手机
  2. 连接建立:建立数据传输通道(通常走 TCP)
  3. 视频流传输:手机将 UI 渲染成视频流,推送到车机
  4. 触控事件回传:车机上的触摸事件,回传给手机处理

9.3.2 代码示例:启动投屏会话

CarProjectionManager projectionManager = car.getCarManager(Car.CAR_PROJECTION_SERVICE);
CarProjectionManager.ProjectionSession session = projectionManager.startProjection(
    new CarProjectionManager.ProjectionCallback() {
        @Override
        public void onProjectionStarted(int status) {
            if (status == CarProjectionManager.STATUS_SUCCESS) {
                Log.d("Projection", "投屏启动成功");
            }
        }
        @Override
        public void onProjectionStopped(int reason) {
            Log.d("Projection", "投屏停止,原因: " + reason);
        }
    }
);

注意:投屏会话的生命周期必须与 Activity 绑定。如果 Activity 被销毁,会话必须主动关闭。否则会出现“手机还连着,但车机界面已经没了”的尴尬情况。

9.3.3 性能优化建议

投屏对性能要求很高。我见过一些车机,投屏时卡成幻灯片。这里给几个优化方向:

  • 视频解码硬件加速:务必使用 MediaCodec 的硬件解码器
  • 帧率控制:根据车机屏幕刷新率,动态调整投屏帧率(一般 30fps 就够了)
  • 分辨率自适应:不要硬上 1080p,根据车机屏幕实际分辨率来

9.4 Wi-Fi 热点:车载“移动基站”

Wi-Fi 热点功能,说白了就是把车变成一个移动路由器。乘客的手机、平板都可以通过车载 Wi-Fi 上网。

这个功能在长途旅行中特别实用。我记得有一次坐朋友的车,他车上的 Wi-Fi 热点信号特别好,我们三个人同时看视频都不卡。

9.4.1 核心实现

Android Automotive OS 使用 SoftApManager 来管理 Wi-Fi 热点。CarService 对它做了一层封装,提供了更符合车载场景的 API。

CarWifiManager wifiManager = car.getCarManager(Car.CAR_WIFI_SERVICE);
// 开启热点
wifiManager.startSoftAp("MyCarWiFi", "password123", new CarWifiManager.SoftApCallback() {
    @Override
    public void onStateChanged(int state) {
        // STATE_ENABLED / STATE_DISABLED / STATE_FAILED
    }
    @Override
    public void onClientConnected(String macAddress) {
        Log.d("WiFiAP", "新设备接入: " + macAddress);
    }
});

9.4.2 热点配置参数

参数 说明 建议值
SSID 热点名称 车辆品牌 + 随机后缀
加密方式 WPA2-PSK 或 WPA3 WPA2(兼容性最好)
最大连接数 同时连接的设备数量 5-8 台(太多会卡)
频段 2.4GHz 或 5GHz 5GHz(干扰少,但穿墙差)

我的建议:热点名称最好加上随机后缀,防止多辆同品牌车停在一起时,用户连错。另外,密码不要用固定值,每次启动时随机生成,用户可以在车机屏幕上查看。

9.4.3 热点与蜂窝网络的带宽分配

热点用的是蜂窝网络的数据。如果车上同时有多个设备在下载大文件,导航可能会受影响。

我建议做带宽限制:

  • 导航流量优先:保证导航应用的最低带宽(比如 1Mbps)
  • 热点限速:每个连接设备限速 5Mbps,防止单个设备占满带宽
  • 动态调整:当蜂窝信号变差时,自动降低热点速度

知识体系总览

下面这张图,我把今天讲的内容串起来了。你可以看到各个服务之间的关系:

车载网络与连接知识体系 CarService CarNetworkService CarBluetoothManager CarProjectionManager CarWifiManager 网络状态监听 网络评分与切换 设备配对连接 Profile 管理 投屏会话管理 视频流传输 热点开启/关闭 客户端管理 带宽分配 限速策略 所有服务均通过 CarService 统一管理,应用层通过 Car API 调用 系统服务 网络服务 蓝牙服务 投屏服务 Wi-Fi 服务

好了,这一章的内容就到这里。车载网络与连接这块,说白了就是“让车能上网、让手机能连车、让乘客能上网”。每个服务都有自己的职责,但最终都要协同工作。

你在实际开发中,如果遇到网络切换不顺畅、蓝牙连接不稳定、投屏卡顿这些问题,可以回头看看这一章的内容。大部分问题,都能从这几个服务的配置和策略里找到答案。

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