物联网平台搭建的全过程介绍(五)——基于阿里云物联网平台的Android聊天app源码

本例程Android源码请点此处免费下载

物联网平台搭建的全过程介绍(四)两台设备之间通过云数据流转实现远程通信之Android studio例程中介绍了两台Android设备通过物联网平台进行通信的步骤;

可调颜色大小可加粗可设置段落自动滚到最后一行的TextView

中介绍了用两个按键模拟聊天界面的实现步骤。

那么下一步就把以上两部分内容结合起来,把两个按键中的一个“发送2”监听换成mqtt接收到消息的监听,接收另外一台设备数据流转过来的信息,并显示在TextView中。“发送1”按键监听中,除把发送内容显示在TextView之外,还要通过mqtt发送到物联网平台,然后流转到另外一台设备。这样就真正实现了类似微信、QQ聊天的即时通信app。本例还增加了登录界面和设置昵称的功能。

目录

一、界面设计

1、前台布局

2、layout代码

(1)登录界面activity_login.xml

(2)聊天界面activity_main.xml

(3)设置昵称settings.xml

二、java程序

1、工程文件目录图

 2、java文件

(1)AiotMqttOption.java

(2)登录loginActivity.java

(3)设置settingsActivity.java

(4)主程序聊天MainActivity.java

三、物联网数据流转解析器配置

1、产品功能定义

2、数据源

3、数据目的

4、解析器脚本

四、测试

1、聊天界面

 2、物联网平台接收数据

 五、本例今后需要改进的地方

1、登录的实用化改进

2、添加好友、建群功能的实现

3、阿里云物联网平台API的调用


一、界面设计

1、前台布局

登录界面

聊天界面

设置昵称界面

  

2、layout代码

(1)登录界面activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/back0"
    tools:context=".loginActivity">
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="50dp"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="10dp"
            android:gravity="center"

            android:orientation="horizontal">
            <ImageView
                android:id="@+id/pirlogo"
                android:layout_width="133dp"
                android:layout_height="54dp"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintHorizontal_bias="0.2"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintVertical_bias="0.25"
                android:src="@drawable/ic_stat_name"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:gravity="center"

            android:orientation="horizontal">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/chocolate"
                android:gravity="center"
                android:textSize="25dp"
                android:text="我的聊聊"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:orientation="horizontal">
            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.3"
                android:gravity="center"
                android:textColor="@color/forestgreen"
                android:textSize="18dp"
                android:text="用户名:"/>
            <EditText
                android:id="@+id/name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:textColor="@color/black"
                android:layout_weight="1"
                />
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:orientation="horizontal">
            <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18dp"
                android:textColor="@color/forestgreen"
                android:layout_weight="0.3"
                android:text="密    码:"/>
            <EditText
                android:id="@+id/pwd"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:inputType="textPassword"
                android:textColor="@color/black"
                android:layout_weight="1"
                />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="20dp"
            android:layout_marginRight="20dp"
            android:orientation="horizontal">
            <Button
                android:id="@+id/login"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_margin="5dp"
                android:background="@drawable/button0"
                android:textColor="@color/black"
                android:text="@string/login"
                />
            <Button
                android:id="@+id/settings"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_margin="5dp"
                android:background="@drawable/button0"
                android:textColor="@color/black"
                android:text="@string/settings"
                />
        </LinearLayout>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

(2)聊天界面activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/wechat_bottombar"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginRight="0dp"
        android:background="@drawable/bg_stoke_4"
        android:layout_marginBottom="0dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginTop="0dp"
            android:layout_marginRight="0dp"
            android:background="@drawable/bg_stoke_4"
            android:layout_marginBottom="0dp"
            android:layout_weight="0"
            android:orientation="horizontal">

                <TextView
                    android:id="@+id/tv_title"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:scrollbars="vertical"
                    android:background="@drawable/bg_stoke_4"
                    android:layout_weight="1"
                    android:textSize="16dp"
                    android:typeface="sans"
                    android:textColor="@color/black"
                    android:textStyle="normal"
                    android:padding="10dp"
                    android:gravity="center"
                    android:layout_marginLeft="10dp"
                    android:layout_marginRight="10dp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintLeft_toLeftOf="parent"
                    app:layout_constraintRight_toRightOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

        </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="5dp"
        android:layout_marginRight="0dp"
        android:background="@drawable/bg_stoke_1"
        android:layout_marginBottom="0dp"
        android:layout_weight="1"
        android:orientation="horizontal">

        <ScrollView
            android:id="@+id/sv_chat"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:background="@drawable/bg_stoke_4"
            >
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            android:background="@drawable/bg_stoke_4"
            android:focusable="true"
            android:layout_marginTop="5dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        </ScrollView>
    </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginTop="0dp"
            android:layout_marginRight="0dp"
            android:background="@drawable/bg_stoke_3"
            android:layout_marginBottom="0dp"
            android:layout_weight="0"
            android:gravity="center"
            android:orientation="horizontal">

            <EditText
                android:id="@+id/et_send_content"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/white"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="0dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="0dp"
                android:textSize="16dp"
                android:typeface="sans"
                android:textColor="@color/black"
                android:textStyle="normal"
                android:padding="8dp"
                android:layout_weight="1"
                />

            <Button
                android:id="@+id/btn_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:layout_marginBottom="0dp"
                android:layout_weight="0"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                android:background="@drawable/button0"
                android:text="@string/chat_send2"
                android:textSize="16dp"
                />

        </LinearLayout>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

