VenusSDK接入与开发指南(Android)vX.X.X
=====================================
# 1. 文档概述
本文介绍在 Android 平台上集成 VenusSDK 的方法,实现应用与 VenusOS 智能眼镜的连接与交互,包括设备连接、设备信息获取、设备状态同步、系统设置、固件升级、以及各项功能(实时语音转文字服务、导航、提词)的信息同步。
# 2. 支持平台与版本
- Android 7.0 及以上
- minSdk 24 及以上
- 支持 Classic Bluetooth 连接
# 3. 快速开始
## 3.1 集成SDK
1. 将 `VenusSDK_vx.x.x_release.aar` 复制到 Application Module/libs 文件夹
2. 在 app 的 build.gradle.kts 中添加依赖:
```gradle
dependencies {
implementation(files("libs/VenusSDK_vx.x.x_release.aar"))
}
```
## 3.2 声明权限
根据场景需要,在 `/app/src/main/AndroidManifest.xml` 文件中申请获取相应的设备权限:
```xml
```
## 3.3 混淆配置
在 `app/proguard-rules.pro` 文件中添加:
```proguard
-keep class com.jueyuantech.venussdk.** { *; }
-dontwarn com.jueyuantech.venussdk.**
```
## 3.4 SDK初始化
VenusSDK 主要提供:`VNSDK`、`VNCommon` 和 `VNOTA` 接口:
- `VNSDK` 负责 SDK 初始化、自定义参数、获取版本构建信息等;
- `VNCommon` 负责处理与设备相关的常用功能,如设备连接管理、系统配置、状态监听和功能调用等;
- `VNOTA` 负责固件升级相关功能。
在 Application 类中初始化 SDK:
```java
VNSDK.init(this, new VNOptions());
```
> 📝 **注意:** 调用 `VNSDK.init` 后,SDK 内部同时会对 VNCommon 和 VNOTA 进行初始化,开发者无需手动初始化,可直接调用其功能。
## 3.5 获取SDK构建信息
获取SDK的版本构建信息:
```java
VNVersionInfo versionInfo = VNSDK.getVersionInfo();
```
返回的 `VNVersionInfo` 对象包含以下信息:
- buildType:构建类型
- code:版本号
- name:版本名称
- commit:构建提交号
- date:构建日期
# 4. 设备连接和配置
## 4.1 设备扫描
SDK 中不提供扫描设备的接口,开发者需自行扫描附近 **Classic Bluetooth** 蓝牙设备,将获取到的 `BluetoothDevice` 对象传递给 SDK 进行初始化和连接。
## 4.2 设备连接管理
> ℹ️ **提示:** 设备连接是指 APP 与眼镜设备的**业务通路**连接。如有用到**音频通路**连接(A2DP、HFP),开发者需通过Android标准API自行维护。
1. 初始化设备:
```java
VNCommon.initDevice(bluetoothDevice);
```
2. 设置连接状态监听:
```java
VNCommon.setDeviceServiceListener(new VNDeviceServiceListener() {
@Override
public void onStateChanged(int state) {
// 根据state判断连接状态
switch (state) {
case VNConstant.ServiceState.CONNECT_SUCCESS:
// 连接成功
break;
case VNConstant.ServiceState.CONNECT_ERROR:
// 连接失败
break;
}
}
});
```
3. 连接设备:
```java
VNCommon.connect(bluetoothDevice);
```
4. 获取当前连接状态:
```java
boolean connected = VNCommon.isConnected();
```
5. 断开连接:
```java
VNCommon.disconnect();
```
## 4.3 设备信息获取
通过`getDeviceInfo`方法获取设备的基本信息,包括设备名称、MAC地址、固件版本等信息:
```java
VNCommon.getDeviceInfo(new VNDeviceInfoCallBack() {
@Override
public void onSuccess(VNDeviceInfo deviceInfo) {
// 获取设备信息成功
// 厂商
String manufacturer = deviceInfo.getManufacturer();
// 型号
String model = deviceInfo.getModel();
// 发行版
String edition = deviceInfo.getEdition();
// 蓝牙MAC地址
String mac = deviceInfo.getMac();
// 设备序列号
String sn = deviceInfo.getSn();
// 固件版本
String firmware = deviceInfo.getFirmware();
// 协议栈版本
String bth = deviceInfo.getBth();
}
@Override
public void onTimeOut() {
// 获取设备信息超时
}
@Override
public void onFailed() {
// 获取设备信息失败
}
});
```
## 4.4 系统配置获取
通过`getSystemConfig`方法获取当前系统的各项配置信息,包括亮度、自动亮度调节、字体大小、系统语言、佩戴检测、触控板等状态:
```java
VNCommon.getSystemConfig(new VNSystemConfigCallBack() {
@Override
public void onSuccess(VNSystemConfig systemConfig) {
// 获取系统配置成功
// 屏幕亮度值(0 - 255)
Integer brightness = systemConfig.getBrightness();
// 自动亮度调节状态(0 - 关闭,1 - 开启)
Integer autoBrightness = systemConfig.getAutoBrightnessEnabled();
// 系统语言
String language = systemConfig.getLanguage();
// 触控板状态(0 - 关闭,1 - 开启)
Integer touchpadEnabled = systemConfig.getTouchpadEnabled();
// ......
}
@Override
public void onTimeOut() {
// 获取系统配置超时
}
@Override
public void onFailed() {
// 获取系统配置失败
}
});
```
## 4.5 时间设置
> ℹ️ **提示:** 设备系统时间由 SDK 在设备连接成功时自动设置,正常情况下无需开发者进行设置。
在检测到应用终端时间发生改变的情况下,需开发者主动调用以同步时间:
```java
/**
* @param timeConfig 时间配置:时间、格式等
*/
void setTimeConfig(TimeConfig timeConfig, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:
TimeConfig timeConfig = new TimeConfig();
timeConfig.setTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
VNCommon.setTimeConfig(timeConfig, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
> 📝 **注意:** 若APP时间与眼镜设备系统时间不一致,以下功能会受影响:
> - [显示通知](#CUSTOM_54_1)
历史固件版本设置时间方法:
```java
/**
* @param time 时间戳,单位:秒
* @deprecated prefer setTimeConfig
*/
void setTime(long time, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:
VNCommon.setTime(System.currentTimeMillis() / 1000, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 4.6 亮度设置
手动设置亮度:
```java
/**
* @param brightness 0 - 255
*/
void setBrightness(int brightness, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:设置亮度值为 128
VNCommon.setBrightness(128, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
自动亮度调节开关:
```java
/**
* @param enabled
* VNConstant.EnableState.ENABLED - 开启
* VNConstant.EnableState.DISABLED - 关闭
*/
void setAutoBrightnessEnabled(int enabled, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:开启自动亮度功能
VNCommon.setAutoBrightnessEnabled(VNConstant.EnableState.ENABLED, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
> 📝 **注意:**
>- 亮度建议值 80 - 180 之间,结合实际场景调优。
>- 自动亮度功能需设备硬件支持。当自动亮度开启时,手动设置亮度值会被覆盖。
## 4.7 音量设置
眼镜设备音量跟随系统音量设置。
## 4.8 显示模式设置
支持显示模式设置,如全屏显示、半屏显示:
```java
/**
* @param displayConfig 显示配置:显示模式、显示区域等配置。
*/
void setDisplayConfig(DisplayConfig displayConfig, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:
DisplayConfig config = new DisplayConfig();
config.setMode(1); // 显示模式:1 - 全屏,0 - 半屏
VNCommon.setDisplayConfig(config, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 4.9 系统语言设置
系统界面语言设置:
```java
/**
* @param language BCP 47 语言代码
*/
void setLanguage(String language, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:设置系统语言为中文
VNCommon.setLanguage("zh-CN", new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
支持语言列表如下:
|语言 |标识符 |
|--------------------|------------|
| 中文(简体) | zh-CN |
| 中文(繁体) | zh-TW |
| English | en-US |
| 日本語 | ja |
| 한국어 | ko |
| Deutsch | de |
| Français | fr-FR |
| Русский | ru |
| Italiano | it |
| Português (Brasil) | pt-BR |
| Español (Spain) | es-ES |
| Tiếng Việt | vi |
| ภาษาไทย | th |
> 📝 **注意:** 支持的语言列表,根据设备固件版本的字库调整。
## 4.10 通知功能设置
设备支持在界面显示通知信息,当功能开启后,用户可以通过 [5.4 通知](#54-通知) 或 ANCS(苹果通知中心服务)向设备发送通知信息。
设置通知功能的开关状态:
```java
/**
* @param enabled
* VNConstant.EnableState.ENABLED - 开启
* VNConstant.EnableState.DISABLED - 关闭
*/
void setNotificationEnabled(int enabled, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:开启通知功能
VNCommon.setNotificationEnabled(VNConstant.EnableState.ENABLED, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
> 📝 **注意:** [5.4 通知](#54-通知) 中的**系统通知**不受该设置影响。
## 4.11 触控板设置
用户可以通过眼镜设备的触控区域进行单击、双击、长按、滑动等手势与设备交互。
设置触控板功能的开关状态:
```java
/**
* @param enabled
* VNConstant.EnableState.ENABLED - 开启
* VNConstant.EnableState.DISABLED - 关闭
*/
void setTouchpadEnabled(int enabled, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:开启触控板
VNCommon.setTouchpadEnabled(VNConstant.EnableState.ENABLED, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**使用场景:**
- 菜单导航:快速浏览和切换不同功能界面
- 内容控制:确认选择、返回上级等操作
- 特殊场景:在不方便使用语音控制时提供替代操作方式
> 📝 **注意:** 此功能需设备硬件支持。
## 4.12 静置状态自动熄屏设置
通过设备的静置传感器检测设备是否处于静置状态(如放置在桌面)。当检测到设备静置超过 10 秒时,系统自动熄屏。
设置静置熄屏功能的开关状态:
```java
/**
* @param enabled
* VNConstant.EnableState.ENABLED - 开启
* VNConstant.EnableState.DISABLED - 关闭
*/
void setIdleDetectionEnabled(int enabled, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:开启功能
VNCommon.setIdleDetectionEnabled(VNConstant.EnableState.ENABLED, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**使用场景:**
- 自动熄屏:用户将设备放置不动时自动进入熄屏模式
- 节能管理:通过自动熄屏机制延长设备使用时间
> 📝 **注意:**
> - 此功能需设备硬件支持。
> - 在任意功能界面进入熄屏后,30 秒会收到 [系统状态监听](#CUSTOM_51_1) 的`onViewChanged(int vnAppId)`退回`HOME`主界面的消息。
## 4.13 非活跃状态自动熄屏设置
非活跃状态监听,是指设备监听超过一段时间(timeout)无新消息抵达设备,与设备无消息交互,则设备自动熄屏。
```java
/**
* @param timeout 单位:秒,0 表示关闭
*/
void setInactivityTimeout(int timeout, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:设置无交互 1 分钟后自动熄屏
VNCommon.setInactivityTimeout(60, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
> 📝 **注意:**
> - 在任意功能界面进入熄屏后,30 秒会收到 [系统状态监听](#CUSTOM_51_1) 的`onViewChanged(int vnAppId)`退回`HOME`主界面的消息。
> - 在特殊场景(如提词)需要保持亮屏时,可周期性(间隔低于 timeout)调用 `VNCommon.sendKeepAlive()` 发送保活信号。
## 4.14 熄屏状态自动关机设置
设备支持熄屏一段时间(timeout)后自动关机设置:
```java
/**
* @param timeout 单位:秒,0 表示关闭
*/
void setPoweroffTimeout(int timeout, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:设置熄屏 5 分钟后自动关机
VNCommon.setPoweroffTimeout(300, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 4.15 佩戴检测设置
开启佩戴检测后,当用户戴上设备时自动亮屏,摘下设备时自动熄屏:
```java
/**
* @param enabled
* VNConstant.EnableState.ENABLED - 开启
* VNConstant.EnableState.DISABLED - 关闭
*/
void setWearDetectionEnabled(int enabled, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:
VNCommon.setWearDetectionEnabled(VNConstant.EnableState.ENABLED, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
> 📝 **注意:** 此功能需设备硬件支持。
# 5 系统状态和操控
用户可以实时获取系统当前的各种状态、事件,结合业务场景来设计实现各项交互:
- `运行状态`:熄屏、亮屏
- `充电状态`:正在充电、未在充电
- `电池电量`
- `应用的进入和退出`
- `触控事件`:长按、双击、前滑、后滑
- `系统主动上报消息`:语音业务请求等
## 5.1 获取、监听、设置系统状态
1. 系统状态监听
通过`setDeviceStatusListener`方法设置设备状态监听器,可以监听设备的系统状态、充电状态、电池电量、应用切换等变化,以及触控板按键事件:
```java
// 设置设备状态监听
VNCommon.setDeviceStatusListener(new VNDeviceStatusListener() {
@Override
public void onSysStateChanged(int sysState) {
// 系统状态变化回调
switch (sysState) {
case VNConstant.SysState.SCREEN_OFF:
// 熄屏状态
break;
case VNConstant.SysState.SCREEN_ON:
// 亮屏状态
break;
}
}
@Override
public void onChargeStateChanged(int chargeState) {
// 充电状态变化回调
switch (chargeState) {
case VNConstant.ChargeState.NOT_CHARGING:
// 未充电
break;
case VNConstant.ChargeState.CHARGING:
// 充电中
break;
}
}
@Override
public void onBatteryChanged(int battery) {
// 电池电量变化回调(0-100)
}
@Override
public void onViewChanged(int vnAppId) {
// 视图状态变化回调
switch (vnAppId) {
case VNConstant.View.HOME:
// 主页
break;
case VNConstant.View.TRANSCRIBE:
// 转写页
break;
case VNConstant.View.TRANSLATE:
// 翻译页
break;
case VNConstant.View.MAP:
// 地图页
break;
case VNConstant.View.PROMPTER:
// 提词器页
break;
case VNConstant.View.READER:
// 阅读页
break;
}
}
@Override
public void onTouchEvent(int event) {
// 设备触控板事件回调,在设备端未消费的事件
switch (event) {
case VNConstant.TouchEvent.SINGLE_TAP:
// 单击
break;
case VNConstant.TouchEvent.DOUBLE_TAP:
// 双击
break;
case VNConstant.TouchEvent.LONG_PRESS:
// 长按
break;
case VNConstant.TouchEvent.SLIP_LEFT:
// 前滑
break;
case VNConstant.TouchEvent.SLIP_RIGHT:
// 后滑
break;
default:
}
}
});
```
2. 通过`getSystemStatus`方法**主动获取**设备当时的运行状态,包括系统状态、充电状态、电池电量等:
```java
VNCommon.getSystemStatus(new VNSystemStatusCallBack() {
@Override
public void onSuccess(int sysState, int chargeState, int battery) {
// 获取设备状态成功
// sysState: 系统状态,参考 VNConstant.SysState
// chargeState: 充电状态,参考 VNConstant.ChargeState
// battery: 电池电量(0-100)
}
@Override
public void onFail(int code, String msg) {
// 获取设备状态失败
}
});
```
3. 在特殊场景下,开发者可**主动设置**系统运行状态:
```java
/**
* @param sysState
* VNConstant.SysState.SCREEN_ON - 亮屏状态
* VNConstant.SysState.SCREEN_OFF - 熄屏状态
*/
void setSysState(int sysState, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:将设备熄屏
VNCommon.setSysState(VNConstant.SysState.SCREEN_OFF, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
// 示例:将设备亮屏
VNCommon.setSysState(VNConstant.SysState.SCREEN_ON, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.2 触控板
开发者可通过 [系统状态监听](#CUSTOM_51_1) 中的 `onTouchEvent(int event)` 回调方法监听到未被设备消费的触摸事件。
在特殊场景下,支持开发者主动发送触摸事件:
```java
/**
* @param event
* VNConstant.TouchEvent.SINGLE_TAP: 单击事件
* VNConstant.TouchEvent.DOUBLE_TAP: 双击事件
* VNConstant.TouchEvent.LONG_PRESS: 长按事件
* VNConstant.TouchEvent.SLIP_LEFT: 向左滑动事件
* VNConstant.TouchEvent.SLIP_RIGHT: 向右滑动事件
*/
void sendTouchEvent(int event)
```
```java
// 示例:发送长按事件
VNCommon.sendTouchEvent(VNConstant.TouchEvent.LONG_PRESS);
```
## 5.3 应用的进入和退出
当系统被触控板或其他途径操控进入和退出应用时,开发者通过 [系统状态监听](#CUSTOM_51_1) 中的 `onViewChanged(int vnAppId)` 回调方法监听到相应的请求。
也可以主动进行应用跳转:
```java
/**
* @param vnAppId
* VNConstant.View.HOME - 主页
* VNConstant.View.TRANSCRIBE - 语音转写
* VNConstant.View.TRANSLATE - 翻译
* VNConstant.View.MAP - 导航
* VNConstant.View.PROMPTER - 题词
* VNConstant.View.GALLERY - 图库
* VNConstant.View.AI - AI会话
*/
void setView(int vnAppId, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:进入翻译应用界面
VNCommon.setView(VNConstant.View.TRANSLATE, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
// 示例:返回主页
VNCommon.setView(VNConstant.View.HOME, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
获取设备当前所在应用:
```java
void getView(VNViewCallBack vnViewCallBack)
```
```java
// 示例:获取设备当前所在应用
VNCommon.getView(new VNViewCallBack() {
@Override
public void onSuccess(int vnAppId) {
// vnAppId 参考 VNConstant.View
}
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.4 通知
系统支持在界面上方与用户进行通知交互:
1. 显示通知:
```java
/**
* @param vnNotificationInfo
* (必选)id - 区分通知用于更新、移除
* (必选)title - 标题
* (必选)msg - 内容
* (必选)type - 通知类型:0-用户,1-系统
* (必选)duration - 持续时间,单位:秒;0 - 常驻等待关闭,n - 时间到自动关闭
* (必选)timeConfig - 通知时间
*/
void addNotification(VNNotificationInfo vnNotificationInfo, VNCommonCallBack vnCommonCallBack)
```
参数说明:
- 类型 `type`:
- `0 - 用户`:当 [4.10 通知功能设置](#410-通知功能设置) 关闭时,用户通知将被过滤不显示;
- `1 - 系统`:不受 [4.10 通知功能设置](#410-通知功能设置) 状态影响
- 持续时间 `duration`:
- `0 - 常驻等待关闭`:显示后需调用 [移除通知](#CUSTOM_54_2) 关闭,或通过双击触控板关闭
- `n - 时间到自动关闭`:n 秒时间到后自动关闭
```java
// 示例:显示通知:
VNNotificationInfo notificationInfo = new VNNotificationInfo();
notificationInfo.setId(1000);
notificationInfo.setTitle("通知标题");
notificationInfo.setMsg("通知内容");
notificationInfo.setType(0);
notificationInfo.setDuration(3);
TimeConfig timeConfig = new TimeConfig();
timeConfig.setTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
notificationInfo.setTimeConfig(timeConfig);
Bitmap appIcon = ...; // (可选)通知图标
String iconBmpData = VNCommon.getVenusBmpRawData(appIcon, 32, 32, true);
notificationInfo.setIconBitmap(iconBmpData);
VNCommon.addNotification(notificationInfo, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
2. 更新通知:
```java
/**
* @param vnNotificationInfo
* (必选)id - 区分通知用于更新、移除
* (可选)msg - 内容
*/
void updateNotification(VNNotificationInfo vnNotificationInfo, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:更新已有通知的内容
notificationInfo.setId(1000);
notificationInfo.setMsg("更新后的通知内容");
VNCommon.updateNotification(notificationInfo, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
3. 移除通知:
```java
/**
* @param vnNotificationInfo
* (必选)id - 区分通知用于更新、移除
*/
void removeNotification(VNNotificationInfo vnNotificationInfo, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:移除指定ID的通知
notificationInfo.setId(1000);
VNCommon.removeNotification(notificationInfo, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.5 文件系统
系统支持用户在 [提词信息同步](#65-提词信息同步)、 [图库](#66-图库)等应用场景下,对设备文件进行管理。如查看设备上当前已上传的提词文件列表、上传新文件等等操作。
1. 文件描述
`VNFile`用于描述设备中的文件信息,包括文件名,文件/文件夹,大小等描述。
部分 API 接收 `VNFile` 参数时,开发者可通过接口将 `File` 转为 `VNFile`:
```java
/**
* @param file 原文件
* @param vnFileType 应用场景
* VNConstant.VNFile.Type.PROMPTER - 题词
* VNConstant.VNFile.Type.GALLERY - 图库
* @return VNFile 设备文件描述
*/
VNFile initVNFile(File file, int vnFileType)
```
```java
// 示例:将本地文件转为题词文件描述
File file = new File("/xxx/xxx.txt");
VNFile vnFile = initVNFile(file, VNConstant.VNFile.Type.GALLERY);
```
2. 文件列表
```java
/**
* @param vnFileType 应用场景
* VNConstant.VNFile.Type.PROMPTER - 题词
* VNConstant.VNFile.Type.GALLERY - 图库
*/
void getFileList(int vnFileType, VNFileListCallBack vnFileListCallBack)
```
```java
// 示例:获取设备端题词场景文件列表
VNCommon.getFileList(VNConstant.VNFile.Type.PROMPTER, new VNFileListCallBack() {
@Override public void onSuccess(List files) { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
3. 上传文件
上传本地文件至设备指定应用场景中:
```java
// 示例:上传本地txt文件至设备题词场景中
IVNFileUploadTask vnFileUploadTask = VNCommon.createFileTransferTask();
// 将要上传的本地文件
File file = new File("/xxx/xxx.txt");
// 初始化上传任务,并注册上传回调
vnFileUploadTask.init(file, VNConstant.VNFile.Type.PROMPTER, new VNFileUploadListener() {
@Override
public void onError(int code, String msg) {
// 发生错误,可以通过retry重试并续传
}
@Override
public void onComplete() {
// 上传完成
}
@Override
public void onProgress(int cur, int total) {
// 上传进度
}
});
// 开始上传
vnFileUploadTask.start();
// 重试:上传发生错误时通过retry重试并续传
vnFileUploadTask.retry();
// 取消当前正在进行中的任务
vnFileUploadTask.cancel();
```
4. 删除文件
```java
/**
* @param vnFile 设备文件描述
* @param vnCommonCallBack 执行结果回调
*/
VNCommon.removeFile(VNFile vnFile, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:删除由getFileList获取到的设备文件列表中的某文件
VNCommon.removeFile(vnFile, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
5. 清空目录
```java
/**
* @param vnFileType 应用场景
* VNConstant.VNFile.Type.PROMPTER - 题词
* VNConstant.VNFile.Type.GALLERY - 图库
* @param vnCommonCallBack 执行结果回调
*/
void clearFolder(int vnFileType, VNCommonCallBack vnCommonCallBack)
```
```java
// 示例:清空题词文件目录
VNCommon.clearFolder(VNConstant.VNFile.Type.PROMPTER, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
6. 检查本地文件是否在设备存在
通常情况下,如果本地目标文件在设备端已经存在,则不需要重新上传。判断是否存在:
```java
/**
* @param file 原文件
* @param vnFileType 应用场景
* VNConstant.VNFile.Type.PROMPTER - 题词
* VNConstant.VNFile.Type.GALLERY - 图库
* @param vnCommonCallBack 执行结果回调
*/
void isFileExist(File file, int vnFileType, VNCommonCallBack vnCommonCallBack)
```
```java
VNCommon.isFileExist(file, VNConstant.VNFile.Type.GALLERY, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.6 查看存储空间
```java
/**
* @param vnRomUsageCallBack 查询结果回调
*/
void getRomUsage(VNRomUsageCallBack vnRomUsageCallBack)
```
```java
// 示例:查询设备存储空间情况
VNCommon.getRomUsage(new VNRomUsageCallBack() {
@Override
public void onSuccess(VNRomUsage usage) {
long remaining = usage.getRemaining(); // 单位:KB
long total = usage.getTotal(); // 单位:KB
}
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.7 监听设备主动消息
监听由眼镜设备主动上报的请求,如唤醒、助手等业务:
```java
// 示例:设置设备主动上报监听
VNCommon.setDeviceUnsolicitedListener(new VNDeviceUnsolicitedListener() {
@Override
public void onSttRequest() {
// 设备发出 STT 请求,至于是需要进入 `TRANSCRIBE` 或 `TRANSLATE` 由 APP 决策
}
});
```
## 5.8 重启
```java
VNCommon.reboot(new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.9 恢复出厂设置
```java
VNCommon.factoryReset(new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 5.10 解绑设备
```java
VNCommon.unbind(new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
# 6. 应用
系统支持常用的应用场景界面,如实时翻译、题词、导航等,并支持开发者把上位机获取到的实时业务信息发送到设备端呈现。
## 6.1 实时翻译(语音转文字显示)信息同步
系统提供将`实时翻译结果`传输到设备端进行显示的方法,以下是使用步骤:
**步骤一:进入翻译应用**
```java
// 示例:
VNCommon.setView(VNConstant.View.TRANSLATE, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤二:配置界面偏好**
- **设置文本显示模式** 语音业务时界面`仅当前`或`含历史`:
```java
/**
* @param vnAppId 应用,与 setView() 对应。
* @param mode 模式:
* VNConstant.SttConfig.TextMode.CURRENT_ONLY - 仅显示当前转写文本
* VNConstant.SttConfig.TextMode.CURRENT_AND_HISTORICAL - 同时显示当前和历史转写文本
* @param vnCommonCallBack 执行结果回调,可为null
*/
void setTextMode(int vnAppId, int mode, VNCommonCallBack vnCommonCallBack)
```
- **设置译文显示模式** 语音翻译业务时界面`仅显示译文`或`译文和原文都显示`:
```java
/**
* @param vnAppId 应用,与setView()对应。
* @param mode 模式:
* VNConstant.SttConfig.TransMode.TRANSLATION_ONLY - 仅显示翻译文本
* VNConstant.SttConfig.TransMode.ORIGINAL_AND_TRANSLATION - 同时显示翻译文本和原文
* @param vnCommonCallBack 执行结果回调,可为null。
*/
void setTransMode(int vnAppId, int mode, VNCommonCallBack vnCommonCallBack)
```
- **设置字号**
```java
// 字号配置
FontConfig fontConfig = new FontConfig();
fontConfig.setWeight(30); // 字体大小,整数类型,建议 30
fontConfig.setWordSpace(1); // 字间距,整数类型,控制字符之间的间距
fontConfig.setRowSpace(8); // 行间距,整数类型,控制行与行之间的间距
/**
* @param vnAppId 应用,与 setView() 对应。
* @param fontConfig 字号配置。
* @param vnCommonCallBack 执行结果回调,可为 null。
*/
void setFontConfig(int vnAppId, FontConfig fontConfig, VNCommonCallBack vnCommonCallBack);
```
- **设置当前语种信息提示**
```java
// 语种信息提示配置
LanguageHint languageHint = new LanguageHint();
languageHint.setMode(1); // 0 - 仅显示源语言;1 - 源语言与目标语言双向显示
languageHint.setSource("中文");
languageHint.setTarget("English");
/**
* @param vnAppId 应用,与 setView() 对应。
* @param languageHint 语种信息提示配置
* @param vnCommonCallBack 执行结果回调,可为 null。
*/
void setLanguageHint(int vnAppId, LanguageHint languageHint, VNCommonCallBack vnCommonCallBack)
```
- **设置当前拾音指示** 指示当前是`手机拾音`或是`眼镜设备拾音`:
```java
/**
* @param vnAppId 应用,与setView()对应。
* @param audioSource 音源:
* VNConstant.SttConfig.AudioSource.PHONE - 使用手机麦克风作为音频输入源
* VNConstant.SttConfig.AudioSource.GLASSES - 使用眼镜设备麦克风作为音频输入源
* @param vnCommonCallBack 执行结果回调,可为null。
*/
void setAudioSourceIndicator(int vnAppId, int audioSource, VNCommonCallBack vnCommonCallBack)
```
> 📝 **注意:** 仅图标指示。实际音源切换通过 Android 平台标准 API 实现。
- **设置麦克风拾音方向** 当眼镜设备拾音时,拾音方向为`前向`或`全向`:
```java
/**
* @param vnAppId 应用,与setView()对应。
* @param micDirectional 拾音方向:
* VNConstant.SttConfig.MicDirectional.OMNI - 全向收音,接收来自各个方向的声音
* VNConstant.SttConfig.MicDirectional.FRONT - 定向收音,主要接收正前方向的声音
*/
void setMicDirectional(int vnAppId, int micDirectional, VNCommonCallBack vnCommonCallBack)
```
> 📝 **注意:** 仅当前为**眼镜设备拾音**时生效。
**步骤三:发送语音转文字内容**
开发者可以通过`VNSttInfo`描述实时转写的内容和状态,包括消息ID、类型、内容、显示区域等。支持根据**消息ID**进行新增、更新更正、移除对应消息:
- `msgId`:消息ID,整数类型,用于多消息同步更新的会话场景,相同msgId的消息会被关联处理。
- `transcribeStr`:转写文本内容,字符串类型
- `translateStr`:翻译文本内容,字符串类型
- `msgType`:消息类型
- `VNConstant.SttInfo.MsgType.STT` 转写内容消息
- `VNConstant.SttInfo.MsgType.HINT` 提示消息,如“正在听...”“网络波动”等提示,HINT类型消息不会进入历史显示。
- `area`:显示区域,对话场景
- `VNConstant.SttInfo.Area.LEFT` 居左
- `VNConstant.SttInfo.Area.RIGHT` 居右
- `VNConstant.SttInfo.Area.CENTER` 居中
- `actionType`:动作类型,用于指定是新建还是更新消息
- `VNConstant.SttInfo.ActionType.NEW` 新建一个语句
- `VNConstant.SttInfo.ActionType.UPDATE` 更新更正语音转文字内容,用于实时场景
- `VNConstant.SttInfo.ActionType.REMOVE` 移除语句
- `isFinal`:最终更正结果标志,如果界面停在 isFinal 条目,则支持划动触控板向前浏览
场景一:顺序推送实时转写结果,不会出现更新历史句、移除某句的场景时,可以不指定`msgId`,而是通过`actionType`来控制句子更新,`NEW`新增一句、`UPDATE`更新更正上一次推送:
```java
// 示例:新建一句
VNSttInfo sttInfo = new VNSttInfo();
sttInfo.setTranscribe(transcribeStr);
sttInfo.setTranslate(translateStr);
sttInfo.setMsgType(VNConstant.SttInfo.MsgType.STT);
sttInfo.setActionType(VNConstant.SttInfo.ActionType.NEW);
VNCommon.updateSttInfo(vnAppId, sttInfo, null);
// 示例:更新上一次推送
VNSttInfo sttInfo = new VNSttInfo();
sttInfo.setTranscribe(transcribeStr);
sttInfo.setTranslate(translateStr);
sttInfo.setMsgType(VNConstant.SttInfo.MsgType.STT);
sttInfo.setActionType(VNConstant.SttInfo.ActionType.UPDATE);
VNCommon.updateSttInfo(vnAppId, sttInfo, null);
```
场景二:当 [文本显示模式](#CUSTOM_61_STEP2_setTextMode) 切换为`含历史`时,可能更新历史句,或可能删除某句的业务场景时,需要指定 `msgId` 来实现:
```java
// 示例:更新更正msgId句
VNSttInfo sttInfo = new VNSttInfo();
sttInfo.setMsgId(msgId);
sttInfo.setTranscribe(transcribeStr);
sttInfo.setTranslate(translateStr);
sttInfo.setMsgType(VNConstant.SttInfo.MsgType.STT);
sttInfo.setActionType(VNConstant.SttInfo.ActionType.UPDATE);
VNCommon.updateSttInfo(vnAppId, sttInfo, null);
// 示例:移除某msgId句
VNSttInfo sttInfo = new VNSttInfo();
sttInfo.setMsgId(msgId);
sttInfo.setActionType(VNConstant.SttInfo.ActionType.REMOVE);
VNCommon.updateSttInfo(vnAppId, sttInfo, null);
```
**步骤四:退出转写应用**
```java
// 返回主页
VNCommon.setView(VNConstant.View.HOME, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 6.2 实时转写(语音转文字显示)信息同步
使用步骤同 [6.1 实时翻译(语音转文字显示)信息同步](#61-实时翻译语音转文字显示信息同步),调整:
- 将所有vnAppId参数换为VNConstant.View.TRANSCRIBE
- 移除sttInfo.setTranscribe(transcribeStr);
## 6.3 对话信息同步
用于语音助手等问答场景,界面支持区分左右条目:
使用步骤同 [6.1 实时翻译(语音转文字显示)信息同步](#61-实时翻译语音转文字显示信息同步),调整:
- 将所有vnAppId参数换为 `VNConstant.View.AI`;
- 通过sttInfo.setArea()设置该句的显示区域;
## 6.4 导航信息同步
将`实时导航信息`同步至设备端显示的步骤如下:
**步骤一:进入导航应用**
```java
// 切换到导航应用界面
VNCommon.setView(VNConstant.View.MAP, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤二:发送导航信息**
```java
// 创建导航信息对象
VNNavInfo navInfo = new VNNavInfo();
// 设置导航信息参数
navInfo.setCurStepRetainDistance("500米"); // 当前导航段剩余距离
navInfo.setNextRoadName("前方道路名称"); // 下一条道路名称
navInfo.setSpeed("60km/h"); // 当前行驶速度
navInfo.setRemainDistance("17.2公里"); // 剩余里程
navInfo.setRemainTime("22分钟"); // 剩余时间
navInfo.setNavMode(1); // 导航模式 1-驾驶
Bitmap customIcon = ...; // 自定义图标位图
String iconBmpData = VNCommon.getVenusBmpRawData(customIcon, width, height, true);
navInfo.setIconBitmap(iconBmpData);
// 发送导航信息到设备
VNCommon.updateNav(navInfo, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
- 图标尺寸建议:48x48,使用 `VNCommon.getVenusBmpRawDataNav(bitmap, 48, 48)`
**步骤三:退出导航应用**
```java
// 返回主页
VNCommon.setView(VNConstant.View.HOME, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 6.5 提词信息同步
本功能支持将`txt`格式的文件同步至设备端显示。
**步骤一:进入提词应用**
```java
// 切换到提词应用界面
VNCommon.setView(VNConstant.View.PROMPTER, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤二(可选):设置界面偏好**
- **设置是否显示上下文** 界面显示上一页的末行和下一页的首行
```java
// 设置是否显示上下文:0 - 不显示,1 - 显示
VNCommon.setPrompterContextLine(1, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
- **设置字号**
```java
// 字号配置
FontConfig fontConfig = new FontConfig();
fontConfig.setWeight(30); // 字体大小,整数类型,建议 30
fontConfig.setWordSpace(1); // 字间距,整数类型,控制字符之间的间距
fontConfig.setRowSpace(8); // 行间距,整数类型,控制行与行之间的间距
/**
* @param vnAppId 应用,与setView()对应。
* @param fontConfig 字号配置。
* @param vnCommonCallBack 执行结果回调,可为null。
*/
void setFontConfig(int vnAppId, FontConfig fontConfig, VNCommonCallBack vnCommonCallBack);
```
> ⚠️ 重要:不支持提词过程中设置字号,须在设置文件之前完成字号设置
**步骤三:监听提词动态** 获取眼镜设备端实时显示内容和进度
```java
VNCommon.setPrompterListener(new VNPrompterListener() {
@Override
public void onPageChanged(VNPrompterPage p) {
// 进度
int curPage = p.getCurrent();
int totalPage = p.getTotal();
// 当前显示的正文
String curContent = p.getCurText().getContent(); // 文本内容
int curStart = p.getCurText().getStart(); // 在原文档的起始位置(字节)
int curEnd = p.getCurText().getEnd(); // 在原文档的结束位置(字节)
// 当前显示的上下文
String preContent = p.getPreText().getContent();
int preStart = p.getPreText().getStart();
int preEnd = p.getPreText().getEnd();
String nextContent = p.getNextText().getContent();
int nextStart = p.getNextText().getStart();
int nextEnd = p.getNextText().getEnd();
}
@Override
public void onLoadStart() {
// 文档加载开始。根据文档大小,加载时间不同,加载过程中须提示用户
}
@Override
public void onLoadEnd() {
// 文档加载完成。完成后可以设置目标页面。
}
});
```
**步骤四:设置提词文档**
将当前App可访问的`txt`文件通过setPrompterFile接口通知设备端进行加载:
onSuccess():加载成功,进行下一步,参考 [显示目标页面](#CUSTOM_65_STEP5) 的说明;
onFailed():加载失败,需通过 [上传文件](#CUSTOM_55_3) 后重试。
```java
// 示例:将file设置为题词文件
VNCommon.setPrompterFile(file, new VNCommonCallBack() {
@Override
public void onSuccess() {
// 设备端检查文件通过,进行下一步,设置页面显示
}
@Override
public void onTimeOut() {
// 检查超时,提示用户或重试
}
@Override
public void onFailed() {
// 设备端检查文件未通过,需上传file文件后再试
}
});
```
> ⚠️ **重要:** 仅支持utf-8编码的txt格式文档
> 📝 **注意:** 建议文件大小不超过 30 KB
**步骤五:显示目标页面**
当文档设置成功后,通过此接口显示目标页面:
```java
// 示例:显示首页
VNPrompterPage vnPrompterPage = new VNPrompterPage();
vnPrompterPage.setCurrent(1);
VNCommon.setPrompterPage(vnPrompterPage, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤六:翻页**
可通过设备触控区域前后滑动翻页,也可通过调用API发送翻页指令:
```java
// 示例:前一页
VNCommon.setPrompterPageUp(new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
// 示例:后一页
VNCommon.setPrompterPageDown(new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤七:退出题词**
```java
// 示例:返回主页
VNCommon.setView(VNConstant.View.HOME, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
## 6.6 图库
**步骤一:进入图库应用**
```java
VNCommon.setView(VNConstant.View.GALLERY, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
**步骤二:显示图片**
- **显示已在眼镜设备上存在的图片**
通过 [文件列表](#CUSTOM_55_2) 获取Gallery类型的VNFile列表,选择列表中文件显示:
```java
// 示例:或通过设备端文件对象
VNCommon.setGalleryFile(vnFile, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
- **上传 APP 端图片到眼镜设备并显示**
通过 [上传文件](#CUSTOM_55_3) 上传Gallery类型的file文件,上传成功后显示:
```java
// 示例:
File file = new File("/xxx/xxx.jpg");
VNCommon.setGalleryFile(file, new VNCommonCallBack() {
@Override
public void onSuccess() {
// 设备端检查文件通过,显示图片
}
@Override
public void onTimeOut() {
// 检查超时,提示用户或重试
}
@Override
public void onFailed() {
// 设备端检查文件未通过,需上传file文件后再试
}
});
```
> **⚠️ 重要:** 图片文件需由 APP 端预处理:
> - 分辨率:根据设备型号查询
> - 文件大小:建议不超过 200 KB
> - 图像:灰度图
**步骤三:退出图库**
```java
// 示例:返回主页
VNCommon.setView(VNConstant.View.HOME, new VNCommonCallBack() {
@Override public void onSuccess() { }
@Override public void onTimeOut() { }
@Override public void onFailed() { }
});
```
# 7. 应用定制
联系我们
# 8. 固件升级
固件升级服务通过专用数据通路(VNOTA)工作,在进行固件升级之前,需要先断开与设备的消息服务通路(VNCommon):
```
+-------------+ +------------+ +-----------+
| Application | | VNCommon | | VNOTA |
+-------------+ +------------+ +-----------+
| | |
| 检查VNCommon连接状态 | |
|---------------------->| |
| | |
| 如果已连接,断开VNCommon |
|---------------------->| |
| | |
| 等待VNCommon完全断开 | |
| | |
| 初始化VNOTA | |
|--------------------------------------------->|
| | |
| 连接VNOTA | |
|--------------------------------------------->|
| | |
| | onConnected |
|<---------------------------------------------|
| | |
| | onStateChanged(2305) |
|<---------------------------------------------|
| | |
| 开始OTA升级 | |
|--------------------------------------------->|
| | |
| | onProgressChanged |
|<---------------------------------------------|
| | |
| | onSuccess/onError|
|<---------------------------------------------|
| | |
| 断开VNOTA连接 | |
|--------------------------------------------->|
| | |
| | onDisconnected |
|<---------------------------------------------|
| | |
| 重新连接VNCommon | |
|---------------------->| |
| | |
```
1. **准备阶段**
- 检查设备电量是否满足升级要求,建议电量在 40% 以上;
- 检查OTA文件是否有效,且本地存储路径可访问。
2. **断开VNCommon连接**
- 如有自动重连机制,请停止;
- 断开VNCommon连接: `VNCommon.disconnect()`;
- 等待并确认VNCommon已断开。
```java
// 断开消息服务通路
VNCommon.disconnect();
// 检查连接状态,如通过轮询
new Runnable() {
@Override
public void run() {
if (retryCount < maxRetries) {
if (VNCommon.isConnected()) {
retryCount++;
handler.postDelayed(this, 1000);
} else {
// TODO 已断开连接,可以进行固件升级操作
}
}
}
};
// 确认断开连接后再进行固件升级操作
```
3. **设置OTA状态监听**
```java
VNOTA.setOtaServiceListener(new VNOtaServiceListener() {
@Override
public void onConnected() {
// 服务已连接
}
@Override
public void onDisconnected() {
// 服务已断开
}
@Override
public void onStateChanged(int state, String msg) {
// 升级过程中阶段变化提示
if (state == 2305) {
VNOTA.startOta();
}
}
@Override
public void onProgressChanged(String progress) {
// 升级进度变更
}
@Override
public void onSuccess() {
// OTA升级成功
// TODO VNCommon.connect()
}
@Override
public void onError(int code, String msg) {
// OTA升级失败
// code: 错误码,具体定义参考 VNConstant.Ota.ErrorCode
// msg: 错误信息
}
});
```
4. **初始化并连接VNOTA**
```java
BluetoothDevice device = null; // 蓝牙设备实例
String otaFilePath = ""; // 升级文件路径
int otaUser = VNConstant.Ota.User.FIRMWARE; // FIRMWARE表示固件升级
VNOTA.initOta(device, otaFilePath, otaUser);
//连接设备的OTA服务链路
VNOTA.connect(device)
```
5. **执行OTA升级**
- 在VNOTA连接成功后SDK内部会开始协商,请等待`onStateChanged`
- ⚠️ 重要:当`onStateChanged`收到 `state == 2305` 时,开始OTA: `VNOTA.startOta()`
- 通过监听器接收升级进度: `onProgressChanged()`
```java
...
@Override
public void onStateChanged(int state, String msg) {
if (state == 2305) {
VNOTA.startOta();
}
}
...
```
5. **OTA完成处理**
- 升级成功: `onSuccess()`
- 断开VNOTA连接: `VNOTA.disconnect()`;
- 如有,清除本地设备信息,待重新连接后获取升级后的设备信息;
- 建立VNCommon连接:`VNCommon.disconnect()`。
- 升级失败: `onError()`
- 断开VNOTA连接: `VNOTA.disconnect()`;
- 显示错误对话框,重试或退出。
> 📝 **注意:**
> 1. 在进行 OTA 升级时,需要确保设备电量充足(至少 40%);
> 2. OTA 升级过程中不应中断,可能导致设备固件损坏;
> 3. 在 OTA 升级完成后,正常情况下设备会自动重启,启动时间比正常开机用时长 1 - 2 分钟。
# 9. 常见问题
## 9.1 设备无法扫描到
- 检查设备是否开机并停留在蓝牙配对界面
- 检查设备是否已与其他终端配对并连接
## 9.2 设备没有声音
- 检查系统蓝牙连接状态,需要 A2DP、HFP 连接正常
# 10. 更新历史