ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【一步到位】Android Studio 实现安卓连接阿里云物联网云平台 [打印本页]

作者: 王海鱼    时间: 2024-10-9 22:39
标题: 【一步到位】Android Studio 实现安卓连接阿里云物联网云平台
软件下载

下载 Android Studio 和应用工具 - Android 开发者  | Android Developers (google.cn),最新版本目前是Android Studio Iguana | 2024.1.2,你可以到官网上去找之前的版本,手上有工作项目的不要去轻易尝试,说不定你就编译失败了,失败了也不要担心,办理就可以了。


本次利用Android Studio 4.0这里提供了一下版本的下载地址,可直接点击下:https://redirector.gvt1.com/edgedl/android/studio/install/4.0.0.16/android-studio-ide-193.6514223-windows.exe

软件安装

在非系统盘(C盘之外)的盘符下面新建一个文件夹定名为Android,作为软件安装目次(注意:目次不要出现中文,否则会堕落),并在文件夹下新建空文件夹定名为SDK,用于下载SDK。


我们双击下载好的Android studio

安装路径选择我们刚才新建的文件下,安装完成后,会进入Android Studio的启动页面,我们点击cancel(取消)。

接下来我们选择next,进入SDK下载界面,修改安装路径选择上面新建文件夹下的SDK路径,然后我们选择SDK安装位置并点击next。

等候Finish, 到这里Android studio安装就完成了!

创建项目

安装完成后桌面生成新的图标,双击图标打开。


第一次进入,并没有工程,所以我们选择新建项目“Start a new Android Studio project”。


选择空缺活动“Empty Activity”并点击“next”。


创建项目,SDA建议选择API21,自界说项目名称、项目存放路径(不能利用带中文的),其他默认,语言选择Java。


项目配置

按照如下路径,右键新建Java类,定名为AliyunIoTSignUtil,添加AliyunIoTSignUtil工具类。


复制代码到新建的类中,并保存。

  1. //第一行保留 自己的pack.com.example.
  2. import java.util.Arrays;
  3. import java.util.Map;
  4. import javax.crypto.Mac;
  5. import javax.crypto.SecretKey;
  6. import javax.crypto.spec.SecretKeySpec;
  7. public class AliyunIoTSignUtil {
  8.     public static String sign(Map<String, String> params, String deviceSecret, String signMethod) {
  9.         //将参数Key按字典顺序排序
  10.         String[] sortedKeys = params.keySet().toArray(new String[]{});
  11.         Arrays.sort(sortedKeys);
  12.         //生成规范化请求字符串
  13.         StringBuilder canonicalizedQueryString = new StringBuilder();
  14.         for (String key : sortedKeys) {
  15.             if ("sign".equalsIgnoreCase(key)) {
  16.                 continue;
  17.             }
  18.             canonicalizedQueryString.append(key).append(params.get(key));
  19.         }
  20.         try {
  21.             String key = deviceSecret;
  22.             return encryptHMAC(signMethod, canonicalizedQueryString.toString(), key);
  23.         } catch (Exception e) {
  24.             throw new RuntimeException(e);
  25.         }
  26.     }
  27.     /**
  28.      * HMACSHA1加密
  29.      */
  30.     public static String encryptHMAC(String signMethod, String content, String key) throws Exception {
  31.         SecretKey secretKey = new SecretKeySpec(key.getBytes("utf-8"), signMethod);
  32.         Mac mac = Mac.getInstance(secretKey.getAlgorithm());
  33.         mac.init(secretKey);
  34.         byte[] data = mac.doFinal(content.getBytes("utf-8"));
  35.         return bytesToHexString(data);
  36.     }
  37.     public static final String bytesToHexString(byte[] bArray) {
  38.         StringBuffer sb = new StringBuffer(bArray.length);
  39.         String sTemp;
  40.         for (int i = 0; i < bArray.length; i++) {
  41.             sTemp = Integer.toHexString(0xFF & bArray[i]);
  42.             if (sTemp.length() < 2) {
  43.                 sb.append(0);
  44.             }
  45.             sb.append(sTemp.toUpperCase());
  46.         }
  47.         return sb.toString();
  48.     }
  49. }
复制代码
右上角,展示形式改为Project。


按照如下路径,寻找文件并打开。


添加下面代码,打开网络权限。


  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <!--允许程序获取网络状态-->
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
复制代码
按照如下路径,打开对应文件。


对比下图,添加缺少的依靠。


  1. implementation 'com.google.android.material:material:1.0.0'
  2. implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
复制代码
页面计划

项目新建后,会自动打开项目界面,如下图。


