本页内容 启动与恢复首次连接选择、取消与解绑控车与状态并发约束Android:按顺序恢复与读取
APP SDK / Android · iOS

车辆绑定与恢复

按扫描、授权、配对、绑定顺序连接车辆,处理切换、解绑和取消后的恢复。

启动与恢复

隐私同意和平台会话准备好后,先执行 recover,补交 SDK 保存的待确认结果,再执行 list 获取云端车辆。cached 仅用于展示,不能作为当前授权或绑定状态的依据。恢复失败时按错误类型提示或重试,不要删除恢复记录来绕过失败。

Android 可使用类型化方法或 execute(action, parametersJson, callback);iOS 使用 execute:parameters:resolve:reject:。下表是两端共用的云操作名,参数均为对象。

action 参数与用途
recover、list、cached 空对象;恢复、云列表、缓存列表
add 空对象;进入添加车辆流程
bootstrap discoveryId,可选 expectedTerminal;获取目标引导授权
bind terminalId;提交绑定证明并恢复目标连接权限
select、report vehicleId、deviceId、terminalId;选择车辆或上报已连接终端
restoreSelection terminalId;取消添加后恢复已有选择
clearBootstrap 空对象;清理临时引导授权
release terminalId;近场撤销终端授权
unbind vehicle 为 list 返回的完整条目,含 vehicle.bindingVersion 与 terminals
authorizePairingRecovery terminalId、nonce;返回恢复证明,交设备客户端继续 PIN 恢复
adoptLegacy 空对象;仅核实旧记录来源后认领,见升级说明

首次连接

  1. 保存当前选择,执行 add,然后启动设备扫描。
  2. 从扫描结果取得 discoveryId,执行 bootstrap;已知目标时同时传入 expectedTerminal。
  3. 使用设备客户端配对接口完成安全握手,按真实终端屏幕提示提交 PIN。
  4. 配对成功后执行 bind;完成云绑定后刷新列表与目标状态。
  5. 按需要准备并连接目标车辆 Wi-Fi,确认目标 terminalId 的认证状态与连接探测结果。
  6. 成功、失败或取消后清理 bootstrap。保留 SDK 自动保存的待确认回执,后续通过 recover 处理。

蓝牙连接、系统配对成功、已连 SSID 和 Wi-Fi 入网回调都不能单独证明车辆业务连接成功。不要在 UI 提前显示“已绑定”或“控车成功”。

选择、取消与解绑

选择已授权车辆使用 select。取消添加时,先停止发现与临时配对、等待旧操作结束,再调用 restoreSelection 恢复原有车辆。每次异步回调核对当前操作和目标,避免上一辆车的迟到结果覆盖当前车辆。

取消调用 cancel(),然后等待 resolve/reject 完成。取消不会回滚终端或服务端已经确认的事实。导航中不应切换或移除车辆,收到 NAVIGATION_ACTIVE 时先让用户结束导航。

release 与 unbind 含义不同:前者撤销近场终端授权,后者通过车辆绑定版本执行云解绑。解绑响应未知时保留相同 bindingVersion 重试;重新登录原账号后由恢复流程完成待处理动作。不要手动清空 pendingReceipt、pendingChallenge 或 pendingUnbind。

控车与状态

根据终端返回的真实能力和用户权限展示按钮。每次明确用户操作只发送一次车辆命令,等待回执;网络重连、界面重建或超时后不能自动重放控车动作。

状态读取与命令回执是不同结果。需要展示执行成功时,使用对应命令的回执和后续有效状态,不用旧缓存推断成功。持续导航、媒体和后台连接还依赖宿主扩展、权限与终端能力。

并发约束

SDK 维护单设备业务会话。绑定、选择、解绑等互斥操作返回 CLOUD_BUSY 时,等待当前操作结束后刷新状态。Android 0.2.1 的同范围列表与恢复请求会合并;每个调用者单独取消自己的结果,不影响其他订阅者。全部取消后,已开始的共享工作仍可运行至完成或超时,以保留已确认回执。其他独占操作期间调用 recover 返回 CLOUD_BUSY,等待操作结束再重试。账号/token 改变后重建客户端。

Android:按顺序恢复与读取

下面的协调器实例只运行一次,在主线程创建、启动和取消;SDK 已配置且平台会话已安装。isCurrent 由宿主核对账号、车辆和页面操作代次;页面退出或会话改变时先使它失效,再调用 cancel()。宿主保留协调器至操作结束。

成功结果交给 result.resolve;失败交给 result.reject,按错误处理决定下一步。取消只撤回当前订阅者的结果,SDK 已开始的共享恢复仍可完成。

import net.oou.mobile.CloudOperation
import net.oou.mobile.CloudVehicles
import net.oou.mobile.ResultCallback

class VehicleRefresh(
    private val vehicles: CloudVehicles,
    private val isCurrent: () -> Boolean,
    private val result: ResultCallback
) {
    private var recovery: CloudOperation? = null
    private var listing: CloudOperation? = null
    private var started = false
    private var cancelled = false
    private fun current() = !cancelled && isCurrent()

    private val listResult = object : ResultCallback {
        override fun resolve(value: Any?) {
            if (current()) result.resolve(value)
        }
        override fun reject(code: String, message: String?, cause: Throwable?) {
            if (current()) result.reject(code, message, cause)
        }
    }

    fun start() {
        check(!started)
        started = true
        if (!current()) return
        recovery = vehicles.recover(object : ResultCallback {
            override fun resolve(value: Any?) {
                if (current()) listing = vehicles.list(listResult)
            }
            override fun reject(code: String, message: String?, cause: Throwable?) {
                listResult.reject(code, message, cause)
            }
        })
    }

    fun cancel() {
        cancelled = true
        recovery?.cancel()
        listing?.cancel()
    }
}