# EZOpenSDK Android 配网

> 本文档涵盖配网 SDK API 调用方式、参数含义、错误码，以及完整配网流程中各页面的内容描述。

## 配网流程页面概览

配网是一个多步骤的向导流程，包含以下页面：

### 流程全景图

```
主页[右上角添加按钮]
     │
     ▼
[1] 扫描二维码
     │ 扫码成功 / 手动输入
     ▼
[1.5] 输入序列号 — 可选
     │ 确认
     ▼
[2] 设备确认
     │ probeDeviceInfo 查询
     │ ┌── 设备在线未添加 → [添加设备] 直接 addDevice → 回设备列表
     │ └── 设备离线/未注册 → 勾选协议 → 下一步
     ▼
[3] 初始化设备
     │ 勾选"指示灯蓝色快闪"
     │   ├── 指示灯未闪 → 重置 Wi-Fi 页
     │   └── 下一步
     ▼
[4] 选择 Wi-Fi
     │ ├── 选择网络 → Wi-Fi 列表页
     │ └── 下一步（填好 SSID/密码）
     ▼
[5] 选择配网方式
     │ 根据设备能力集显示 AP / 声波 / Smart / 组合
     │ 点击一种方式
     ▼
[6] 正在配置
     │ 进度环 + 步骤列表
     ▼
[完成] 返回主页设备列表
```

### 共用视觉元素

- **步骤条**：页面顶部 4 段横条，根据当前步骤高亮（完成=蓝色，待定=灰色）
- **底部主按钮**：全圆角蓝色胶囊按钮，不可用状态半透明
- **导航栏**：左侧返回按钮 + 中间标题

### 页面 1：扫描二维码

**页面内容**：
- 全屏相机预览 + 方形取景框（4 个角标 + 扫描线动画）
- 顶部栏：返回按钮、标题"扫描二维码"、右侧"手动输入"入口
- 底部操作区：闪光灯按钮、相册按钮
- 底部提示卡片："请扫描设备机身或说明书上的二维码进行设备添加" + 小图标

**业务逻辑**：
- 扫描 QR 码
- 二维码解析支持多种格式（详见下方"二维码解析规则"章节）
- 支持从相册选图识别二维码
- 需要相机权限，拒绝则提示并退出
- 防重复扫描

**跳转**：扫码成功 → 设备确认页；点击手动输入 → 输入序列号页

### 页面 1.5：输入序列号

**页面内容**：
- 顶部说明文字："在设备上查看设备序列号、验证码并在此输入"
- 引导图：设备标签示意图
- 序列号输入框：最大 9 位，大写字母模式，右侧清空按钮
- 验证码输入框：最大 8 位，大写字母模式，右侧清空按钮
- 底部"确认"按钮

**业务逻辑**：
- 确认按钮启用条件：序列号长度 == 9 且验证码长度 >= 6
- 清空按钮：有文本时显示，点击清空

**跳转**：确认 → 设备确认页

### 页面 2：设备确认

**页面内容（两种状态）**：

**加载状态**：
- 搜索动画
- 提示文字："正在查询设备信息，请稍等…"

**结果状态**：
- 设备图片（从 `defaultPicPath` 加载）
- 设备名称（`displayName`）
- 红色错误信息（可选，根据错误码显示）
- 勾选项："阅读并同意产品服务使用协议"
- 勾选项："设备已通电"（仅配网分支显示）
- 底部按钮："下一步"或"添加设备"

**业务逻辑**：
- 进入页面后子线程调用 `probeDeviceInfo`
- **分支 A（设备在线未添加）**：显示设备信息 + 单勾协议 + "添加设备"按钮，点击直接 addDevice
- **分支 B（设备需要配网）**：显示设备信息 + 双勾（协议+通电）+ "下一步"按钮
- 错误码分类处理（详见本文档第七章 7.1 节）

**跳转**：分支 A 添加成功 → 回主页；分支 B 下一步 → 初始化设备页

### 页面 3：初始化设备

