本例程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来自动创建。