协议兼容与演进¶
最后更新:
EVCC 开放 API 的产品版本与 Binder 协议版本彼此独立。当前公开基线是 EVCC 3.3.1 中的 EvccApi 1.3:
客户端必须以运行时 getApiInfo() 的结果为准,不能仅按用户报告的 EVCC 展示版本推断接口能力。
握手顺序¶
推荐客户端按以下顺序建立会话:
- 绑定
com.kooo.evcc.evccapi.BIND。 - 调用
getApiInfo()。 - 检查
apiMajor == EvccApiContract.API_MAJOR;不相等则停止调用。 - 用真实应用包名和回调调用
openSession()。 - 读取
EvccSessionInfo,以grantedPermissions为本会话授权事实。 - 调用
queryCapabilities(),按能力 ID 判断当前版本、车型、来源和权限是否支持目标功能。
当前 EvccApiClient 自动完成前四步,并在主版本不一致时停止重试。contractHash 用于构建和排障时
确认双方契约基线;它不是授权凭据,也不能替代 queryCapabilities()。同一协议版本下,属性源在线
状态、车型支持和用户权限仍然可能不同。
版本字段如何使用¶
| 字段 | 客户端用途 | 不应做的事 |
|---|---|---|
apiMajor |
判断 Binder/Parcelable 基线是否兼容 | 主版本不同仍尝试调用 |
apiMinor |
判断某个后续追加能力是否可能存在 | 只看次版本、不查询能力 |
contractHash |
日志、产物核对和异常组合诊断 | 作为身份或签名校验 |
serviceVersionName/code |
展示 EVCC 版本、提交问题时记录 | 用版本名字符串比较能力 |
capabilitiesRevision |
发现内置能力目录可能变化后重新查询 | 当作时间戳或用户授权版本 |
grantRevision |
发现当前应用授权记录变化 | 假设修订号连续或跨设备可比 |
应用应在每次 onSessionReady() 后重新读取会话权限和能力。来源上下线不会要求协议升级,应通过
querySourceStates() 和 onSourceStateChanged() 处理;来源代次语义见
初始化、监听与重同步。
1.x 兼容规则¶
协议 1.x 采用保守的追加式演进。以下变化可以在次版本中出现,但新客户端必须同时使用 apiMinor、
能力查询或业务状态进行保护:
- 新增能力 ID、权限 ID、动作 ID、明确来源 ID或状态字符串;客户端应忽略未知 ID,并把未知状态按 “非成功、保留原文供诊断”处理。
- 在 AIDL 接口末尾追加使用新请求/返回类型的方法;已有方法的事务顺序和签名保持不变。新客户端 连接旧服务时,不得在确认次版本/能力前调用新增方法。
- 新增独立 Parcelable 类型,而不是改变旧类型的线格式。
- 收紧资源限制或安全策略时,通过明确状态和
message返回;客户端不能把当前上限当成永久配额。
当前 Parcelable 使用按固定顺序手写的无版本长度 Parcel 编码。因此,现有类型在 1.x 中必须保持:
- 字段数量、顺序和基础类型不变;
- nullable 与非 nullable 约定不变;
- 默认值和既有字段语义不被重新解释;
- 时间字段的单位/时基不被静默改变。
需要增加模型信息时,优先新增类型和新方法,或把可扩展内容放在有独立 schema 的 JSON 字段中。只有 “在现有 Parcelable 末尾再写一个字段”并不能保证旧客户端向新服务端发送请求时仍可安全解码。
以下变化需要提升主版本,而不能伪装成 1.x 小改动:
- 删除、重命名或改变现有 AIDL 方法,或在已有方法中间插入导致事务编号变化的方法;
- 改变 Parcelable 字段顺序、类型、可空性或编码方式;
- 改变现有状态、来源、权限或动作 ID 的含义;
- 把同步调用改为异步回调,或反向改变;
- 改变既有来源之间的 AUTO 相对优先级、写入不回退等会影响控制目标的基础规则;精确车型门控的新来源可在次版本中追加,但必须通过
resolvedSource和能力查询可见; - 为
observedAt等既有字段静默指定与 1.0 不兼容的新单位。
能力兼容优先于版本分支¶
版本只能说明“某项能力可能存在”,不能说明当前应用可以使用。正确模式是按稳定 ID 查找:
val capabilities = withContext(Dispatchers.IO) {
client.queryCapabilities().associateBy(EvccCapability::id)
}
val canWrite = capabilities[EvccApiContract.Permission.PROPERTY_WRITE]?.available == true
val canLaunch = capabilities["action.app.launch"]?.available == true
权限能力、source.* 能力和 action.* 能力共享 EvccCapability 模型,但 ID 空间不同。执行动作时传入
不带 action. 前缀的动作 ID,详见变量与动作。任何高风险能力仍须以服务端
逐次权限检查为准,能力查询结果不能缓存成永久授权。
升级、降级与重装¶
- EVCC 升级或进程重启会结束现有 Binder 会话;SDK 重连后重新读取
EvccApiInfo、授权和能力,并恢复 最后一次成功的订阅集合。 - 客户端升级后必须保留对其声明支持的最低协议次版本的分支;不能因为编译时 Contract 更新就直接调用 新方法。
- EVCC 降级后若主版本仍相同,客户端仍应按实际次版本和能力运行;缺失能力应降级界面,而不是循环 调用。
- 第三方应用重新签名、改变 UID 或使用共享 UID 时,旧授权不会继承。它属于身份/授权变化,不是协议 兼容问题;处理方式见权限与授权。
- “米德宝/AIDL 联动”旧版接口与 EVCC 开放 API 是独立协议和授权域,版本号不能互相比较,也不存在 自动迁移。
发布前兼容检查¶
第三方应用至少应验证:
- 当前 1.3 EVCC 正常连接、读取和取消订阅;1.0 客户端只使用已有事务。
- EVCC 被停止再恢复后,SDK 重绑且业务以新
INITIAL_SNAPSHOT建立基线。 - 撤权、功能关闭和签名变化时停止重试并给出用户可操作提示。
- 未知能力和未知非成功状态不会造成崩溃或误判成功。
- 目录始终按
nextPageToken + snapshotToken继续,不依赖固定每页数量。 - 写入和动作在能力不足、权限不足或车型不支持时安全降级。
精确 AIDL 方法见AIDL 接口参考,全部 Parcelable 字段见 数据模型参考,通用错误处理见状态与错误码。
1.1 音乐扩展¶
会话尾部追加 5 个音乐方法,回调尾部追加音乐事件,原 1.0 Parcelable 不变。新客户端先检查 minor>=1,旧客户端不订阅音乐时不会收到新回调。详情见音乐与歌词。
1.2 音量组扩展¶
会话尾部追加 4 个音量方法,新增独立请求和返回模型;已有模型、方法和回调不变。新 SDK 连接 1.0/1.1 服务时不发送音量事务,返回 UNSUPPORTED。权限和车型支持仍需分别判断;重连不重放写入。见音量组。
1.4 ECARX 原生 VHAL 来源¶
新增稳定来源 ID ECARX_VHAL,不追加 AIDL 事务,也不改变任何 Parcelable 布局。该来源受精确车型和云端 profile 双重门控,仅 L946 配置会进入 AUTO 首位;不满足门槛时它是不可用来源,不改变其他车型的实际解析结果。旧客户端会按 1.x 规则忽略未知来源 ID;需要显式选择该来源的客户端应先确认 apiMinor >= 4 并查询 source.ecarx_vhal 能力。旧 ECARX_EAS ID 不作为别名保留。