**页面内容**：
- 步骤条（第 2 步高亮）
- 设备图片（与设备确认页一致）
- 说明文字："请将设备插上电源，耐心等待约1分钟，直到指示灯呈蓝色快速闪烁"
- 勾选项："指示灯已经蓝色快闪"
- 底部"下一步"按钮（勾选后启用）
- 文字链接："指示灯没有蓝色快闪？"

**跳转**：下一步 → 选择 Wi-Fi 页；文字链接 → 重置 Wi-Fi 页

### 页面 3.5：重置 Wi-Fi

**页面内容**：
- 引导图：Reset 按钮示意图
- 说明文字："请根据图示长按 reset 键，直到设备提示重置成功后松开"
- 底部"下一步"按钮
- 文字链接："我连接了网线"

**跳转**：下一步 → 返回初始化设备页；"我连接了网线" → 提示信息

### 页面 4：选择 Wi-Fi

**页面内容**：
- 步骤条（第 3 步高亮）
- SSID 输入框（只读，点击跳转 Wi-Fi 列表页）+ 右侧"选择网络"按钮
- 密码输入框 + 右侧密码可见性切换按钮（眼睛图标）
- 提示文字："若无密码则无需输入"
- 底部"下一步"按钮（SSID 非空才启用）

**业务逻辑**：
- 进入页面自动获取手机当前连接的 Wi-Fi（非 5G 才填入）
- 自动从缓存回填对应 SSID 的密码
- 密码可见性切换

**跳转**：选择网络 → Wi-Fi 列表页；下一步 → 选择配网方式页

### 页面 4.5：Wi-Fi 列表

**页面内容**：
- 标题："选择 Wi-Fi"
- 说明文字："请选择家庭或商铺路由器的 Wi-Fi，如超过一个网络源，请选择距离设备安装位置最近的"
- "找不到想连接的网络"文字 + 右侧刷新按钮
- Wi-Fi 列表：每项显示 SSID + 信号强度图标
- 5G Wi-Fi 条目：灰化 + 标注"此设备不支持 5GHz"，不可点击

**业务逻辑**：
- 扫描周围 Wi-Fi（需定位权限）
- 按 SSID 去重
- 5G 频段判定：frequency > 4900

**跳转**：点击非 5G 条目 → 返回 SSID 给选择 Wi-Fi 页

### 页面 5：选择配网方式

**页面内容**：
- 步骤条（第 3 步高亮）
- 配网方式卡片列表（根据设备能力集动态显示）：
  - AP 配网："连接设备热点进行配网，兼容性更广"
  - 声波配网："通过手机扬声器发送声波信号配网"
  - Smart 配网："通过 Wi-Fi 广播方式快速配网"
  - 声波/Smart 组合配网："同时使用声波和 Smart 配网，成功率更高"
- 每张卡片：左侧图标 + 中间名称/描述 + 右侧箭头

**业务逻辑**：
- 根据 `EZProbeDeviceInfo` 的 `getSupportAP()==2`、`getSupportSoundWave()==1`、`getSupportWifi()>0` 动态显示
- 组合配网仅在声波和 Smart 都支持时显示

**跳转**：点击一种方式 → 正在配置页

### 页面 6：正在配置

**页面内容**：
- 步骤条（4 段全部高亮）
- 圆形进度环 + 中间百分比数字
- 初始提示文字："正在配置设备网络，请耐心等待"（连接成功后隐藏）
- 步骤列表（逐步显示）：
  - "成功连接网络 ✓"
  - "正在注册到平台" → "设备已连接并注册到平台 ✓"
  - "正在绑定账号" → "成功绑定账号 ✓"
  - "配置完成 ✓"
- 底部"完成"按钮（成功或失败时显示）
- 失败时：红色失败提示 + 按钮变为"重试"

**业务逻辑**：
- 进度条自增，绑定成功后跳到 100%
- 根据选择的配网方式调用对应配网 API（AP/声波/Smart/组合）
- 收到"连接网络"回调时缓存 Wi-Fi 密码
- 收到"注册到平台"回调后调用 addDevice 绑定
- addDevice 的 120023 错误码视为成功
- 忽略 `PHONE_NOT_CONNECTED_TO_TARGET_WIFI` 错误码（AP 配网预期中间状态）

