一、关键概念
动态注册用于产品量产过程中,在控制台批量创建设备后,设备根据 productId、productSecret、deviceId,从后台获取设备密钥(deviceSecret)。该机制减少客户手动逐个烧录设备密钥的工作量,提升量产效率。
二、适用场景
·量产阶段需要批量激活大量设备,逐一烧录设备密钥成本过高。
·设备出厂时只烧录产品级别的 productSecret,由设备首次联网时自行换取设备密钥。
·设备端希望密钥不固化在产线,降低密钥泄漏风险。
三、名词解释
| 名词 | 说明 |
| productId | 产品标识,在控制台创建产品时生成。 |
| productSecret | 产品密钥,产品级别,用于动态注册时对请求进行 HMAC-SHA256 签名与对响应进行 AES-128-CBC 解密。 |
| deviceId | 设备名称,在控制台批量创建设备时由平台生成或自定义,需与控制台保持一致。 |
| deviceSecret | 设备密钥,动态注册成功后由云端下发,后续登录时使用。 |
四、前提条件
在接入动态注册功能前,请你先完成以下准备工作:
1. 登录 物联网开发平台控制台,创建产品并记录 productId 与 productSecret。
2. 在控制台批量创建设备,记录每台设备的 deviceId。动态注册要求设备名必须先在控制台预创建,否则会返回 Pre create mode: device not exists。
3. 在产品详情页开启动态注册功能。如果未开启,设备端会收到 Not support dynamic device register, please check setting first。
4. 已完成 SDK 初始化(initSDK)流程。动态注册仅需 SDK 初始化,不依赖登录成功。
五、接入步骤
本节介绍如何调用 SDK 完成动态注册的核心调用:初始化 SDK、发起注册请求、在回调中获取设备密钥、使用密钥完成登录。
六、步骤 1:控制台预创建设备并开启动态注册
1. 登录 物联网开发平台控制台,在产品列表中单击创建的产品名称进入详情。
2. 在设备页面单击批量新建设备,生成若干 deviceId。动态注册时传入的 deviceId 必须在此列表中存在。
3. 在产品详情页的动态注册开关处,确认功能已开启。关闭状态下注册请求会被云端拒绝。
七、步骤 2:初始化 SDK
调用 initSDK 完成 SDK 初始化,动态注册依赖 SDK 内部的 HTTP/TLS 能力。初始化成功返回 0(TXIoTError.SUCCESS)。
TXIoTDeviceEngine.Config config = new TXIoTDeviceEngine.Config();config.storagePath = getFilesDir().getAbsolutePath();config.logLevel = TXIoTDeviceEngine.LogLevel.INFO;int ret = TXIoTDeviceEngine.getInstance(applicationContext).initSDK(config);if (ret != TXIoTError.SUCCESS) { Log.e(TAG, "initSDK failed: " + ret); return;}
八、步骤 3:发起动态注册请求
调用 dynamicRegister 发起注册,入参 DynamicRegisterParams:
| 字段 | 说明 |
| productId | 产品标识,必填。 |
| deviceId | 设备名称,必填,需在控制台预创建。 |
| productSecret | 产品密钥,必填,长度需 ≥ 16字节(AES-128 密钥长度要求)。 |
回调 TXIoTValueCallback<String> 参数说明:
| 回调 | 说明 |
| onSuccess(String deviceKey) | 注册成功,deviceKey 为云端下发的设备密钥,后续登录时作为 deviceSecret 使用。 |
| onError(int code, String desc) | 注册失败,code 为错误码,desc 为错误描述。常见错误码详见 常见问题。 |
注意:说明:
TXIoTDeviceEngine.DynamicRegisterParams params = new TXIoTDeviceEngine.DynamicRegisterParams();params.productId = "YOUR_PRODUCT_ID";params.deviceId = "YOUR_DEVICE_ID";params.productSecret = "YOUR_PRODUCT_SECRET";TXIoTDeviceEngine.getInstance(applicationContext).dynamicRegister(params, new TXIoTValueCallback<String>() { @Override public void onSuccess(String deviceKey) { Log.i(TAG, "dynamic register success, deviceKey=" + deviceKey); // 见步骤 4:使用该密钥登录 } @Override public void onError(int code, String desc) { Log.e(TAG, "dynamic register failed: " + code + ", " + desc); }});
九、步骤 4:使用获取的密钥登录
动态注册成功后,在回调中拿到 deviceKey,将其作为 deviceSecret 调用 login 完成登录。建议将密钥持久化到本地存储,避免每次开机都重新注册。
@Overridepublic void onSuccess(String deviceKey) { Log.i(TAG, "dynamic register success, deviceKey=" + deviceKey); // 建议持久化 deviceKey,下次开机直接复用,无需再次动态注册 // saveDeviceSecretToStorage(deviceKey); TXIoTDeviceEngine.DeviceInfo deviceInfo = new TXIoTDeviceEngine.DeviceInfo(); deviceInfo.productId = "YOUR_PRODUCT_ID"; deviceInfo.deviceId = "YOUR_DEVICE_ID"; deviceInfo.deviceSecret = deviceKey; // 使用动态注册获取的密钥 TXIoTDeviceEngine.getInstance(applicationContext).login(deviceInfo, new TXIoTCallback() { @Override public void onSuccess() { Log.i(TAG, "login success"); } @Override public void onError(int code, String desc) { Log.e(TAG, "login failed: " + code + ", " + desc); } });}
注意:deviceKey 属于设备敏感凭证,建议持久化到应用私有目录或 Android Keystore 等安全存储中,避免明文保存或提交到代码仓库。
十、完整示例代码
以下示例整合上述步骤,演示在 Android 应用中完成 SDK 初始化、动态注册、并使用获取的密钥登录的完整流程。
package com.example.iotdemo;import android.content.Context;import android.util.Log;import com.tencent.liteav.iot.TXIoTCallback;import com.tencent.liteav.iot.TXIoTDeviceEngine;import com.tencent.liteav.iot.TXIoTError;import com.tencent.liteav.iot.TXIoTValueCallback;public class DynamicRegisterHelper { private static final String TAG = "DynamicRegister"; private final TXIoTDeviceEngine mEngine; private final String mProductId; private final String mDeviceId; private final String mProductSecret; public DynamicRegisterHelper(Context context, String productId, String deviceId, String productSecret) { mEngine = TXIoTDeviceEngine.getInstance(context.getApplicationContext()); mProductId = productId; mDeviceId = deviceId; mProductSecret = productSecret; } /** 初始化 SDK 并开始动态注册 */ public void start() { // 1. 初始化 SDK TXIoTDeviceEngine.Config config = new TXIoTDeviceEngine.Config(); config.logLevel = TXIoTDeviceEngine.LogLevel.INFO; int ret = mEngine.initSDK(config); if (ret != TXIoTError.SUCCESS) { Log.e(TAG, "initSDK failed: " + ret); return; } // 2. 发起动态注册 TXIoTDeviceEngine.DynamicRegisterParams params = new TXIoTDeviceEngine.DynamicRegisterParams(); params.productId = mProductId; params.deviceId = mDeviceId; params.productSecret = mProductSecret; mEngine.dynamicRegister(params, new TXIoTValueCallback<String>() { @Override public void onSuccess(String deviceKey) { Log.i(TAG, "dynamic register success, deviceKey=" + deviceKey); loginWithDeviceKey(deviceKey); } @Override public void onError(int code, String desc) { Log.e(TAG, "dynamic register failed: " + code + ", " + desc); } }); } /** 3. 使用动态注册获取的密钥登录 */ private void loginWithDeviceKey(String deviceKey) { // 建议持久化 deviceKey,下次开机直接复用,无需再次动态注册 // saveDeviceSecretToStorage(deviceKey); TXIoTDeviceEngine.DeviceInfo deviceInfo = new TXIoTDeviceEngine.DeviceInfo(); deviceInfo.productId = mProductId; deviceInfo.deviceId = mDeviceId; deviceInfo.deviceSecret = deviceKey; mEngine.login(deviceInfo, new TXIoTCallback() { @Override public void onSuccess() { Log.i(TAG, "login success"); } @Override public void onError(int code, String desc) { Log.e(TAG, "login failed: " + code + ", " + desc); } }); } /** 4. 业务完成后释放资源 */ public void release() { mEngine.logout(null); mEngine.uninitSDK(); }}
注意:说明:
注意:1. 动态注册仅依赖 initSDK 成功,无需提前登录;获取到 deviceKey 后再执行 login。
注意:2. Demo 的 LoginActivity 已集成动态注册流程,可参考其实现。
十一、编译并运行
Demo 已开源,仓库地址:github.com/Tencent-RTC/Tencent_IoT_Device,Android Demo 位于顶层 Android/ 目录。
1. 使用 git clone 将开源 Demo 从 GitHub 克隆到本地。
2. 打开 Android Studio,点击 Open 导入工程,等待 Gradle Sync 完成。
3. 连接 Android 真机,点击工具栏 Run 编译运行。
# 也可在控制台打包 APK 后发送到手机安装./gradlew :app:assembleDebug
4. 观察日志输出,出现以下内容代表动态注册与登录均成功。
dynamic register success, deviceKey=xxxxxxxxxxxxxlogin success
十二、常见问题
| 现象 | 排查建议 |
| 动态注册回调提示 Not support dynamic device register, please check setting first。 | 动态注册功能未在控制台开启。请在产品详情页打开动态注册开关后再试。 |
| 动态注册回调提示 Pre create mode: device not exists。 | 传入的 deviceId 在控制台未预创建。请先在控制台批量创建对应设备,确保 deviceId 与控制台一致。 |
| 动态注册回调提示 Device has been activated。 | 该设备已动态注册过且密钥已激活。已注册的设备名再次动态注册会被拒绝,请使用上次获取的密钥登录。 |
| 动态注册获取的密钥未登录,再次注册拿到新密钥。 | 如果动态注册获取的密钥未用于登录,下次仍可执行动态注册,但会获取到新的密钥,之前的密钥同时失效,只能使用最新获取的密钥。 |
| dynamicRegister 返回 DYNAMIC_REGISTER_BUSY(-20) | 上一次注册请求仍在途。SDK 同一时刻只允许一个注册请求,请等待回调返回后再发起新请求。 |
| dynamicRegister 返回 INVALID_ARGUMENT(-3) | 检查 productId、deviceId 是否为空或过长;productSecret 长度是否 ≥ 16字节(AES-128 密钥要求)。 |
| dynamicRegister 返回 NOT_INITIALIZED(-4) | 确认在调用前已成功调用 initSDK。 |
| DYNAMIC_REGISTER_REQUEST_FAILED(-21) | HTTP 请求失败或云端返回错误。请检查网络、productSecret 是否正确、签名是否匹配;查看日志中的错误描述获取具体原因。 |
| DYNAMIC_REGISTER_RESPONSE_INVALID(-22) | 云端响应格式异常或解密失败。常见原因为 productSecret 与控制台不一致(解密失败),或响应被中间代理改写。 |
十三、联系我们
如果你在接入或使用过程中有任何疑问或者建议,欢迎 联系我们 提交反馈。