本文介紹如何進行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連接:
配置項
說明
相關代碼
保活時間
設置設備的?;顣r間。通過該設置實現設備與物聯網平臺保持長連接。
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();