**跳转**：完成 → 回主页设备列表

### 页面返回导航

配网流程中，用户点击返回按钮应逐页返回上一步（而非直接关闭 Activity）：

| 当前页面 | 返回目标 | 说明 |
|---------|---------|------|
| 设备输入 | 关闭 Activity | 回到设备列表 |
| 设备确认 | 设备输入 | 保留已输入的序列号/验证码 |
| 初始化设备 | 设备确认 | 保留勾选状态 |
| 重置WiFi | 初始化设备 | 保留勾选状态 |
| WiFi 选择 | 初始化设备 | 保留已选择的 WiFi 信息 |
| 配网方式选择 | WiFi 选择 | 保留已输入的密码 |
| 配网进度 | 不允许返回 | 正在配网中 |
| 配网结果 | 关闭 Activity | 回到设备列表 |

**关键原则**：返回时只切换页面可见性，不重置已有的输入/勾选状态。

### 生命周期清理

配网页面退出时必须调用：
```java
EZOpenSDK.getInstance().stopConfigWiFi();
EZOpenSDK.getInstance().stopAPConfigWifiWithSsid();
```



## 配网模块 import 参考

```java
// AP 配网
import com.videogo.openapi.EZOpenSDK;
import com.videogo.wificonfig.APWifiConfig;                              // AP 配网回调
import com.ezviz.sdk.configwifi.EZConfigWifiInfoEnum;                   // AP 配网信息枚举（注意：不在 com.videogo 包下）
import com.ezviz.sdk.configwifi.EZConfigWifiErrorEnum;                  // AP 配网错误枚举（注意：不在 com.videogo 包下）

// 声波配网 / Smart 配网
import com.videogo.openapi.EZConstants;                                  // EZWiFiConfigMode、EZWifiConfigStatus
import com.videogo.openapi.EZOpenSDKListener;                            // EZStartConfigWifiCallback

// 接触式 AP 配网
import com.ezviz.sdk.configwifi.touchAp.GetTokenCallback;               // 获取配网 token 回调
import com.ezviz.sdk.configwifi.touchAp.GetAccessDeviceInfoCallback;    // 获取设备信息回调
import com.ezviz.sdk.configwifi.touchAp.StartNewApConfigCallback;       // 配置设备网络回调
import com.ezviz.sdk.configwifi.touchAp.QueryPlatformBindStatusCallback; // 轮询绑定状态回调
import com.ezviz.http.model.DeviceTokenInfo;                             // 配网 token 对象
import com.ezviz.http.model.AccessDeviceInfo;                            // 设备信息对象
import com.ezviz.http.exception.EzConfigWifiException;                   // 配网异常

// 设备探测
import com.videogo.openapi.bean.EZProbeDeviceInfoResult;
import com.videogo.openapi.bean.EZProbeDeviceInfo;
```

## 一、配网方式概览

| 配网方式 | 说明 |
|----------|------|
| AP 配网 | 设备创建临时热点，手机连接后传输 WiFi 信息。一般设备都支持 |
| 声波配网 | 通过特定频率声波传输配网信息 |
| 一般配网（Smart） | SDK 自动选择配网模式 |
| 接触式 AP 配网 | 适用于防跌倒雷达、宠物喂食机等无二维码设备 |
| 网线配网 | 插网线后直接绑定 |

## 二、配网方式选择

通过 probeDeviceInfo 获取设备能力后判断：

```java
EZProbeDeviceInfoResult result = EZOpenSDK.getInstance().probeDeviceInfo(deviceSerial, deviceType);
EZProbeDeviceInfo info = result.getEZProbeDeviceInfo();
```

选择逻辑：
1. `info.getSupportAP() == 2` → 只需接入 AP 配网即可
2. 不支持 AP 且 `info.getSupportSoundWave() == 1` → 接入声波配网
3. 不支持 AP 且 `info.getSupportWifi() == 3` → 接入 Smart 配网
4. 同时支持声波和 Smart → 混合模式（mode = EZWiFiConfigSmart | EZWiFiConfigWave）
5. 接触式 AP → 无二维码的特殊设备
6. 网线配网 → 插网线后直接 addDevice

