本文将介绍如何在 Android 平台基于腾讯云物联网设备端 Android SDK,使用动态注册(Dynamic Register)能力,在产品量产阶段由设备自动从云端获取设备密钥,减少客户手动逐个烧录设备密钥的工作量,提升量产效率。
关键概念
动态注册用于产品量产过程中,在控制台批量创建设备后,设备根据
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 为错误描述。常见错误码详见 常见问题。 |
说明:
dynamicRegister 是异步接口,注册结果通过回调异步返回。同一时刻只允许有一个注册请求在途,重复调用会返回
TXIoTError.DYNAMIC_REGISTER_BUSY。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>() {@Overridepublic void onSuccess(String deviceKey) {Log.i(TAG, "dynamic register success, deviceKey=" + deviceKey);// 见步骤 4:使用该密钥登录}@Overridepublic 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; // 使用动态注册获取的密钥deviceInfo.region = "ap-guangzhou";TXIoTDeviceEngine.getInstance(applicationContext).login(deviceInfo, new TXIoTCallback() {@Overridepublic void onSuccess() {Log.i(TAG, "login success");}@Overridepublic 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. 初始化 SDKTXIoTDeviceEngine.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>() {@Overridepublic void onSuccess(String deviceKey) {Log.i(TAG, "dynamic register success, deviceKey=" + deviceKey);loginWithDeviceKey(deviceKey);}@Overridepublic 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;deviceInfo.region = "ap-guangzhou";mEngine.login(deviceInfo, new TXIoTCallback() {@Overridepublic void onSuccess() {Log.i(TAG, "login success");}@Overridepublic 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 已集成动态注册流程,可参考其实现。编译并运行
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 与控制台不一致(解密失败),或响应被中间代理改写。 |
联系我们