Authentication and connection

Updated at:

This topic explains how to initialize the Java Link SDK to connect a device to IoT Platform.

Prerequisites

  • You have created a product and a device. For more information, see Create a product and a device.

  • You have obtained the device's authentication credentials and access domain name.

Background information

  • The Java Link SDK supports only device secret-based authentication.

    Authentication method

    Registration method

    Description

    Unique-certificate-per-device

    Not applicable

    Each device is flashed with its own device certificate (ProductKey, DeviceName, and DeviceSecret).

    Unique-certificate-per-product

    Pre-registration

    • Devices under the same product are flashed with the same product certificate (ProductKey and ProductSecret).

    • The Dynamic registration feature must be enabled for the product.

    • The device obtains a DeviceSecret through dynamic registration.

    No pre-registration

    • Devices under the same product are flashed with the same product certificate (ProductKey and ProductSecret).

    • The Dynamic registration feature must be enabled for the product.

    • The device obtains a ClientID and DeviceToken pair through dynamic registration.

    Note

    For more information about the differences between pre-registration and no pre-registration, see Differences between pre-registration and no pre-registration.

  • For more information about the parameters in the Java Link SDK, see LinkKitInitParams.

Unique-certificate-per-device authentication

The following sample code shows how to use unique-certificate-per-device authentication:

String productKey = "${YourProductKey}";
String deviceName = "${YourDeviceName}";
String deviceSecret = "${YourDeviceSecret}";

LinkKitInitParams params = new LinkKitInitParams();
final String TAG = "HelloWorld";

/**
 * step 1: Set the MQTT initialization parameters.
 */
IoTMqttClientConfig config = new IoTMqttClientConfig();

MqttConfigure.mqttHost = "{YourInstanceId}.mqtt.iothub.aliyuncs.com:8883";

/*
 * Specifies whether to receive offline messages.
 * Corresponds to the cleanSession field in MQTT.
 */
config.receiveOfflineMsg = false;
params.mqttClientConfig = config;

/**
 * step 2: Set the device authentication credentials for initialization.
 */
DeviceInfo deviceInfo = new DeviceInfo();
deviceInfo.productKey = productKey;
deviceInfo.deviceName = deviceName;
deviceInfo.deviceSecret = deviceSecret;
params.deviceInfo = deviceInfo;

/**
 * step 3: Set the username, token, and clientId for the device.
 * Used only for unique-certificate-per-product authentication without pre-registration.
 * Disabled by default.
 */
 // 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);
    }
});
Note
  • After you send an initialization request, onInitDone is returned if the initialization is successful. onError is returned if the initialization failed.

  • If the initialization fails, you can configure the SDK to re-initialize. The Java Link SDK does not automatically attempt to reconnect to IoT Platform after a failed initialization.

  • After a successful initialization, the Java Link SDK automatically reconnects if the device disconnects unexpectedly.

Dynamic registration

Unique-certificate-per-product authentication, also known as dynamic registration, is used to obtain a device secret from IoT Platform. It includes two methods: no pre-registration and pre-registration. Before you use this feature, make sure that:

  • You have created a product in the IoT Platform console and enabled dynamic registration.

  • In the deviceinfo file of the demo, the value of deviceSecret is empty and the value of productSecret is not empty.

  • Make sure that you have executed steps 1, 2, and 3 in the sample code below.

  • After dynamic registration succeeds or fails, disconnect the current persistent connection for dynamic registration. For more information, see step 4 in the sample code.

  • The current demo supports unique-certificate-per-product authentication with pre-registration. To switch to the method without pre-registration, refer to the description in step 1 of the sample code.

  • For security, after you obtain a device secret using unique-certificate-per-product authentication, permanently save the secret to the device. If the device needs to connect to IoT Platform, follow the unique-certificate-per-device authentication process described earlier.

The differences between pre-registering and not pre-registering are described below.

Difference

Pre-registration

No pre-registration

Communication protocol

MQTT, HTTPS

MQTT