## 三、AP 配网

### 流程
1. 权限配置（本地网络权限 + 定位权限）
2. 查询设备信息 probeDeviceInfo
3. 调用 startAPConfigWifiWithSsid 发起配网
4. 调用 addDevice 添加设备

### 查询设备信息
```java
new Thread(() -> {
    EZProbeDeviceInfoResult result = EZOpenSDK.getInstance().probeDeviceInfo(serialNo, deviceType);
    if (result != null && result.getBaseException() == null) {
        // 查询成功，设备在线未添加
        // 注意：即使有错误码，getEZProbeDeviceInfo() 仍可能返回设备信息（含能力集）
        EZProbeDeviceInfo info = result.getEZProbeDeviceInfo();
        String prefix = EZBusinessTool.getWiFiConfigPrefix(info.getDeviceHotSpot());
    } else if (result != null) {
        int errorCode = result.getBaseException().getErrorCode();
        // 重要：有错误码时也要获取设备信息，用于提取能力集
        EZProbeDeviceInfo info = result.getEZProbeDeviceInfo();
        // info 可能不为 null，包含 supportAP、supportSoundWave、supportWifi 等能力集
        // 根据错误码处理（见 ezopensdk-device.md 设备探测章节）
    }
}).start();
```

### 发起 AP 配网
```java
// 注意：startAPConfigWifiWithSsid 是异步 API（接收回调），可在主线程直接调用
EZOpenSDK.getInstance().startAPConfigWifiWithSsid(
    wifiSsid,              // WiFi 名称
    wifiPwd,               // WiFi 密码
    deviceSerial,          // 设备序列号
    deviceVerifyCode,      // 设备验证码
    deviceHotspotName,     // 设备热点名称（EZVIZ_ 开头可传空）
    deviceHotspotPwd,      // 设备热点密码（可传空）
    autoConnect,           // 是否自动连接设备热点
    new APWifiConfig.APConfigCallback() {
        @Override
        public void onSuccess() {
            // WiFi 信息已发送给设备（密码可能错误，设备不一定联网成功）
        }

        @Override
        public void onInfo(int code, String message) {
            if (code == EZConfigWifiInfoEnum.CONNECTED_TO_PLATFORM.code) {
                // 设备已注册到平台，可以添加设备
                addDevice(deviceSerial, verifyCode);
            }
        }

        @Override
        public void OnError(int code) {
            // 错误处理
            if (code == EZConfigWifiErrorEnum.CONFIG_TIMEOUT.code) {
                // 配网超时
            }
        }
    }
);
```

### 停止 AP 配网
```java
EZOpenSDK.getInstance().stopAPConfigWifiWithSsid();
```

### 添加设备
```java
boolean success = EZOpenSDK.getInstance().addDevice(deviceSerial, verifyCode);
```
当状态为 CONNECTED_TO_PLATFORM 时方可添加成功。

### 设备热点前缀
```java
// 0-EZVIZ，1-SoftAP，2-CAMGO
String prefix = EZBusinessTool.getWiFiConfigPrefix(deviceHotSpot);
```
v5.17 起 SDK 已自动适配定制设备热点前缀。

## 四、声波配网 & 一般配网（Smart）

### 发起配网
```java
// 注意：startConfigWifi 是异步 API（接收回调），可在主线程直接调用
int mode = 0;
mode |= supportWifi ? EZConstants.EZWiFiConfigMode.EZWiFiConfigSmart : 0;
mode |= supportSoundWave ? EZConstants.EZWiFiConfigMode.EZWiFiConfigWave : 0;

EZOpenSDK.getInstance().startConfigWifi(
    context,
    deviceSerial,
    wifiSsid,
    wifiPassword,
    mode,
    new EZOpenSDKListener.EZStartConfigWifiCallback() {
        @Override
        public void onStartConfigWifiCallback(String deviceSerial, EZConstants.EZWifiConfigStatus status) {
            if (status == EZConstants.EZWifiConfigStatus.DEVICE_WIFI_CONNECTING) {
                // 正在连接
            } else if (status == EZConstants.EZWifiConfigStatus.DEVICE_WIFI_CONNECTED) {
                // WiFi 已连接
            } else if (status == EZConstants.EZWifiConfigStatus.DEVICE_PLATFORM_REGISTED) {
                // 已注册到平台，可以添加设备
                addDevice(deviceSerial, verifyCode);
            }
        }
    }
);
```