(3)设置昵称settings.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/wechat_bottombar"
    tools:context=".settingsActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="0dp"
        android:layout_marginTop="0dp"
        android:layout_marginRight="0dp"
        android:background="@drawable/bg_stoke_4"
        android:layout_marginBottom="0dp"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginTop="0dp"
            android:layout_marginRight="0dp"
            android:background="@drawable/bg_stoke_1"
            android:layout_marginBottom="0dp"
            android:layout_weight="0"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_setings_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scrollbars="vertical"
                android:background="@drawable/bg_stoke_4"
                android:layout_weight="1"
                android:textSize="16dp"
                android:typeface="sans"
                android:textColor="@color/black"
                android:textStyle="normal"
                android:padding="5dp"
                android:gravity="center"
                android:layout_marginTop="0dp"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginTop="100dp"
            android:layout_marginRight="0dp"
            android:background="@drawable/bg_stoke_4"
            android:layout_marginBottom="0dp"
            android:layout_weight="0"
            android:orientation="horizontal">

            <TextView

                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scrollbars="vertical"
                android:background="@drawable/bg_stoke_4"
                android:layout_weight="1"
                android:textSize="16dp"
                android:typeface="sans"
                android:textColor="@color/black"
                android:textStyle="normal"
                android:padding="10dp"
                android:gravity="center"
                android:text="我的昵称:"
                android:layout_marginLeft="10dp"
                android:layout_marginRight="10dp"
                 />

            <TextView
                android:id="@+id/tv_setings_nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:textSize="18dp"
                android:textColor="@color/forestgreen"
                android:layout_weight="1"
                android:text="我的昵称"/>

        </LinearLayout>



        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="0dp"
            android:layout_marginTop="10dp"
            android:layout_marginRight="0dp"
            android:background="@drawable/bg_stoke_4"
            android:layout_marginBottom="0dp"
            android:layout_weight="0"
            android:gravity="center"
            android:orientation="horizontal">


            <EditText
                android:id="@+id/et_settings_nickname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@color/white"
                android:layout_marginLeft="10dp"
                android:layout_marginTop="0dp"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="0dp"
                android:textSize="16dp"
                android:typeface="sans"
                android:textColor="@color/black"
                android:textStyle="normal"
                android:padding="8dp"
                android:layout_weight="1"

                />

            <Button
                android:id="@+id/btn_set"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="5dp"
                android:layout_marginBottom="0dp"
                android:layout_weight="0"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                android:background="@drawable/button0"
                android:text="@string/btn_set"
                android:textSize="16dp"
                />

        </LinearLayout>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

二、java程序

1、工程文件目录图

 2、java文件

(1)AiotMqttOption.java

package com.example.myaliyunchat;

import java.math.BigInteger;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * MQTT建连选项类,输入设备三元组productKey, deviceName和deviceSecret, 生成Mqtt建连参数clientId,username和password.
 */
class AiotMqttOption {
    private String username = "";
    private String password = "";
    private String clientId = "";

    String getUsername() { return this.username;}
    String getPassword() { return this.password;}
    String getClientId() { return this.clientId;}