Region support

  • For MQTT-based dynamic registration, all regions where IoT Platform is available are supported.

  • HTTPS-based dynamic registration is supported only in the China (Shanghai) region. This method is not recommended and is not covered in this sample code.

China (Shanghai), China (Beijing)

Returned device secret

DeviceSecret. For more information about how to use it, see Step 1 in the unique-certificate-per-device authentication example.

The device's ClientID and DeviceToken. Save them permanently to the device for features such as cloud connection. For more information about how to use them, see Step 3 in the unique-certificate-per-device authentication example.

Add device

You must pre-register the DeviceName in IoT Platform.

You do not need to pre-register the DeviceName in IoT Platform.

Usage limits

  • A set of device credentials can be used to activate only one physical device. If a physical device A is activated with a DeviceName, but you need to use the same DeviceName for a physical device B under the same product, you can delete device A in the IoT Platform console. This invalidates the DeviceSecret of device A. Then, you can add a new device with the original DeviceName to activate physical device B.

  • If a device needs to be reactivated because its DeviceSecret is lost, call the ResetThing API operation to reset the device status to inactive. Then, connect the device to the internet to reactivate it. The DeviceSecret issued by IoT Platform remains unchanged.

IoT Platform allows up to five physical devices to be activated with the same ProductKey, ProductSecret, and DeviceName. IoT Platform issues a different ClientID and DeviceToken for each physical device.

The following is sample code:

        String deviceName = "${YourDeviceName}";
        String productKey = "${YourProductKey}";
        String productSecret = "${YourProductSecret}";

        // Dynamic registration step 1: Determine the type of unique-certificate-per-product authentication (no pre-registration or pre-registration).
        // case 1: If registerType is set to regnwl, it indicates unique-certificate-per-product authentication without pre-registration (no device creation required).
        // case 2: If this field is empty or set to "register", it indicates unique-certificate-per-product authentication with pre-registration (device creation required).
        String registerType = "register";

        // Dynamic registration step 2: Set the domain name of the registration endpoint for dynamic registration.
        MqttConfigure.mqttHost = "ssl://${YourMqttHostUrl}:8883";

        MqttInitParams initParams = new MqttInitParams(productKey, productSecret, deviceName, "",registerType);

        // Dynamic registration step 3: If you use a new public instance or an Enterprise instance (which has a product page in the console), you must set the instance ID for dynamic registration.
        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);
                    // Returned for unique-certificate-per-product authentication with pre-registration
                    String deviceSecret = jsonObject.getString("deviceSecret");

                    // Returned for unique-certificate-per-product authentication without pre-registration
                    String clientId = jsonObject.getString("clientId");
                    String deviceToken = jsonObject.getString("deviceToken");

                    //TODO: Save the device secret. Do not connect to the cloud here. Connect to the cloud only after step 4 is complete (for example, in the onSuccess branch).
                    
                    // Allow the waiting API to continue.
                    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");
                // Allow the waiting API to continue.
                synchronized (lock){
                    lock.notify();
                }
            }

            @Override
            public boolean needUISafety() {
                return false;
            }
        });

        try {
            // Wait for the mobile terminated message. A response is usually received within 1s.
            synchronized (lock){
                lock.wait(3000);
            }

            // Dynamic registration step 4: Shut down the instance for dynamic registration.
            // Do not call the following function in the LinkKit.getInstance().deviceDynamicRegister callback. Otherwise, an error occurs.
            LinkKit.getInstance().stopDeviceDynamicRegister(2000, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken iMqttToken) {
                    System.out.println("mqtt dynamic registration success");
                    //TODO: Refer to the unique-certificate-per-device authentication method to connect to the cloud and initialize.
                }

                @Override
                public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
                    System.out.println("mqtt dynamic registration failed");
                }
            });

        } catch (Exception e) {
        }

Set an access domain name

The following is sample code:

// Set the MQTT request domain name for LinkKitInitParams initialization.
IoTMqttClientConfig clientConfig = new IoTMqttClientConfig();
clientConfig.channelHost = "a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com:8883";
linkKitInitParams.mqttClientConfig = clientConfig;           