此时打开了两个文件,分别后缀是.java和.xml。可以理解为.xml是计划项目页面的部分,.java是计划项目逻辑关系的部分。

起首我们举行页面计划。


Android Studio支撑图形编辑,右上角有三种展示模式。分别为代码,代码与展示,图形计划。

起首我们通过图形界面放置四个文本框和二个按钮。


放置元素后,须要对其举行布局,Androi Stduio共有6种布局方式,分别为:线性布局“LinearLayout”、相对布局“RelativeLayout”、表格布局“TableLayout”、层布局“FrameLayout”

、绝对布局“AbsoluteLayout”、网格布局“GridLayout”,具体部分可网上自行了解。


我们这次利用的是线性布局,及元素在同一条水平或垂直的线上。

实例代码为:

  1. <LinearLayout
  2.         android:layout_width="match_parent"
  3.         android:layout_height="match_parent"
  4.         android:orientation="vertical">
  5.         <LinearLayout
  6.             android:id="@+id/linearLayoutTemperature"
  7.             android:layout_width="match_parent"
  8.             android:layout_height="wrap_content"
  9.             android:gravity="center"
  10.             android:orientation="horizontal"
  11.             android:layout_marginTop="96sp">
  12.             <TextView
  13.                 android:id="@+id/textView1"
  14.                 android:layout_width="65dp"
  15.                 android:layout_height="wrap_content"
  16.                 android:layout_marginStart="20dp"
  17.                 android:text="温度"
  18.                 android:textSize="20sp"
  19.                 android:textStyle="bold" />
  20.             <TextView
  21.                 android:id="@+id/Temp"
  22.                 android:layout_width="71dp"
  23.                 android:layout_height="wrap_content"
  24.                 android:layout_marginStart="16dp"
  25.                 android:text="NuLL"
  26.                 android:textSize="20sp" />
  27.         </LinearLayout>
  28.         <LinearLayout
  29.             android:id="@+id/linearLayoutHumidity"
  30.             android:layout_width="match_parent"
  31.             android:layout_height="wrap_content"
  32.             android:gravity="center"
  33.             android:orientation="horizontal"
  34.             android:layout_marginTop="46sp">
  35.             <TextView
  36.                 android:id="@+id/textView2"
  37.                 android:layout_width="65dp"
  38.                 android:layout_height="wrap_content"
  39.                 android:layout_marginStart="20dp"
  40.                 android:text="湿度"
  41.             android:textSize="20sp"
  42.             android:textStyle="bold" />
  43.             <TextView
  44.                 android:id="@+id/Humi"
  45.                 android:layout_width="71dp"
  46.                 android:layout_height="wrap_content"
  47.                 android:layout_marginStart="16dp"
  48.                 android:text="NuLL"
  49.                 android:textSize="20sp" />
  50.         </LinearLayout>
  51.         <LinearLayout
  52.             android:id="@+id/linearLayoutButtons"
  53.             android:layout_width="match_parent"
  54.             android:layout_height="wrap_content"
  55.             android:gravity="center"
  56.             android:orientation="horizontal"
  57.             android:layout_marginTop="96sp">
  58.             <Button
  59.                 android:id="@+id/open"
  60.                 android:layout_width="wrap_content"
  61.                 android:layout_height="wrap_content"
  62.                 android:text="开" />
  63.             <Button
  64.                 android:id="@+id/close"
  65.                 android:layout_width="wrap_content"
  66.                 android:layout_height="wrap_content"
  67.                 android:text="关" /> <!-- 修改为“关”以与按钮功能匹配 -->
  68.         </LinearLayout>
  69.     </LinearLayout>
复制代码
将新创建的四个文本元素和两个按钮,举行线性布局,对应代码的功能可通过英语翻译大概了解,或自行查阅资料,这里不做解释。


我们设置了两个文本用于现实温度湿度数值,用两个按钮用于控制设备开关。

逻辑计划

