.DS_StoreBinary files differ
HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
@@ -21,7 +21,7 @@ //初始化SDK HDLSdk.getInstance().init(this); //控制SDK日志打印 HDLSdk.getInstance().setLogEnabled(true); HDLSdk.getInstance().setLogEnabled(false); } HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
@@ -10,7 +10,6 @@ import android.Manifest; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.TextView; @@ -18,17 +17,14 @@ import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.listener.OnItemClickListener; import com.google.gson.reflect.TypeToken; import com.hdl.sdk.common.event.EventListener; import com.hdl.sdk.common.exception.HDLLinkException; import com.hdl.sdk.common.utils.IdUtils; import com.hdl.sdk.common.utils.IpUtils; import com.hdl.sdk.common.utils.gson.GsonConvert; import com.hdl.sdk.connect.HDLLink; import com.hdl.sdk.connect.bean.LinkResponse; import com.hdl.sdk.connect.bean.request.AuthenticateRequest; import com.hdl.sdk.connect.bean.request.PropertyReadRequest; import com.hdl.sdk.connect.bean.response.BaseLocalResponse; import com.hdl.sdk.connect.bean.response.GatewaySearchBean; import com.hdl.sdk.connect.callback.HDLLinkCallBack; import com.hdl.sdk.connect.callback.HDLLinkResponseCallBack; @@ -47,18 +43,15 @@ import java.util.List; import java.util.Map; import static com.hdl.sdk.common.config.TopicConstant.GATEWAY_SEARCH_REPLY; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private DemoAdapter demoAdapter; private RecyclerView rv; private TextView tv; private TextView responseTv; boolean isOn; private EventListener allTopicsListener; private String testLightSid = "0001010D48C71B02020100010101"; private String testLightSid = "000101B847C71B02020100010101"; @Override protected void onDestroy() { @@ -76,7 +69,6 @@ rv.setLayoutManager(new LinearLayoutManager(this)); checkIfCertified(); registerAllTopicsListener(); ActivityResultLauncher<String[]> launcher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<Map<String, Boolean>>() { @@ -103,7 +95,9 @@ // final SocketOptions options = new SocketOptions(); // MessagePipeLine pipeLine = new MessagePipeLine(); // MessagePipeLine pipeLine = new MessagePipeLine(); // // pipeLine.add(new LinkMessageDecoder()); // pipeLine.add(new LinkMessageEncoder()); // options.setHandleMessage(pipeLine); // options.setEnabledHeartbeat(false); @@ -169,52 +163,11 @@ @Override public void onMessage(Object msg) { LinkResponse response = (LinkResponse)msg; if(response != null){ Log.i(TAG, "AllTopicsListener" + "\nTopic: " + response.getTopic() +"\n Data: " + response.getData()); handleLinkResponse(response); } //response.getData() 使用这个方法获取数据转json就可以了 // Log.i("TAG", "AllTopicsListener onMessage: "+msg.toString()); } }; HDLLink.getInstance().registerAllTopicsListener(allTopicsListener); } /** * 处理收到的主题 * @param response */ private void handleLinkResponse(LinkResponse response){ //网关搜索回复 if(response.getTopic().contains("/user/all/custom/gateway/search_reply")){ String data = response.getData(); if (!TextUtils.isEmpty(data)) { Log.i("handleLinkResponse", "data:"+data); final BaseLocalResponse<GatewaySearchBean> bean = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() { }.getType()); GatewaySearchBean searchBean = bean.getObjects(); Log.i("handleLinkResponse", "GatewaySearchBean: "+searchBean.getGatewayId()); } }else{ //其它主题 } } private GatewaySearchBean getGatewaySearchBean(Object msg) { GatewaySearchBean searchBean = null; if (msg instanceof LinkResponse) { LinkResponse linkResponse = (LinkResponse) msg; String data = linkResponse.getData(); if (!TextUtils.isEmpty(data)) { final BaseLocalResponse<GatewaySearchBean> response = GsonConvert.getGson().fromJson(data, new TypeToken<BaseLocalResponse<GatewaySearchBean>>() { }.getType()); searchBean = response.getObjects(); } } return searchBean; } /** @@ -256,7 +209,7 @@ infoBean.setDeviceName("红外宝");//设备名字 infoBean.setDeviceModel("HDL");// infoBean.setAccessMode("WIFI"); infoBean.setIPGateway("192.168.12.1"); infoBean.setIPGateway("192.168.10.1"); infoBean.setIPAddress(IpUtils.getIP(this)); infoBean.setOID("010105000000FE08"); HDLSDK/build.gradle
@@ -6,7 +6,7 @@ mavenCentral() } dependencies { classpath "com.android.tools.build:gradle:4.2.2" classpath "com.android.tools.build:gradle:4.1.2" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files HDLSDK/hdl-common/src/main/java/com/hdl/sdk/common/exception/HDLLinkCode.java
@@ -13,7 +13,6 @@ HDL_SEND_ERROR(-2003,"发送失败"), HDL_TIMEOUT_ERROR(-2004,"超时"), HDL_UNAUTHORIZED_ERROR(-2005,"未认证,请先认证"), HDL_AUTH_ERROR_GATEWAY_NOT_REGISTERED(-2006,"认证失败,网关未注册到云端"), HDL_GET_DEVICE_LIST_ERROR(-2100,"获取设备列表失败"), HDL_GET_FUNCTION_LIST_ERROR(-2101,"获取功能列表失败"), HDL_GET_FUNCTION_PROPERTIES_ERROR(-2102,"获取功能属性失败"), HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java
@@ -28,7 +28,6 @@ * instance */ private volatile static HDLLinkConfig instance; /** * getInstance * @@ -72,7 +71,6 @@ /** * 保存配置 * * @param localSecret * @param gatewayId * @param ipAddress @@ -88,7 +86,6 @@ /** * 检测是否已经认证过 * * @return */ public boolean checkIfCertified() { @@ -130,18 +127,10 @@ public void setCurrentGateway(GatewaySearchBean currentGateway) { this.currentGateway = currentGateway; if (this.currentGateway != null && !TextUtils.isEmpty(this.currentGateway.getIp_address())) { if (!this.ipAddress.equals(this.currentGateway.getIp_address())) { //如果IP地址有变化则更新 this.ipAddress = this.currentGateway.getIp_address(); SPUtils.put(AUTHENTICATE_IPADDRESS_KEY, ipAddress); } } } /** * 判断当前主题数据是否需要加密 * * @param topicStr 当前主题 * @return */ @@ -156,7 +145,6 @@ /** * 拼接网关ID获取完整的主题 * * @param topicStr * @return */ HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
@@ -1,6 +1,8 @@ package com.hdl.sdk.connect.protocol; import android.util.Log; import com.hdl.sdk.common.utils.LogUtils; import com.hdl.sdk.connect.config.HDLLinkConfig; import com.hdl.sdk.common.event.EventDispatcher; @@ -22,44 +24,133 @@ private final List<Byte> bytes; private final byte[] head = "Topic:".getBytes(); private final byte[] body = "\r\n\r\n".getBytes(); // private final byte[] body = "\r\n\r\n".getBytes(); public LinkMessageDecoder() { this.bytes = new ArrayList<>(); } @Override protected LinkResponse decoder(Object msg) throws Exception { LinkResponse response = new LinkResponse(); if (msg instanceof byte[]) { //解析流 byte[] data = (byte[]) msg; bytes.addAll(ByteUtils.toByteList(data)); byte[] byteArray = ByteUtils.toByteArray(bytes); int headIndex = ByteUtils.getByteIndexOf(byteArray, head); if (headIndex > 0) { //移动到head 开始位置 bytes.subList(0, headIndex).clear(); byteArray = ByteUtils.toByteArray(bytes); /// <summary> /// 获取内容长度 /// </summary> /// <param name="topMsgs"></param> /// <returns></returns> int getLenght(String[] topMsgs) { for (int i = 0; i < topMsgs.length; i++) { String topMsg = topMsgs[i].trim(); if (topMsg.startsWith("Length:")) { return Integer.parseInt(topMsg.replace("Length:", "")); } } //找不到长度 return -1; } int bodyIndex = ByteUtils.getByteIndexOf(byteArray, body); if (bodyIndex < 0) { //头部未获取完成 /// <summary> /// 获取主题 /// </summary> /// <param name="topMsgs"></param> /// <returns></returns> private String getTopic(String[] topMsgs) { for (int i = 0; i < topMsgs.length; i++) { String topMsg = topMsgs[i].trim(); if (topMsg.startsWith("Topic:")) { return topMsg.replace("Topic:", ""); } } //找不到主题 return null; } int bodyStartIndex = bodyIndex + body.length; //解析头部 ProtocolParse parse = new ProtocolParse(byteArray); response.setTopic(parse.getTopic()); /** * 获取数据的开始位置 * * @param arrayList 接收到的所有数据 * @return 数据位的开始索引 */ int getDataIndex(List<Byte> arrayList) { byte r = (byte) '\r'; byte n = (byte) '\n'; for (int i = 0; i < arrayList.size(); i++) { //找出数据内容前面的两个换行 if (3 <= i && arrayList.get(i - 3) == r && arrayList.get(i - 2) == n && arrayList.get(i - 1) == r && arrayList.get(i) == n) { //剩余的数据 return i + 1; } } return -1; } int bodyLength = parse.getLength(); if (bodyLength > 0) { if (byteArray.length >= bodyLength + bodyStartIndex) { byte[] body = ByteUtils.getRangeBytes(bytes, bodyStartIndex, bodyStartIndex + bodyLength); void initReceiveData(List<Byte> list) { int index = 0; boolean isMatch = false; for (; index < list.size() - head.length; index++) { isMatch = true; for (int j = 0, k = 0; j < head.length; j++, k++) { if (head[j] != list.get(index + k)) { isMatch = false; break; } } if (isMatch) { break; } } if (0 < index && isMatch) { List<Byte> tempList = new ArrayList<Byte>(); for (int i = index; i < list.size(); i++) { tempList.add(list.get(index)); } list.clear(); for(int i=0;i<tempList.size();i++){ list.add(tempList.get(i)); } } } @Override protected LinkResponse decoder(Object msg) throws Exception { if (msg instanceof byte[]) { bytes.addAll(ByteUtils.toByteList((byte[]) msg)); //如果多条命令打包在一条数据中,都需要处理完 while (true) { initReceiveData(bytes); byte[] recevieBytes = ByteUtils.toByteArray(bytes); String data = new String(recevieBytes); String[] topMsgs = data.split("\r\n"); String topic = getTopic(topMsgs); if (topic == null) { break; } int lenght = getLenght(topMsgs); if (lenght <= 0) { //头部数据还没有接收完成 break; } //是否已经获取完整所有的数据 byte[] body = new byte[lenght]; int index = getDataIndex(bytes); if (bytes.size() < index + lenght) { //当前数据还没有接收完成 break; } //复制出body数据 System.arraycopy(recevieBytes, index, body, 0, body.length); //保留剩余的数据,以次用 bytes.clear(); for (int i = index + lenght; i < recevieBytes.length; i++) { bytes.add(recevieBytes[i]); } LinkResponse response = new LinkResponse(); response.setTopic(topic); if (HDLLinkConfig.getInstance().ifNeedEncrypt(response.getTopic())) { //需要解密 byte[] bodyBytes = AesUtil.aesDecrypt(body, HDLLinkConfig.getInstance().getLocalSecret()); @@ -70,29 +161,77 @@ } else { //解密失败,返回原数据 response.setData(new String(body, "utf-8")); LogUtils.e( "解密失败"); } } else { response.setData(new String(body, "utf-8")); } if (byteArray.length >= bodyLength + bodyStartIndex) { //保存余留 byte[] remaining = ByteUtils.getRangeBytes(bytes, bodyStartIndex + bodyLength, byteArray.length); bytes.clear(); for (byte b : remaining) { bytes.add(b); } } Log.i("TAG", "LinkMessageDecoder->decoder:" + response.getTopic() + "\r\n" + response.getData()); //解析完成,topic发送一次 EventDispatcher.getInstance().post(response.getTopic(), response); return response; } } else if (bodyLength == 0) { //body为空 return response; } return null; // //解析流 // byte[] data = (byte[]) msg; // bytes.addAll(ByteUtils.toByteList(data)); // // byte[] byteArray = ByteUtils.toByteArray(bytes); // int headIndex = ByteUtils.getByteIndexOf(byteArray, head); // if (headIndex > 0) { // //移动到head 开始位置 // bytes.subList(0, headIndex).clear(); // byteArray = ByteUtils.toByteArray(bytes); // } // // int bodyIndex = ByteUtils.getByteIndexOf(byteArray, body); // if (bodyIndex < 0) { // //头部未获取完成 // return null; // } // int bodyStartIndex = bodyIndex + body.length; // // //解析头部 // ProtocolParse parse = new ProtocolParse(byteArray); // response.setTopic(parse.getTopic()); // // int bodyLength = parse.getLength(); // if (bodyLength > 0) { // if (byteArray.length >= bodyLength + bodyStartIndex) { // byte[] body = ByteUtils.getRangeBytes(bytes, bodyStartIndex, bodyStartIndex + bodyLength); // // if (HDLLinkConfig.getInstance().ifNeedEncrypt(response.getTopic())) { // //需要解密 // byte[] bodyBytes = AesUtil.aesDecrypt(body, HDLLinkConfig.getInstance().getLocalSecret()); //// byte[] bodyBytes = AESUtils.decryptAES(body,AuthenticateConfig.getInstance().getLocalSecret()); // if (bodyBytes != null) { // response.setData(new String(bodyBytes, "utf-8")); //// LogUtils.i("TAG", "解密 主题:"+response.getTopic()+ " body: "+response.getData()); // } else { // //解密失败,返回原数据 // response.setData(new String(body, "utf-8")); // } // // } else { // response.setData(new String(body, "utf-8")); // } // // if (byteArray.length >= bodyLength + bodyStartIndex) { // //保存余留 // byte[] remaining = ByteUtils.getRangeBytes(bytes, bodyStartIndex + bodyLength, byteArray.length); // bytes.clear(); // for (byte b : remaining) { // bytes.add(b); // } // } // //解析完成,topic发送一次 // EventDispatcher.getInstance().post(response.getTopic(), response); // return response; // } // } else if (bodyLength == 0) { // //body为空 // return response; // } } return null; HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java
@@ -164,17 +164,12 @@ String localSecret = bean.getAuth().getLocalSecret(); String gatewayId = bean.getObjects().getGatewayID(); String ipAddress = bean.getObjects().getIPAddress(); //判断网关是否已经注册到云端 if(TextUtils.isEmpty(localSecret) ||TextUtils.isEmpty(gatewayId)){ //认证失败,网关未注册到云端 callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_AUTH_ERROR_GATEWAY_NOT_REGISTERED)); }else{ HDLLinkConfig.getInstance().saveConfig(localSecret,gatewayId,ipAddress); callBack.onSuccess("认证成功"); } }else{ callBack.onError(HDLLinkException.getErrorWithCode(HDLLinkCode.HDL_DATA_ERROR)); } } @Override HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java
@@ -702,6 +702,7 @@ } threadPool.shutdownNow(); } EventDispatcher.getInstance().remove(eventTag, this); } }; HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HdlSocketHelper.java
@@ -129,5 +129,6 @@ if (listener != null) { listener.onFailure(); } EventDispatcher.getInstance().remove(eventListener); } } HDLSDK/hdl-socket/src/main/java/com/hdl/sdk/socket/client/TcpClient.java
@@ -2,6 +2,7 @@ import com.hdl.sdk.common.utils.ByteUtils; import com.hdl.sdk.common.utils.ThreadToolUtils; import com.hdl.sdk.socket.SocketBoot; import com.hdl.sdk.socket.SocketOptions; @@ -14,7 +15,7 @@ import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @@ -22,6 +23,11 @@ * Created by Tong on 2021/9/15. */ public final class TcpClient implements IClient { /* *接收数据的缓冲区 */ private final List<Byte> byteList; private final byte[] head = "Topic:".getBytes(); private SocketOptions socketOptions; @@ -33,6 +39,7 @@ private byte[] readBuffer; private TcpClient(String ip, int port, SocketOptions socketOptions) { this.byteList = new ArrayList<>(); this.socketOptions = socketOptions; this.ip = ip; this.port = port; @@ -84,18 +91,104 @@ return socketOptions; } /// <summary> /// 获取内容长度 /// </summary> /// <param name="topMsgs"></param> /// <returns></returns> int getLenght(String[] topMsgs) { for (int i = 0; i < topMsgs.length; i++) { String topMsg = topMsgs[i].trim(); if (topMsg.startsWith("Length:")) { return Integer.parseInt(topMsg.replace("Length:", "")); } } //找不到长度 return -1; } /// <summary> /// 获取主题 /// </summary> /// <param name="topMsgs"></param> /// <returns></returns> private String getTopic(String[] topMsgs) { for (int i = 0; i < topMsgs.length; i++) { String topMsg = topMsgs[i].trim(); if (topMsg.startsWith("Topic:")) { return topMsg.replace("Topic:", ""); } } //找不到主题 return null; } /** * 获取数据的开始位置 * @param arrayList 接收到的所有数据 * @return 数据位的开始索引 */ int getDataIndex(List<Byte> arrayList) { byte r = (byte)'\r'; byte n = (byte)'\n'; for (int i = 0; i < arrayList.size(); i++) { //找出数据内容前面的两个换行 if (3 <= i && arrayList.get(i - 3) == r && arrayList.get(i - 2) == n && arrayList.get(i - 1) == r && arrayList.get(i) == n) { //剩余的数据 return i + 1; } } return -1; } void initReceiveData(List<Byte> list) { int index = 0; boolean isMatch=false; for (; index < list.size() - head.length; index++) { isMatch=true; for (int j = 0, k = 0; j < head.length; j++, k++) { if (head[j] != list.get(index + k)) { isMatch=false; break; } } if(isMatch) { break; } } if (0 < index&&isMatch) { List<Byte> tempList = new ArrayList<Byte>(); for(int i=index;i<list.size();i++) { tempList.add(list.get(index)); } list=tempList; } } @Override public void onHandleResponse() throws Exception { final InputStream stream = getInputStream(); if (stream != null && getOptions() != null) { readBuffer = new byte[1024]; int len; int len=0; while ((len = getInputStream().read(readBuffer)) != -1) { IHandleMessage handleMessage = getOptions().getHandleMessage(); if (handleMessage != null && len > 0) { handleMessage.read(Arrays.copyOfRange(readBuffer, 0, len)); // handleMessage.read(readBuffer); if (handleMessage != null) { byte []bytes = new byte[len]; System.arraycopy(readBuffer,0,bytes,0,len); //完整的数据才回调 handleMessage.read(bytes); } } } README.md
@@ -2,3 +2,8 @@ HDLSDK_A_Android 测试认证信息 "supplier": "WISE", "mac": "AA000000000000AB", "spk": "music.standard", "deviceSecret": "ca5edb13106847a8"