### 停止配网
```java
EZOpenSDK.getInstance().stopConfigWiFi();
```

## 五、接触式 AP 配网

适用于防跌倒雷达、宠物喂食机等无二维码设备。

### 流程
```java
// 1. 获取配网 token
EZOpenSDK.getInstance().getNewApConfigToken(new GetTokenCallback() {
    @Override
    public void onGetTokenSuccess(DeviceTokenInfo tokenInfo) {
        String token = tokenInfo.token;
        String lbsDomain = tokenInfo.lbsDomain;
    }
});

// 2. 用户手动连接设备热点（去系统设置页面）

// 3. 获取设备信息
EZOpenSDK.getInstance().getAccessDeviceInfo(new GetAccessDeviceInfoCallback() {
    @Override
    public void onGetAccessDeviceInfoSuccess(AccessDeviceInfo info) {
        String devSubserial = info.devSubserial; // 设备序列号
    }
});

// 4. 配置设备网络
EZOpenSDK.getInstance().startNewApConfigWithToken(
    token, wifiSsid, wifiPwd, lbsDomain,
    new StartNewApConfigCallback() {
        @Override
        public void onResponse(int statusCode, String statusDesc) {
            // 开始轮询设备绑定状态
        }
        @Override
        public void onError(EzConfigWifiException e) {
            // 设备关闭热点去连网，也需要发起轮询
        }
    }
);

// 5. 轮询设备绑定状态
EZOpenSDK.getInstance().queryPlatformBindStatus(deviceSerial,
    new QueryPlatformBindStatusCallback() {
        @Override
        public void onBindSuccess() {
            // 设备绑定成功
        }
    }
);
```

## 六、网线配网

给设备插上网线，待设备提示注册平台成功后，直接添加：
```java
boolean success = EZOpenSDK.getInstance().addDevice(deviceSerial, verifyCode);
```

## 七、实战要点

以下是完整配网流程中容易忽略但非常关键的 SDK 使用细节：

### 7.0 API 同步/异步区分

| API | 类型 | 线程要求 |
|-----|------|---------|
| `probeDeviceInfo` | **同步阻塞** | 必须在子线程调用 |
| `addDevice` | **同步阻塞** | 必须在子线程调用 |
| `startAPConfigWifiWithSsid` | **异步回调** | 可在主线程调用，结果通过回调通知 |
| `startConfigWifi` | **异步回调** | 可在主线程调用，结果通过回调通知 |
| `stopConfigWiFi` | 同步 | 建议子线程调用（避免 ANR） |
| `stopAPConfigWifiWithSsid` | 同步 | 建议子线程调用（避免 ANR） |

### 7.0b 二维码解析规则

萤石/海康设备二维码有多种格式，解析优先级如下：

**格式1：海康 URL 格式（hikmall.com / hikvision.com）**
```
https://share.hikmall.com/...?QD=04&SN=FW6913546PTZkXkgSDS-7808N-F1(D)
```
解析规则：
1. 找到 `SN=` 参数位置
2. 取 `SN=` 后面的内容，过滤不可见字符
3. 提取连续字母数字部分（遇到 `-` 等非字母数字字符停止）
4. 前 9 位 = 序列号，接下来 8 位 = 验证码

```java
String afterSN = content.substring(snIndex + 3);
String alphanumeric = afterSN.takeWhile(Character::isLetterOrDigit);
String serial = alphanumeric.substring(0, 9);      // FW6913546
String verifyCode = alphanumeric.substring(9, 17); // PTZkXkgS
```

**格式2：空格/换行分隔格式**
```
ys7 C94219413 GIAIFP CS-C4Wi-3C2WFR
```
解析规则：按空白字符拆分，找到长度为 9 的纯字母数字 = 序列号，长度为 6 的 = 验证码

