本文介绍如何进行Java Link SDK初始化,建立设备与物联网平台的连接。
前提条件
已创建产品和设备。具体操作,请参见创建产品和设备。
已获取设备的认证信息以及设备的接入域名。
背景信息
Java Link SDK仅支持设备密钥方式,进行设备身份认证,具体包括以下几种认证方式。
认证方式
注册方式
说明
不涉及
每台设备烧录自己的设备证书(ProductKey、DeviceName和DeviceSecret)。
预注册
同一产品下设备烧录相同产品证书(ProductKey和ProductSecret)。
产品需开启动态注册功能。
设备通过动态注册获取DeviceSecret。
免预注册
同一产品下设备烧录相同产品证书(ProductKey和ProductSecret)。
产品需开启动态注册功能。
设备通过动态注册获取ClientID与DeviceToken的组合。
说明一型一密预注册和免预注册的区别,请参见预注册和免预注册的区别。
Java Link SDK中参数说明,请参见LinkKitInitParams。
一机一密
一机一密的设备认证方式的示例代码如下:
String productKey = "${YourProductKey}";
String deviceName = "${YourDeviceName}";
String deviceSecret = "${YourDeviceSecret}";
LinkKitInitParams params = new LinkKitInitParams();
final String TAG = "HelloWorld";
/**
* step 1: 设置MQTT初始化参数
*/
IoTMqttClientConfig config = new IoTMqttClientConfig();
MqttConfigure.mqttHost = "{YourInstanceId}.mqtt.iothub.aliyuncs.com:8883";
/*
*是否接受离线消息
*对应MQTT的cleanSession字段
*/
config.receiveOfflineMsg = false;
params.mqttClientConfig = config;
/**
* step 2: 设置初始化设备认证信息
*/
DeviceInfo deviceInfo = new DeviceInfo();
deviceInfo.productKey = productKey;
deviceInfo.deviceName = deviceName;
deviceInfo.deviceSecret = deviceSecret;
params.deviceInfo = deviceInfo;
/**
* step 3: 设置设备的username, token和clientId
* 仅用于一型一密免预注册
* 默认关闭
*/
// MqttConfigure.deviceToken="${YourDeviceToken}";
// MqttConfigure.clientId="${YourClientId}";
LinkKit.getInstance().init(params, new ILinkKitConnectListener() {
public void onError(AError aError) {
ALog.e(TAG, "Init Error error= "+aError);
}
public void onInitDone(InitResult initResult) {
ALog.i(TAG, "onInitDone result=" + initResult);
}
});
发起初始化请求后,如果返回
onInitDone
表示初始化成功,返回onError
表示初始化失败。初始化失败后,您可以根据业务需要,设置是否再次进行初始化,Java Link SDK不会自动尝试连接物联网平台。
初始化成功后,如果设备异常断开,Java Link SDK会自动重连。
动态注册
一型一密又称动态注册,用于向物联网平台获取设备的密钥,具体分为免预注册和预注册两种方式。使用该功能前,需要确保:
已在物联网平台创建产品并开启动态注册开关。
Demo的
deviceinfo
文件中的deviceSecret的值为空,productSecret不为空。请确保已执行下面示例代码中的step1、step2、step3。
动态注册成功或失败之后,需要断开当前的动态注册长连接,请参考示例代码的step4。
当前Demo支持的是一型一密预注册方式。您可参考示例代码中step 1的说明调整成一型一密免预注册方式。
为了您的设备安全,使用一型一密认证方式获取到设备密钥后,请将设备密钥持久固化至设备。若设备需连接至物联网平台,请参考上述一机一密流程。
免预注册和预注册区别如下:
区别 | 预注册 | 免预注册 |
通信协议 | MQTT、HTTPS | MQTT |
地域支持 |
| 华东2(上海)、华北2(北京) |
返回的设备密钥 | DeviceSecret具体使用方式,请参考上述一机一密示例中的Step1。 | 设备的ClientID和DeviceToken,请将其持久固化至设备,以便连云等其他功能使用。具体使用方式,请参考上述一机一密示例中的Step3。 |
添加设备 | 需要在物联网平台预注册设备DeviceName。 | 不需要在物联网平台预注册设备DeviceName。 |
使用次数限制 |
| 物联网平台允许最多5个物理设备使用同一组ProductKey、ProductSecret、DeviceName进行激活,并为不同物理设备颁发不同的ClientID、DeviceToken。 |
示例代码如下:
String deviceName = "${YourDeviceName}";
String productKey = "${YourProductKey}";
String productSecret = "${YourProductSecret}";
//动态注册step1: 确定一型一密的类型(免预注册, 还是非免预注册)
//case 1: 如果registerType里面填写了regnwl, 表明设备的一型一密方式为免预注册(即无需创建设备)
//case 2: 如果这个字段为空, 或填写"register", 则表示为需要预注册的一型一密(需要实现创建设备)
String registerType = "register";
//动态注册step2: 设置动态注册的注册接入点域名
MqttConfigure.mqttHost = "ssl://${YourMqttHostUrl}:8883";
MqttInitParams initParams = new MqttInitParams(productKey, productSecret, deviceName, "",registerType);
//动态注册step3: 如果用户所用的实例为新版本的公共实例或者企业实例(控制台中有实例详情的页面), 需设置动态注册的实例id
initParams.instanceId = "${YourInstanceId}";
final Object lock = new Object();
LinkKit.getInstance().deviceDynamicRegister(initParams, new IOnCallListener() {
@Override
public void onSuccess(com.aliyun.alink.linksdk.channel.core.base.ARequest request, com.aliyun.alink.linksdk.channel.core.base.AResponse response) {
try {
String responseData = new String((byte[]) response.data);
JSONObject jsonObject = JSONObject.parseObject(responseData);
// 一型一密预注册返回
String deviceSecret = jsonObject.getString("deviceSecret");
// 一型一密免预注册返回
String clientId = jsonObject.getString("clientId");
String deviceToken = jsonObject.getString("deviceToken");
//TODO: 请用户保存用户密钥,不要在此做连云的操作,要等step 4执行完成后再做连云的操作(例如在其onSuccess分支中进行连云)
//让等待的api继续执行
synchronized (lock){
lock.notify();
}
} catch (Exception e) {
}
}
@Override
public void onFailed(ARequest aRequest, com.aliyun.alink.linksdk.channel.core.base.AError aError) {
System.out.println("mqtt dynamic registration failed");
//让等待的api继续执行
synchronized (lock){
lock.notify();
}
}
@Override
public boolean needUISafety() {
return false;
}
});
try {
//等待下行报文,一般1s内就有回复
synchronized (lock){
lock.wait(3000);
}
//动态注册step4: 关闭动态注册的实例。
//不要在LinkKit.getInstance().deviceDynamicRegister回调中执行下述函数,否则会报错
LinkKit.getInstance().stopDeviceDynamicRegister(2000, null, new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken iMqttToken) {
System.out.println("mqtt dynamic registration success");
//TODO: 在此处参考一机一密进行连云和初始化
}
@Override
public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
System.out.println("mqtt dynamic registration failed");
}
});
} catch (Exception e) {
}
设置接入域名
示例代码如下:
// 设置MQTT请求域名LinkKitInitParams初始化参数
IoTMqttClientConfig clientConfig = new IoTMqttClientConfig();
clientConfig.channelHost = "a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com:8883";
linkKitInitParams.mqttClientConfig = clientConfig;
参数说明:
参数 | 示例 | 说明 |
channelHost | a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com:8883 | 设备的
新旧版公共实例和企业版实例、以及接入域名的更多信息,请参见查看实例终端节点。 |
更多设置
您可以设置以下参数,实现设备接入相关的更多设置。
MQTT连接:
配置项
说明
相关代码
保活时间
设置设备的保活时间。通过该设置实现设备与物联网平台保持长连接。
MqttConfigure.setKeepAliveInterval(int interval);
QoS等级
设置QoS(Quality of Service)等级,即物联网平台与设备之间保证交付信息的协议。仅支持:
0
:最多一次。1
:最少一次。
- qos设置 MqttPublishRequest request = new MqttPublishRequest(); // 支持 0 和 1, 默认0 request.qos = 0; request.isRPC = false; request.topic = topic.replace("request", "response"); String resId = topic.substring(topic.indexOf("rrpc/request/")+13); request.msgId = resId; // TODO 用户根据实际情况填写,仅做参考 request.payloadObj = "{\"id\":\"" + resId + "\", \"code\":\"200\"" + ",\"data\":{} }";
离线消息
通过cleanSession,设置是否接收离线消息。
/** * 设置MQTT初始化参数 */ IoTMqttClientConfig config = new IoTMqttClientConfig(); config.productKey = deviceInfoData.productKey; config.deviceName = deviceInfoData.deviceName; config.deviceSecret = deviceInfoData.deviceSecret; config.channelHost = pk + ".iot-as-mqtt." + deviceInfoData.region + ".aliyuncs.com:1883"; /** * 是否接受离线消息 * 对应 receiveOfflineMsg = !cleanSession, 默认不接受离线消息 */ config.receiveOfflineMsg = false; params.mqttClientConfig = config;
日志与Log4j支持:
用户可以通过如下日志输出Debug日志:
ALog.setLevel(ALog.LEVEL_DEBUG); MqttLogger.isLoggable = true; // 输出底层MQTT库的全量日志, 默认关闭
Java Link SDK从1.2.3.1版本起,提供了一个全量的拦截器,支持用户重写拦截器的
log
函数,实现自定义的日志处理。例如将日志通过Log4j工具持久化到文件中。日志输出示例代码:
ALog.setLogDispatcher(new ILogDispatcher() { @Override public void log(int level, String prefix, String msg) { switch (level){ case LEVEL_DEBUG: System.out.println("debug:"+ prefix + msg); break; case LEVEL_INFO: System.out.println("info:" + prefix + msg); break; case LEVEL_ERROR: System.out.println("error:" + prefix + msg); break; case LEVEL_WARNING: System.out.println("warnings:" + prefix + msg); break; default: System.out.println("other:" + prefix + msg); } } });
连接状态与下行消息监听:
如果需要监听设备的上下线信息,以及物联网平台下发的消息,可以设置以下监听器。
IConnectNotifyListener notifyListener = new IConnectNotifyListener() { @Override public void onNotify(String connectId, String topic, AMessage aMessage) { // 物联网平台下行数据回调,包括connectId、连接类型、下行Topic和aMessage下行数据 //String pushData = new String((byte[]) aMessage.data); // pushData示例 {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"} // 上一行代码表示method服务类型以及params下推数据内容 } @Override public boolean shouldHandle(String connectId, String topic) { // 选择是否不处理某个Topic的下行数据 // 如果不处理某个Topic,则onNotify不会收到对应Topic的下行数据 return true; //TODO 根据实际情况,编写要处理的监听逻辑。 } @Override public void onConnectStateChange(String connectId, ConnectState connectState) { // 对应连接类型的连接状态变化回调,具体连接状态参考SDK ConnectState //当SDK因网络波动断开连接时,会自动尝试重连,重试的间隔是1s、2s、4s、8s...128s...128s, 到了最大间隔128s后,会一直以128s为间隔重连直到连云成功。 } } // 注册下行监听,包括长连接的状态和下行的数据 LinkKit.getInstance().registerOnNotifyListener(notifyListener);
反初始化:
如果需要注销初始化,请参考如下示例代码。
// 取消注册 notifyListener,notifyListener对象需和注册的时候是同一个对象 LinkKit.getInstance().unRegisterOnNotifyListener(notifyListener); LinkKit.getInstance().deinit();