    /**
     * 获取Mqtt建连选项对象
     * @param productKey 产品秘钥
     * @param deviceName 设备名称
     * @param deviceSecret 设备机密
     * @return AiotMqttOption对象或者NULL
     */
    public AiotMqttOption getMqttOption(String productKey, String deviceName, String deviceSecret) {
        if (productKey == null || deviceName == null || deviceSecret == null) {
            return null;
        }

        try {
            String timestamp = Long.toString(System.currentTimeMillis());

            // clientId
            this.clientId = productKey + "." + deviceName + "|timestamp=" + timestamp +
                    ",_v=paho-android-1.0.0,securemode=2,signmethod=hmacsha256|";

            // userName
            this.username = deviceName + "&" + productKey;

            // password
            String macSrc = "clientId" + productKey + "." + deviceName + "deviceName" +
                    deviceName + "productKey" + productKey + "timestamp" + timestamp;
            String algorithm = "HmacSHA256";
            Mac mac = Mac.getInstance(algorithm);
            SecretKeySpec secretKeySpec = new SecretKeySpec(deviceSecret.getBytes(), algorithm);
            mac.init(secretKeySpec);
            byte[] macRes = mac.doFinal(macSrc.getBytes());
            password = String.format("%064x", new BigInteger(1, macRes));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        return this;
    }
}

(2)登录loginActivity.java

package com.example.myaliyunchat;


import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class loginActivity extends AppCompatActivity {


    private EditText User_name,User_pwd;

    String loginer1="20220001";
    String loginer2="20220002";
    String Password1="123456";
    String Password2="654321";
    boolean check1;
    boolean check2;
    String str_name;
    String str_pwd;

    SharedPreferences sp_user;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_login);

        User_name = this.findViewById(R.id.name);            //用户名输入框
        User_pwd = this.findViewById(R.id.pwd);              //密码输入框
        Button btnlogin = this.findViewById(R.id.login);         //登录按钮
        Button btn_set = this.findViewById(R.id.settings);

        sp_user=this.getSharedPreferences("sp_user",this.MODE_PRIVATE);
        User_name.setText(sp_user.getString("Name",null));
        User_pwd.setText(sp_user.getString("Password",null));


        btnlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                SharedPreferences.Editor editor = sp_user.edit();

                str_name = User_name.getText().toString();
                str_pwd = User_pwd.getText().toString();
                check1=(str_name.equals(loginer1)) &&(str_pwd.equals(Password1));
                check2=(str_name.equals(loginer2)) &&(str_pwd.equals(Password2));

                if(check1 || check2)
                {
                    editor.putString("Name", str_name);
                    editor.putString("Password", str_pwd);
                    editor.apply();

                    Intent intent = new Intent(loginActivity.this, MainActivity.class);
                    startActivity(intent);
                }
                else
                {
                    User_name.setText("");
                    User_pwd.setText("");
                    Toast toast = Toast.makeText(loginActivity.this, getText(R.string.wrong_neme_or_psw), Toast.LENGTH_LONG);
                    toast.show();

                }
            }
        });

        btn_set.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                    Intent intent = new Intent(loginActivity.this, settingsActivity.class);
                    startActivity(intent);
                }

        });

}


}

(3)设置settingsActivity.java

package com.example.myaliyunchat;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class settingsActivity extends AppCompatActivity {

    private EditText et_nickname;
    TextView tv_title,tv_nickname;
    String str_nickname;
    SharedPreferences sp_user;//存放用户账号、密码、昵称信息

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings);
        tv_title = this.findViewById(R.id.tv_setings_title);//标题栏
        et_nickname = this.findViewById(R.id.et_settings_nickname);//昵称输入框
        tv_nickname= this.findViewById(R.id.tv_setings_nickname);//昵称显示
        Button btn_set = this.findViewById(R.id.btn_set);         //设置确认
        tv_title.setText(R.string.settings_title);

        sp_user=this.getSharedPreferences("sp_user",this.MODE_PRIVATE);
        tv_nickname.setText(sp_user.getString("nickname",null));
        btn_set.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                SharedPreferences.Editor editor = sp_user.edit();
                str_nickname = et_nickname.getText().toString();
                editor.putString("nickname", str_nickname);
                editor.apply();
                tv_nickname.setText(sp_user.getString("nickname",null));
                et_nickname.setText("");

            }
        });

}

}

(4)主程序聊天MainActivity.java

package com.example.myaliyunchat;


import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONException;
import org.json.JSONObject;
import org.eclipse.paho.android.service.MqttAndroidClient;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;


public class MainActivity extends AppCompatActivity {

    /* 设备三元组信息 */
    //20220002
    private String IotInstanceId="";
    private String PRODUCTKEY="";
    private String DEVICENAME="";
    private String DEVICESECRET="";

    //20221001
    private String PRODUCTKEY1="***********";
    private String DEVICENAME1="20220001";
    private String DEVICESECRET1="*********************************";