**格式3：URL 参数格式**
```
https://open.ys7.com/xxx?sn=XXX&vc=XXX
```
解析规则：标准 URL 参数解析，取 `sn` 和 `vc` 参数

**格式4：冒号分隔**
```
FW6913546:PTZkXkgS
```

**验证码长度**：6-8 位（海康 NVR 设备为 8 位，摄像头通常为 6 位）

### 7.1 probeDeviceInfo 返回的错误码区分

**重要：即使返回错误码，`result.getEZProbeDeviceInfo()` 仍可能返回设备信息（包含能力集）。必须在所有分支中都尝试获取设备信息。**

```java
EZProbeDeviceInfoResult result = EZOpenSDK.getInstance().probeDeviceInfo(serialNo, null);
// 无论是否有错误码，都尝试获取设备信息
EZProbeDeviceInfo info = result.getEZProbeDeviceInfo();

if (result.getBaseException() == null) {
    // 设备在线未添加 → 直接 addDevice
} else {
    int errorCode = result.getBaseException().getErrorCode();
    // info 可能不为 null，包含 supportAP、supportSoundWave、supportWifi 等能力集
    // 用于后续配网方式选择
}
```

根据错误码分两类处理：

```java
switch (errorCode) {
    // 设备离线/未注册 → 可以走配网流程
    case 120023:  // 设备不在线，未被用户添加
    case 120002:  // 设备不存在，未被用户添加
    case 120029:  // 设备不在线，已经被自己添加
        goToWifiConfig();
        break;

    // 设备在线或状态异常 → 无需配网，直接显示错误信息
    case 120020:  // 设备在线，已经被自己添加
    case 120022:  // 设备在线，已经被别的用户添加
    case 120024:  // 设备不在线，已经被别的用户添加
    case 120021:  // 设备在线，未被用户添加（不需要配网）
    case 102020:  // 设备版本不支持
    case 102030:  // 设备不支持
    case 120006:  // 网络异常
    case 150000:  // 服务器异常
    case 110002:  // access_token 异常
    case 120004:  // 硬件特征码验证失败
        showError(result.getBaseException().getErrorInfo().description);
        break;
}
```

### 7.2 根据设备能力集选择配网方式

`EZProbeDeviceInfo` 提供了 3 个关键字段：

| 字段 | 含义 | 判断值 |
|------|------|-------|
| `getSupportAP()` | 是否支持 AP 配网 | `== 2` 支持 |
| `getSupportSoundWave()` | 是否支持声波配网 | `== 1` 支持 |
| `getSupportWifi()` | 是否支持 SmartConfig | `> 0` 支持 |

根据 3 个字段的组合动态显示配网方式入口：
- 同时支持 SoundWave + SmartConfig 时，额外提供"组合配网"入口，成功率更高

### 7.3 配网过程中的容错错误码

`EZConfigWifiErrorEnum.PHONE_NOT_CONNECTED_TO_TARGET_WIFI`（常见为 502）：
- AP 配网中，手机从设备热点切换回目标 Wi-Fi 时的短暂中间状态
- **不应该展示为配网失败**，应该忽略并继续等待 `CONNECTED_TO_PLATFORM` 回调

```java
@Override
public void OnError(int code) {
    if (code == EZConfigWifiErrorEnum.PHONE_NOT_CONNECTED_TO_TARGET_WIFI.code) {
        return;   // 忽略，等待后续回调
    }
    showConfigFailed(code);
}
```

### 7.4 addDevice 的 120023 异常要视为成功

设备注册到平台后，部分设备可能立即被自动绑定到用户账号，再调 `addDevice` 会抛 `120023`：

```java
try {
    EZOpenSDK.getInstance().addDevice(mSerial, mVerifyCode);
    onBindSuccess();
} catch (Exception e) {
    if (e.getMessage() != null && e.getMessage().contains("120023")) {
        onBindSuccess();   // 视为成功
    } else {
        onBindFailed();
    }
}
```

### 7.5 Wi-Fi 密码本地缓存

