全部產品
Search
文件中心

:認證與串連

更新時間:Jun 30, 2024

本文介紹如何進行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

地區支援

  • 基於MQTT的動態註冊,物聯網平台支援的所有地區。

  • 基於HTTPS的動態註冊,僅限於上海地區,不推薦使用,不在本範例程式碼介紹範圍之內。

華東2(上海)、華北2(北京)

返回的裝置密鑰

DeviceSecret具體使用方式,請參考上述一機一密樣本中的Step1。

裝置的ClientID和DeviceToken,請將其持久固化至裝置,以便連雲等其他功能使用。具體使用方式,請參考上述一機一密樣本中的Step3。

添加裝置

需要在物聯網平台預註冊裝置DeviceName。

不需要在物聯網平台預註冊裝置DeviceName。

使用次數限制

  • 同一組裝置認證只能用於啟用一個物理裝置。若DeviceName名下已啟用物理裝置A,但同一產品下物理裝置B需要使用該DeviceName,則您可以在物聯網平台上刪除裝置A,使裝置A的DeviceSecret作廢,再使用原DeviceName重新添加裝置,啟用物理裝置B。

  • 若裝置因丟失DeviceSecret等原因需要重新啟用,需您調用ResetThing介面,重設裝置狀態為未啟用,然後將裝置重新連網啟用。此時,物聯網平台下發的DeviceSecret不變。

物聯網平台允許最多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

裝置的${接入網域名稱}:${連接埠號碼}

  • 企業版執行個體和新版公用執行個體:在執行個體詳情頁面的開發配置面板,查看接入網域名稱。

  • 舊版公用執行個體:接入網域名稱格式為${YourProductKey}.iot-as-mqtt.${YourRegionId}.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函數,實現自訂的Tlog。例如將日誌通過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();