    //20220002
    private String PRODUCTKEY2="***********";
    private String DEVICENAME2="20220002";
    private String DEVICESECRET2="*********************************";

    String loginName;
    String NickName;
    String loginer1="20220001";
    String loginer2="20220002";

    //系统默认昵称
    String NickName1="曹操";
    String NickName2="刘备";


    /* 自动Topic, 用于上报消息 */
    private String PUB_TOPIC;

    /* 自动Topic, 用于接受消息 */
    private String SUB_TOPIC;

    /* 阿里云Mqtt服务器域名 */
    String host;

    /*Mqtt建连参数*/
    private String clientId;
    private String userName;
    private String passWord;

    //设置log.e的TAG
    private final String TAG = "AiotMqtt";

    MqttAndroidClient mqttAndroidClient;

    SharedPreferences sp_user;//存放用户账号、密码、昵称信息

    //ui相关变量
    TextView tv_content,tv_title;
    EditText et_send_content;
    Button btn_send;
    ScrollView scrollView;

    @SuppressLint("WrongViewCast")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        scrollView=this.findViewById(R.id.sv_chat);
        tv_content= this.findViewById(R.id.tv_content);
        tv_title= this.findViewById(R.id.tv_title);
        tv_content.setSelected(true);


        et_send_content=this.findViewById(R.id.et_send_content);
        tv_content.setTextSize(16);

        btn_send= findViewById(R.id.btn_send);

        sp_user=this.getSharedPreferences("sp_user",this.MODE_PRIVATE);
        loginName=sp_user.getString("Name",null);


        //根据登录账号的不同分别选择不同的阿里云三要素、昵称
        assert loginName != null;
        if(loginName.equals(loginer1))
        {
            PRODUCTKEY=PRODUCTKEY1;
            DEVICENAME=DEVICENAME1;
            DEVICESECRET=DEVICESECRET1;
            NickName=NickName1;
        }
        else if(loginName.equals(loginer2))
        {
            PRODUCTKEY=PRODUCTKEY2;
            DEVICENAME=DEVICENAME2;
            DEVICESECRET=DEVICESECRET2;
            NickName=NickName2;
        }
        else
        {
            PRODUCTKEY="";
            DEVICENAME="";
            DEVICESECRET="";
            NickName="";
        }
        if(Objects.requireNonNull(sp_user.getString("Name", null)).isEmpty())
        {
            if(loginName.equals(loginer1))
            {
                NickName=NickName1;
            }
            else if(loginName.equals(loginer2))
            {
                NickName=NickName2;
            }
            else
            {
                NickName="";
            }
            SharedPreferences.Editor editor = sp_user.edit();
            editor.putString("nickname", NickName);
            editor.apply();
        }

        NickName=sp_user.getString("nickname",null);


        //根据阿里云三要素构建subtopic、pubtopic、host
        AliyunTopicHostSet(0);

        //MQTT建连选项类,输入设备三元组productKey, deviceName和deviceSecret, 生成Mqtt建连参数clientId,username和password
        AiotMqttOption aiotMqttOption = new AiotMqttOption().getMqttOption(PRODUCTKEY, DEVICENAME, DEVICESECRET);
        if (aiotMqttOption == null) {
            Log.e(TAG, "device info error");
        } else {
            clientId = aiotMqttOption.getClientId();
            userName = aiotMqttOption.getUsername();
            passWord = aiotMqttOption.getPassword();
        }