实例代码:

  1. //package ..... 这一行保留自己的
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.os.Message;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.CompoundButton;
  11. import android.widget.TextView;
  12. import android.widget.Toast;
  13. import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
  14. import org.eclipse.paho.client.mqttv3.MqttCallback;
  15. import org.eclipse.paho.client.mqttv3.MqttClient;
  16. import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
  17. import org.eclipse.paho.client.mqttv3.MqttException;
  18. import org.eclipse.paho.client.mqttv3.MqttMessage;
  19. import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
  20. import org.json.JSONException;
  21. import org.json.JSONObject;
  22. import java.util.HashMap;
  23. import java.util.Map;
  24. import java.util.concurrent.Executors;
  25. import java.util.concurrent.ScheduledExecutorService;
  26. import java.util.concurrent.TimeUnit;
  27. public class MainActivity extends AppCompatActivity {
  28.     private MqttClient client;
  29.     private MqttConnectOptions options;
  30.     private Handler handler;
  31.     private ScheduledExecutorService scheduler;
  32.     //阿里云三元组
  33.     private String productKey = "k0796zJ6ms6";
  34.     private String deviceName = "QtDev";
  35.     private String deviceSecret = "04c37a6b23ca9a936e8c760d56eca377";
  36.     //Topic
  37.     private final String pub_topic = "/sys/k0796zJ6ms6/QtDev/thing/event/property/post";
  38.     private final String sub_topic = "/sys/k0796zJ6ms6/QtDev/thing/service/property/set";
  39.     private int temp = 0;
  40.     private int humi = 0;
  41.     private TextView Temp;
  42.     private TextView Humi;
  43.     protected void onCreate(Bundle savedInstanceState) {
  44.         super.onCreate(savedInstanceState);
  45.         setContentView(R.layout.activity_main);
  46.         Temp = findViewById(R.id.Temp);
  47.         Humi = findViewById(R.id.Humi);
  48.         Button btn_open = findViewById(R.id.open);
  49.         Button btn_close = findViewById(R.id.close);
  50.         btn_open.setOnClickListener(new View.OnClickListener() {
  51.             @Override
  52.             public void onClick(View v) {
  53.                 //开
  54.                 publish_message("{"params":{"Wind":1},"version":"1.0.0"}");
  55.             }
  56.         });
  57.         btn_close.setOnClickListener(new View.OnClickListener() {
  58.             @Override
  59.             public void onClick(View v) {
  60.                 //关
  61.                 publish_message("{"params":{"Wind":0},"version":"1.0.0"}");
  62.             }
  63.         });
  64.         mqtt_init();
  65.         start_reconnect();
  66.         handler = new Handler() {
  67.             @SuppressLint("SetTextI18n")
  68.             public void handleMessage(Message msg) {
  69.                 super.handleMessage(msg);
  70.                 switch (msg.what) {
  71.                     case 1: //开机校验更新回传
  72.                         break;
  73.                     case 2:  // 反馈回传
  74.                         break;
  75.                     case 3:  //MQTT 收到消息回传   UTF8Buffer msg=new UTF8Buffer(object.toString());
  76.                         String message = msg.obj.toString();
  77.                         Log.d("nicecode", "handleMessage: "+ message);
  78.                         try {
  79.                             //JSON解析获取数据
  80.                             JSONObject jsonObjectALL = null;
  81.                             jsonObjectALL = new JSONObject(message);
  82.                             JSONObject items = jsonObjectALL.getJSONObject("items");
  83.                             JSONObject obj_temp = items.getJSONObject("Temp");
  84.                             JSONObject obj_humi = items.getJSONObject("Humi");
  85.                             temp = obj_temp.getInt("value");
  86.                             humi = obj_humi.getInt("value");
  87.                             Temp.setText(temp + "");
  88.                             Humi.setText(humi + "");
  89.                             Log.d("nicecode", "temp: "+ temp);
  90.                             Log.d("nicecode", "humi: "+ humi);
  91.                         } catch (JSONException e) {
  92.                             e.printStackTrace();
  93.                             break;
  94.                         }
  95.                         break;
  96.                     case 30:  //连接失败
  97.                         Toast.makeText(MainActivity.this, "连接失败", Toast.LENGTH_SHORT).show();
  98.                         break;
  99.                     case 31:   //连接成功
  100.                         Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
  101.                         try {
  102.                             client.subscribe(sub_topic, 1);
  103.                         } catch (MqttException e) {
  104.                             e.printStackTrace();
  105.                         }
  106.                         break;
  107.                     default:
  108.                         break;
  109.                 }
  110.             }
  111.         };
  112.     }
  113.     private void mqtt_init() {
  114.         try {
  115.             String clientId = "a1MoTKOqkVK.test_device1";
  116.             Map<String, String> params = new HashMap<String, String>(16);
  117.             params.put("productKey", productKey);
  118.             params.put("deviceName", deviceName);
  119.             params.put("clientId", clientId);
  120.             String timestamp = String.valueOf(System.currentTimeMillis());
  121.             params.put("timestamp", timestamp);
  122.             // cn-shanghai
  123.             String host_url ="tcp://"+ productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";
  124.             String client_id = clientId + "|securemode=2,signmethod=hmacsha1,timestamp=" + timestamp + "|";
  125.             String user_name = deviceName + "&" + productKey;
  126.             //example.自己的名字 参考package com.example.mqqttest;
  127.             String password = com.example.mqqttest.AliyunIoTSignUtil.sign(params, deviceSecret, "hmacsha1");
  128.             //host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
  129.             System.out.println(">>>" + host_url);
  130.             System.out.println(">>>" + client_id);
  131.             //connectMqtt(targetServer, mqttclientId, mqttUsername, mqttPassword);
  132.             client = new MqttClient(host_url, client_id, new MemoryPersistence());
  133.             //MQTT的连接设置
  134.             options = new MqttConnectOptions();
  135.             //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
  136.             options.setCleanSession(false);
  137.             //设置连接的用户名
  138.             options.setUserName(user_name);
  139.             //设置连接的密码
  140.             options.setPassword(password.toCharArray());
  141.             // 设置超时时间 单位为秒
  142.             options.setConnectionTimeout(10);
  143.             // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
  144.             options.setKeepAliveInterval(60);
  145.             //设置回调
  146.             client.setCallback(new MqttCallback() {
  147.                 @Override
  148.                 public void connectionLost(Throwable cause) {
  149.                     //连接丢失后,一般在这里面进行重连
  150.                     System.out.println("connectionLost----------");
  151.                 }
  152.                 @Override
  153.                 public void deliveryComplete(IMqttDeliveryToken token) {
  154.                     //publish后会执行到这里
  155.                     System.out.println("deliveryComplete---------" + token.isComplete());
  156.                 }
  157.                 @Override
  158.                 public void messageArrived(String topicName, MqttMessage message)
  159.                         throws Exception {
  160.                     //subscribe后得到的消息会执行到这里面
  161.                     System.out.println("messageArrived----------");
  162.                     Message msg = new Message();
  163.                     //封装message包
  164.                     msg.what = 3;   //收到消息标志位
  165.                     msg.obj =message.toString();
  166.                     //发送messge到handler
  167.                     handler.sendMessage(msg);    // hander 回传
  168.                 }
  169.             });
  170.         } catch (Exception e) {
  171.             e.printStackTrace();
  172.         }
  173.     }
  174.     private void mqtt_connect() {
  175.         new Thread(new Runnable() {
  176.             @Override
  177.             public void run() {
  178.                 try {
  179.                     if (!(client.isConnected()))  //如果还未连接
  180.                     {
  181.                         client.connect(options);
  182.                         Message msg = new Message();
  183.                         msg.what = 31;
  184.                         // 没有用到obj字段
  185.                         handler.sendMessage(msg);
  186.                     }
  187.                 } catch (Exception e) {
  188.                     e.printStackTrace();
  189.                     Message msg = new Message();
  190.                     msg.what = 30;
  191.                     // 没有用到obj字段
  192.                     handler.sendMessage(msg);
  193.                 }
  194.             }
  195.         }).start();
  196.     }
  197.     private void start_reconnect() {
  198.         scheduler = Executors.newSingleThreadScheduledExecutor();
  199.         scheduler.scheduleAtFixedRate(new Runnable() {
  200.             @Override
  201.             public void run() {
  202.                 if (!client.isConnected()) {
  203.                     mqtt_connect();
  204.                 }
  205.             }
  206.         }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
  207.     }
  208.     private void publish_message(String message) {
  209.         if (client == null || !client.isConnected()) {
  210.             return;
  211.         }
  212.         MqttMessage mqtt_message = new MqttMessage();
  213.         mqtt_message.setPayload(message.getBytes());
  214.         try {
  215.             client.publish(pub_topic, mqtt_message);
  216.         } catch (MqttException e) {
  217.             e.printStackTrace();
  218.         }
  219.     }
复制代码
自行修改阿里云三元组


注意:如下两行种的R.id.Temp与Humi,与你在.xml定名的id相同。

  1. Temp = findViewById(R.id.Temp);
  2. Humi = findViewById(R.id.Humi);
复制代码
注意:com.example.mqqttest.利用自己的名字 参考package com.example.mqqttest;

  1. String password = com.example.mqqttest.AliyunIoTSignUtil.sign(params, deviceSecret, "hmacsha1");
复制代码
可再次代码上举行二次加工。

项目运行

安装虚拟机



安装完成后启动虚拟机,并运行项目程序。


利用阿里云设备模拟器大概MQTT.fx举行硬件设备模拟,结果展示。



最后,大家就完成了本次计划。请求留下名贵的点赞收藏。

我是一个励志成为嵌入式全栈工程师的大三门生,求实习!!!

B站/CSDN:此乃刘同学

liustu.com.cn


项目展示链接:【Android Studio 实现安卓连接阿里云物联网云平台】https://www.bilibili.com/video/BV1rCpneCEfY?vd_source=4a3d8c11d455291dbb5507669d40a8b8










免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4