本文介绍如何进行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();