        /* Mqtt建连 */
        try {

            /* 创建MqttConnectOptions对象并配置username和password */
            final MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
            mqttConnectOptions.setUserName(userName);
            mqttConnectOptions.setPassword(passWord.toCharArray());

            /* 创建MqttAndroidClient对象, 并设置回调接口 */
            //String plstring;
            mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), host, clientId);
            mqttAndroidClient.connect(mqttConnectOptions,null, new IMqttActionListener() {
                //连接成功方法
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "connect succeed");

                    subscribeTopic(SUB_TOPIC);
                }
                //连接失败方法
                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "connect failed");
                }
            });

        } catch (MqttException e) {
            e.printStackTrace();
        }

        /**
         * mqtt回调类,此类内包含三个方法:connectionLost(掉线),messageArrived(订阅消息到达),deliveryComplete(发布消息送达)
         */
        mqttAndroidClient.setCallback(new MqttCallback() {

            //连接中断方法
            @Override
            public void connectionLost(Throwable cause) {
                Log.i(TAG, "connection lost");
            }

            @SuppressLint("SetTextI18n")
            @Override

            //订阅消息后,消息到达时方法
            public void messageArrived(String topic, MqttMessage message) throws Exception {

                Log.i(TAG, "topic: " + topic + ", msg: " + new String(message.getPayload()));

                String payload = new String(message.getPayload());
//                JSONObject Jobj_payload = new JSONObject(payload);
//                JSONObject Jobj_params=new JSONObject(Jobj_payload.getString("params"));

                JSONObject Jobj_params = new JSONObject(payload);

                String chat_user=Jobj_params.getString("user");
                String char_message=Jobj_params.getString("message");
                Date curDate = new Date(System.currentTimeMillis());
                SimpleDateFormat format= new SimpleDateFormat("M月d日 HH:mm", Locale.getDefault());
                String str_curDate = format.format(curDate);

                tv_content.append( Html.fromHtml("<font color='#696969' size='5'>"+chat_user +"("+str_curDate+"):"+"</font>"+"<br>"));
                tv_content.append( Html.fromHtml("<p><font color='#D2691E' size='5'>"+char_message+"</font><p>"+"<br>"));
                tv_title.setText(chat_user);

            }// messageArrived类结束标志

            //发布消息后,消息投递成功后返回方法
            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                Log.i(TAG, "msg delivered");
            }
        });//mqttAndroidClient.setCallback类结束标志



        /**
         * 点"上传"按钮后,将数学、语文分数发送到阿里云物联网平台
         */
        btn_send.setOnClickListener((view)-> {


            String send_content=et_send_content.getText().toString();
            Date curDate = new Date(System.currentTimeMillis());
            SimpleDateFormat format= new SimpleDateFormat("M月d日 HH:mm", Locale.getDefault());
            String str_curDate = format.format(curDate);

            tv_content.append( Html.fromHtml("<font color='#696969' size='10'>"+NickName+"("+str_curDate+"):"+"</font>"+"<br>"));
            tv_content.append( Html.fromHtml("<p><font color='#3CB371' size='10'>"+send_content+"</font><p>"+"<br>"));
            et_send_content.setText("");

            //发布消息的payload数据包生成方法一:利用JSONObject,分两层将params内的数学、语文分数,和params外的id,version打成一个json数据包
            JSONObject Jobj_payload = new JSONObject();
            JSONObject Jobj_params = new JSONObject();
            try {
                Jobj_params.put("message",send_content);
                Jobj_params.put("user_id",NickName);
                Jobj_payload.put("id", DEVICENAME);
                Jobj_payload.put("version", "1.0");
                Jobj_payload.put("params", Jobj_params);

            } catch (JSONException e) {
                e.printStackTrace();
            }
            publishMessage(Jobj_payload.toString());
            et_send_content.setText("");
//            scrollView.fullScroll(ScrollView.FOCUS_DOWN);


        });

        scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override

            public void onGlobalLayout() {
                scrollView.post(new Runnable() {
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);

                    }

                });

            }

        });
    }//oncreat结束标志


    /**
     * 设置阿里云物联网平台参数
     * @param IotInstanceType 实例类型,0:华东2(上海)服务器公共实例;1:企业实例
     */
    public void AliyunTopicHostSet(int IotInstanceType) {

        SUB_TOPIC ="/sys/" + PRODUCTKEY + "/" + DEVICENAME + "/thing/service/property/set";
        PUB_TOPIC = "/sys/" + PRODUCTKEY + "/" + DEVICENAME + "/thing/event/property/post";

        if(IotInstanceType==0)
        {
            host="tcp://" + PRODUCTKEY + ".iot-as-mqtt.cn-shanghai.aliyuncs.com:1883";//适用于公共实例华东2(上海)
        }
        else
        {
            host="tcp://" + IotInstanceId + ".mqtt.iothub.aliyuncs.com:1883";//试用于企业实例
        }

    }

    /**
     * 订阅特定的主题
     * @param topic mqtt主题
     */
    public void subscribeTopic(String topic) {
        try {
            mqttAndroidClient.subscribe(topic, 0, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "subscribed succeed");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "subscribed failed");
                }
            });

        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    /**
     * 向默认的主题/user/update发布消息
     * @param payload 消息载荷
     */
    public void publishMessage(String payload) {
        try {
            if (!mqttAndroidClient.isConnected()) {
                mqttAndroidClient.connect();
            }

            MqttMessage message = new MqttMessage();
            message.setPayload(payload.getBytes());
            message.setQos(0);
            mqttAndroidClient.publish(PUB_TOPIC, message,null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    Log.i(TAG, "publish succeed!");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    Log.i(TAG, "publish failed!");
                }
            });
        } catch (MqttException e) {
            Log.e(TAG, e.toString());
            e.printStackTrace();
        }
    }
}