配网成功连接网络后，将 `SSID → 密码` 保存到 `SharedPreferences`，下次选择同一 SSID 时自动回填密码，提升用户体验：

```java
public class WifiPasswordCache {
    private static final String PREF_NAME = "wifi_password_cache";
    public static void save(Context ctx, String ssid, String pwd) {
        if (ssid == null || ssid.isEmpty()) return;
        ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE).edit()
            .putString(ssid, pwd != null ? pwd : "").apply();
    }
    public static String get(Context ctx, String ssid) {
        if (ssid == null || ssid.isEmpty()) return null;
        return ctx.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
            .getString(ssid, null);
    }
}
```

缓存时机：**仅在收到"WiFi 连接成功"回调后保存**（`onSuccess` for AP / `DEVICE_WIFI_CONNECTED` for Smart/Wave），避免错误密码被缓存。

### 7.6 Wi-Fi 列表中过滤 5G 频段

多数摄像头只支持 2.4GHz，不支持 5GHz。UI 上应把 5G 条目灰化并禁止点击：

```java
// 从 ScanResult 判断 5G：frequency > 4900
boolean is5G = scanResult.frequency > 4900;

// 从 WifiInfo 判断当前连接的是否 5G
int freq = wifiInfo.getFrequency();
boolean is5G = (freq >= 4900 && freq <= 5900);
```

### 7.7 SSID 获取时去引号

Android 的 `WifiInfo.getSSID()` 返回值会带 `"`，使用时要去掉：

```java
String ssid = wifiInfo.getSSID();
if (ssid.startsWith("\"") && ssid.endsWith("\"")) {
    ssid = ssid.substring(1, ssid.length() - 1);
}
// 另外要排除 "<unknown ssid>"
```

### 7.8 配网页面退出时必须清理

避免用户中途退出导致 SDK 内部状态污染：

```java
EZOpenSDK.getInstance().stopConfigWiFi();
EZOpenSDK.getInstance().stopAPConfigWifiWithSsid();
```

### 7.9 配网完成后刷新设备列表

配网成功后应返回设备列表页面并触发刷新，保证最新配网的设备出现在列表中。

## 八、配网常见问题

### 公共问题

**Q：SoftAP 等定制设备无法配网**
A：v5.17 起 SDK 已自动适配定制设备热点前缀。旧版本需手动设置 deviceHotspotName 和 deviceHotspotPwd。

**Q：AP 配网故意输错 WiFi 密码，SDK 还在轮询**
A：SDK 将 WiFi 信息发送给设备后，手机和设备没有通讯联系。SDK 只能等待 90 秒轮询设备是否注册到平台，超时后回调配网失败。

**Q：设备配网时提示"当前网络环境复杂"**
A：环境中 WiFi 信号过多，设备未搜索到指定 WiFi。换个信号干扰少的环境重试。

### Android 配网问题

**Q：AP 配网弹出网络连接确认框**
A：Android 10+ 系统使用新 API 连接 WiFi 会弹框确认，这是正常现象。

**Q：AP 配网不断弹框提示是否连接网络**
A：系统缓存了设备热点为"无外网"。解决方案：手动去 WiFi 管理页面删除缓存的同名 WiFi。

**Q：AP 配网错误码含义**
| 错误码 | 含义 |
|--------|------|
| 105 | 配网参数异常 |
| 110 | 仍在执行上次配网，需先调用停止接口 |
| 111 | 手机未接入目标 WiFi |
| 120 | 验证码错误 |
| 15 | 90 秒配网超时 |
| 501 | 未打开定位权限 |
| 502 | AP 配网进行中 |
| 505 | 设备不支持 AP 配网或未重置到 AP 模式 |
| 506 | 用户拒绝连接设备热点（Android 10+） |
| 507 | 打开 WiFi 开关失败 |
| 605 | 手机未连接 WiFi |
| 705 | 手机音量未调到最大（声波配网） |
| 801 | 服务器异常 |
| 802 | 网络异常 |

### 重要提示
账户下删除设备重新配网时，请在重置设备后等待 2 分钟再调用配网接口，等平台确认设备下线后配网成功率更高。