Parameter descriptions:

Parameter

Example

Description

channelHost

a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com:8883

The ${Access domain name}:${Port number} of the device.

  • Enterprise instances and new public instances: View the access domain name on the Developer Configuration panel of the product page.

  • Old public instances: The access domain name is in the format ${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com:8883.

For more information about new and old public instances, Enterprise instances, and access domain names, see View instance endpoints.

More settings

You can configure the following parameters to customize the device connection.

  • MQTT connection:

    Configuration item

    Description

    Related code

    Keepalive interval

    Set the keepalive interval for the device. This setting keeps a persistent connection between the device and IoT Platform.

    MqttConfigure.setKeepAliveInterval(int interval);

    QoS level

    Set the Quality of Service (QoS) level. This is the protocol that ensures message delivery between the device and IoT Platform. Only the following values are supported:

    • 0: at most once.

    • 1: at least once.

    // QoS settings
    MqttPublishRequest request = new MqttPublishRequest();
    // 0 and 1 are supported. The default value is 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: Specify the value as needed. This is for reference only.
    request.payloadObj = "{\"id\":\"" + resId + "\", \"code\":\"200\"" + ",\"data\":{} }";

    Offline messages

    Use cleanSession to specify whether to receive offline messages.

    /**
     * Set the MQTT initialization parameters.
     */
    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";
    /**
     * Specifies whether to receive offline messages.
     * Corresponds to receiveOfflineMsg = !cleanSession. By default, offline messages are not received.
     */
    config.receiveOfflineMsg = false;
    params.mqttClientConfig = config;
  • Logs and Log4j support:

    You can output debug logs using the following code:

    ALog.setLevel(ALog.LEVEL_DEBUG);
    MqttLogger.isLoggable = true;  // Outputs the full logs of the underlying MQTT library. This feature is disabled by default.

    Starting from version 1.2.3.1, the Java Link SDK provides a full interceptor that lets you rewrite the log function of the interceptor to implement custom log processing. For example, you can use the Log4j tool to save logs to a file.

    The following sample code shows how to output logs:

            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);
                    }
                }
            });
  • Connection status and mobile terminated message listener:

    To listen for device online and offline events and messages from IoT Platform, you can set the following listener.

    IConnectNotifyListener notifyListener = new IConnectNotifyListener() {
        @Override
        public void onNotify(String connectId, String topic, AMessage aMessage) {
            // Callback for mobile terminated data from IoT Platform. The data includes the connectId, connection type, mobile terminated topic, and aMessage data.
            //String pushData = new String((byte[]) aMessage.data);
            // Sample pushData  {"method":"thing.service.test_service","id":"123374967","params":{"vv":60},"version":"1.0.0"}
            // The preceding line of code indicates the method service type and the content of the pushed params data.    
    }
        @Override
        public boolean shouldHandle(String connectId, String topic) {
            // Select whether to process mobile terminated data for a specific topic.
            // If you do not process data for a topic, onNotify does not receive mobile terminated data for that topic.
            return true; //TODO: Write the listener logic as needed.
        }
        @Override
        public void onConnectStateChange(String connectId, ConnectState connectState) {
            // Callback for connection status changes of the corresponding connection type. For specific connection states, see ConnectState in the SDK.
            // When the SDK disconnects due to network fluctuations, it automatically retries the connection. The retry intervals are 1s, 2s, 4s, 8s, and so on, up to a maximum of 128s. After reaching the maximum interval, the SDK continues to retry every 128s until the cloud connection is successful.
        }
    }
    // Register a listener for mobile terminated messages, including the status of the persistent connection and the mobile terminated data.
    LinkKit.getInstance().registerOnNotifyListener(notifyListener);
                
  • Deinitialization:

    To unregister the initialization, see the following sample code.

    // Unregister notifyListener. The notifyListener object must be the same as the one used for registration.
    LinkKit.getInstance().unRegisterOnNotifyListener(notifyListener);
    LinkKit.getInstance().deinit();