三、物联网数据流转解析器配置

1、产品功能定义

产品名称:我的聊聊,在该产品下创建两个设备:20220001和20220002

2、数据源

3、数据目的

4、解析器脚本

var data = payload("json");

var select = {};

select.put("message", getOrNull(data,"items","message","value"));
select.put("user", getOrNull(data,"items","user_id","value"));


if(deviceName()=="20220001")
{
writeIotTopic(1003, "/sys/***********/20220002/thing/service/property/set", select);
}

if(deviceName()=="20220002")
{
writeIotTopic(1003, "/sys/***********/20220001/thing/service/property/set", select);

因为数据源选择的是全部设备,所以20220001和20220002上传的数据都会流转到解析器来,所以在脚本中,要控制设备上传的数据不转发自己本身,只转发给另外一个用户。

四、测试

1、聊天界面

刘备端截图1

刘备端截图2

 2、物联网平台接收数据

曹操端上传数据

曹操端“聊天消息”记录

 五、本例今后需要改进的地方

1、登录的实用化改进

本例“我的聊聊”app两个登录账号以及两组阿里云物联网平台的三要素都是固定存在app内的,实际聊天工具应该把“我的聊聊”登录账号、密码、昵称以及对应的阿里云三要素存放到云服务器或者云数据库内。首先要访问数据库或者服务器web页面,验证账号和密码,通过之后,再从数据库中取出昵称、阿里云三要素,然后再使用这组三要素连接物联网平台,完成接入、订阅和发布的功能。

2、添加好友、建群功能的实现

本例只是实现了一对一聊天的基本功能,更加实用的聊天工具需要可以添加好友、建群,可以选择不同好友进行一对一聊天,可以群聊。这些功能需要app端相应功能,还要配合解析器脚本的合理化设计。

3、阿里云物联网平台API的调用

本例物联网平台设备的创建和云数据流转都是通过手工进行的,实际的项目需要能在app端调用API来自动创建。

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
1.物联网的开发难度越来越低当小王被老板要求开发一个物联网项目时,他面临这许多种解决方案,从硬件到软件一应俱全。有的提供了模块化的硬件,有的提供了高度集成的软件开发环境,有的支持python开发,有的支持图形化开发,有的提供硬件SDK,有的提供从云端到移动端成套的解决方案。小王该如何选择?的确,物联网的开发难度越来越低,只要你想,就可以拖拖拽拽做出来一个简单的设备。移动端APP呢?也是如此,你甚至可以登陆某平台的网站在线生成一个安装包直接安装到手机上。但是这些便利化的前提是失去对核心技术的掌握,以及跳转界面、使用习惯等无法把控。2.移动端APP技能是必备当学习物联网技术的小赵到某公司应聘时,公司技术主管对他的知识结构基本满意。然后让他开发一个物联网项目,要软硬件结合,移动端APP是必备的。小赵可以很快做出来一台基于ESP8266的硬件设备,连接到某物联网平台,做出来一个手机端的APP。但是主管对这个APP不太满意,问小赵自己会不会制作手机APP?小赵有些尴尬。为什么移动端APP技能是必备?因为物联网技术涉及到的知识领域有很多个,能够自己做出APP才算是将这些领域的知识完全掌握。就像是一个侠客的武功,最厉害的那个还没有练成,还不能算是真正的高手。3.定制APP价格很贵市场上有不少的物联网软件公司开展物联网应用APP的定制业务,当然价格不菲。如果是公司采购,你将花费较大的价格采购到一个未来并不可控的APP。反过来说,如果是学生应聘,你学到移动端应用知识,将大大提升你的竞争力,你的技能将成为核心竞争力。4.没有类似的教程原因就不多说了。即使有一些片段代码给了大家,大家也做不出来一个能用的APP。5.本课程要讲什么基于阿里云物联网平台(其他物联网平台类似),带您使用Android Studio编写一个安卓APP,实现连接阿里云物联网平台,控制一台智能灯。通过一个软硬件结合项目,结合源代码,一点一点为大家讲解怎么样连接阿里云物联网平台,每一个步骤是怎么回事,源代码怎么实现。为了照顾一些零基础的朋友,课程中还会用一些通俗的语言介绍这些知识,让大家掌握书上和网络上一些不太注意的技术细节。  
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值