Uni-app SDK
概述
店滴物联网云平台的 uni-app JavaScript SDK 是一套用于在 uni-app 项目中快速集成物联网功能的工具包。SDK 包含了 HTTP 请求、WebSocket 通信、设备控制等核心功能,帮助开发者快速构建物联网应用。
功能特性
- HTTP 请求封装: 统一的 API 调用接口,支持拦截器、错误处理等功能
- WebSocket 通信: 基于 WebSocket 的实时双向通信,支持设备控制和状态监听
- 设备管理: 提供设备数据获取、控制指令发送等功能
- 权限管理: 支持用户认证、权限验证等功能
- 通用工具: 包含常用工具函数和常量定义
安装与配置
1. 引入 SDK
在项目的入口文件 main.js 中引入并配置 SDK:
import ddiot from '@/uni_modules/ddiot-ui/js_sdk/index.js'
import diandi from './config.js'
// 在 createApp 函数中使用
export function createApp() {
const app = createSSRApp(App)
const pinia = createPinia()
app.use(pinia)
// 全局挂载
app.config.globalProperties.$wxapp_id = diandi.wxapp_id
app.config.globalProperties.$ddiot = ddiot
// 初始化 ddiot 插件
app.use(ddiot, {
websocketConf: {
url: "wss://iot.ddicms.com:9502/addons", // WebSocket 服务器地址
heartRateType: 'heart', // 心跳类型
authUrl: 'wss://iot.ddicms.com:9502/auth', // 认证服务器地址
heartRate: 20000, // 心跳间隔(毫秒)
username: 'blocc', // 用户名
password: '12345678', // 密码
app_secret: 'c1WlCFNGJEM2PYXmifQHLrSwnkpvKuDs', // 应用密钥
app_id: 'wPKnajOJMNX0SD5b', // 应用ID
},
http: {
successCode: 200,
apiConfig: {
bloc_id: diandi.bloc_id,
store_id: diandi.store_id,
baseUrl: diandi.baseUrl,
siteUrl: diandi.siteUrl,
uploadImgUrl: diandi.baseUrl + '/upload/images',
imgBaseUrl: diandi.siteUrl + '/attachment/',
// ... 其他配置
}
}
})
return {
app
}
}
2. WebSocket 配置参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | String | 是 | WebSocket 服务器地址 |
| authUrl | String | 是 | 认证服务器地址 |
| heartRateType | String | 是 | 心跳消息类型 |
| heartRate | Number | 是 | 心跳间隔时间(毫秒) |
| app_id | String | 是 | 应用标识符 |
| app_secret | String | 是 | 应用密钥 |
WebSocket 使用指南
1. 初始化 WebSocket
SDK 提供了 createSocket 方法来创建 WebSocket 连接:
// 在页面或组件中使用
import { getCurrentInstance } from 'vue'
const { proxy } = getCurrentInstance()
const $ddiot = proxy.$ddiot
// 创建 WebSocket 连接
const initWebSocket = async () => {
if ($ddiot) {
try {
const res = await $ddiot.createSocket('addons')
console.log('WebSocket 创建结果:', res)
if (res && $ddiot.websocket) {
const websocket = $ddiot.websocket
// 监听全局消息
websocket.on('*', (message) => {
console.log('全局消息监听', message)
})
// 监听临时密钥响应
websocket.on('temp_secret_res', (message) => {
console.log('temp_secret_res', message)
if (message.code === 200) {
uni.setStorageSync('app_secret', message.data.temp_secret)
}
})
// 获取临时密钥
websocket.emit("temp-secret", {
'app_id': $ddiot.appId,
}, 'auth', 'addons', 'temp-secret')
}
} catch (error) {
console.error('WebSocket 初始化失败:', error)
}
}
}
2. WebSocket 消息监听
SDK 支持多种消息类型的监听:
// 监听临时密钥过期
websocket.on('app_secret_error', (message) => {
console.log('app_secret_error', message)
websocket.emit("temp-secret", {
'app_id': $ddiot.appId,
}, 'auth', 'addons', 'temp-secret')
})
// 监听命令响应
websocket.on('command_res', (message) => {
console.log('command_res', message)
if (message.code === 200) {
uni.showLoading({
title: message.message
})
setTimeout(() => {
uni.hideLoading()
}, 1000)
}
})
// 监听心跳响应
websocket.on('heart_res', (message) => {
console.log('heart_res', message)
})
// 监听操作错误
websocket.on('operation_error', (message) => {
console.log('operation_error', message)
})
// 监听操作成功
websocket.on('operation_success', (message) => {
console.log('operation_success', message)
uni.showToast({
title: '操作成功',
duration: 1500,
icon: 'none'
})
})
3. 发送设备控制命令
通过 WebSocket 发送设备控制指令:
// 发送设备控制命令
const sendControlCommand = (func) => {
if ($ddiot.websocket && $ddiot.websocket._connectioned) {
try {
$ddiot.websocket.emit("operation", {
"device_id": Number(func.device_id),
"id": func.instruction_id,
"imei": func.device_mac,
}, 'yrddtu', 'dtu', 'command')
} catch (error) {
console.error('发送命令失败:', error)
}
} else {
console.log('WebSocket 连接未初始化')
}
}
实际应用示例
设备数据展示页面
参考 allData.vue 页面的实际应用:
<template>
<view class="page">
<!-- Tab 切换 -->
<scroll-view class="detail-tab" :show-scrollbar="false" id="tab-wrap" scroll-x :scroll-left="scrollLeft">
<view v-for="(item, index) in funcList" :key="item.id" :id="'tab-' + index" class="tab-item"
:class="{ active: current === index }" @click="changeTab(index)">
{{ item.title }}
</view>
</scroll-view>
<!-- Swiper 内容 -->
<swiper class="detail-swiper" :current="current" @change="onSwiperChange" :duration="300">
<swiper-item v-for="(goods, gIndex) in funcList" :key="goods.id">
<view class="swiper-list">
<view class="tool-item" v-for="(err, eIndex) in goods.property" :key="err.id">
<view class="label">
{{ err.label}}
</view>
<view class="data-value">
{{ err.value }}{{ err.unit ? ' (' + err.unit + ')' : '' }}
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
<!-- 浮动操作按钮 -->
<view class="floating-action-btn" @click="openSetting">
<uni-icons type="gear" size="34" color="#567feb"></uni-icons>
</view>
<!-- 设置弹窗 -->
<uni-popup ref="popup" type="top" :safe-area="false">
<view class="setting-popup">
<view class="close" @click="closeSetting">
<uni-icons type="clear" size="30" color="#9e9e9e"></uni-icons>
</view>
<view class="title">{{ funcList[current]?.title }}操作</view>
<view class="list">
<view class="list-item" v-for="(func, gIndex) in funcList[current]?.function" :key="func.id"
@click="handleOperationClick(func)">
<view class="label">
{{ func.label }}
</view>
<view class="data-value">
{{ func.value }}{{ func.unit ? ' (' + func.unit + ')' : '' }}
</view>
</view>
</view>
</view>
</uni-popup>
</template>
<script setup>
import {
onShow,
onLoad
} from '@dcloudio/uni-app'
import {
ref,
nextTick,
getCurrentInstance
} from 'vue'
const {
proxy
} = getCurrentInstance()
const $ddiot = proxy.$ddiot
const deviceMac = ref('')
/* 数据 */
const funcList = ref([])
const current = ref(0)
const scrollLeft = ref(0)
const websocket = ref(null)
const isConnected = ref(false)
/* popup */
const popup = ref(null)
// 初始化 WebSocket
const initWebSocket = async () => {
console.log('开始初始化 WebSocket')
if ($ddiot) {
try {
const res = await $ddiot.createSocket('addons')
console.log('WebSocket 创建结果:', res)
if (res && $ddiot.websocket) {
websocket.value = $ddiot.websocket
isConnected.value = true
// 全局消息监听
websocket.value.on('*', (message) => {
console.log('全局消息监听message', message)
})
// 监听临时秘钥响应
websocket.value.on('temp_secret_res', (message) => {
console.log('temp_secret_res', message)
if (message.code === 200) {
uni.setStorageSync('app_secret', message.data.temp_secret)
}
})
// 监听临时秘钥过期,过期了就重新获取
websocket.value.on('app_secret_error', (message) => {
console.log('app_secret_error', message)
websocket.value.emit("temp-secret", {
'app_id': $ddiot.appId,
}, 'auth', 'addons', 'temp-secret')
})
// 监听命令响应
websocket.value.on('command_res', (message) => {
console.log('command_res', message)
if (message.code === 200) {
uni.showLoading({
title: message.message
})
setTimeout(() => {
uni.hideLoading()
}, 1000)
}
})
// 监听心跳响应
websocket.value.on('heart_res', (message) => {
console.log('heart_res', message)
})
// 监听操作错误
websocket.value.on('operation_error', (message) => {
console.log('operation_error', message)
})
// 监听操作成功
websocket.value.on('operation_success', (message) => {
console.log('operation_success', message)
// 删除缓存池该事件消息
if (websocket.value.removeBufferByEvent) {
websocket.value.removeBufferByEvent(message.event)
}
})
// 获取临时秘钥
websocket.value.emit("temp-secret", {
'app_id': $ddiot.appId,
}, 'auth', 'addons', 'temp-secret')
}
} catch (error) {
console.error('WebSocket 初始化失败:', error)
}
}
}
/* 打开弹窗 */
const openSetting = (err) => {
popup.value?.open()
}
const closeSetting = () => {
popup.value?.close()
}
/* tab 切换 */
const changeTab = (index) => {
setCurrent(index)
}
/* swiper 切换 */
const onSwiperChange = (e) => {
setCurrent(e.detail.current)
}
const handleOperationClick = (func) => {
console.log('WebSocket 实例:', websocket.value)
console.log('WebSocket 连接状态:', isConnected.value)
// 检查 WebSocket 连接是否存在
if (websocket.value && isConnected.value) {
// 发送设备控制命令示例
try {
websocket.value.emit("operation", {
"device_id": Number(func.device_id),
"id": func.instruction_id,
"imei": func.device_mac,
}, 'yrddtu', 'dtu', 'command')
} catch (error) {
console.error('发送命令失败:', error)
}
} else {
console.log('WebSocket 连接未初始化')
// 尝试重新连接
initWebSocket()
}
}
/* 设置当前项 + tab 自动居中 */
const setCurrent = (index) => {
current.value = index
scrollToTab(index)
}
// 获取设备组数据
const getDeviceGroupData = (device_mac) => {
$ddiot.request('/device/deviceGroup', 'POST', {
device_mac
}, true, {
scene: 'iot'
}).then(res => {
funcList.value = res.data.child_device
nextTick(() => {
scrollToTab(0)
})
})
}
onLoad((options) => {
deviceMac.value = options.mac || ''
getDeviceGroupData(options.mac)
// 初始化 WebSocket 连接
initWebSocket()
})
</script>
WebSocket 类详解
Socket 类构造函数
constructor(option = {}, route = 'addons') {
this._url = route === 'addons' ? option.url : option.authUrl;
this._reconnection = option.reconnection || true; // 是否自动重连
this._buffer = option.buffer || true; // 是否建立缓存池
this._heart_rate = option.heartRate > 0 ? option.heartRate : 60000; // 心跳间隔
this._project_id = option.project_id;
this._app_id = option.app_id;
this._app_secret = option.app_secret;
this._device_id = option.device_id;
this.init();
}
主要方法
1. on(event, handler, single = false)
注册事件监听器
// 监听特定事件
websocket.on('command_res', (message) => {
console.log('收到命令响应:', message)
})
// 监听所有消息
websocket.on('*', (message) => {
console.log('收到所有消息:', message)
})
2. emit(event, param = {}, addons = '', controller = '', action = '')
发送消息到服务器
// 发送设备控制命令
websocket.emit("operation", {
"device_id": 123,
"id": 456,
"imei": "device_mac_address",
}, 'yrddtu', 'dtu', 'command')
3. close()
关闭 WebSocket 连接
websocket.close()
4. getState()
获取连接状态
// 返回值:0-连接中,1-连接成功,2-重连中,3-失败
const state = await websocket.getState()
缓存池机制
SDK 提供了缓存池机制,确保在网络不稳定时消息不会丢失:
// 添加到缓存池
await websocket.addBuffer(data)
// 根据事件删除缓存
await websocket.removeBufferByEvent(event)
// 清空所有缓存
await websocket.removeBufferAll()
// 获取缓存
const buffer = await websocket.getBuffer(event)
错误处理
SDK 提供了完善的错误处理机制:
// 监听连接错误
websocket.on('error', (err) => {
console.error('WebSocket 连接错误:', err)
})
// 监听重连错误
websocket.on('reconnectionerror', (err) => {
console.error('WebSocket 重连错误:', err)
})
最佳实践
- 连接管理: 在页面加载时初始化 WebSocket,在页面卸载时正确关闭连接
- 状态检查: 发送消息前检查连接状态
- 错误处理: 始终包含适当的错误处理逻辑
- 资源清理: 及时移除事件监听器,避免内存泄漏
- 重连机制: 利用 SDK 内置的重连机制,无需手动实现
注意事项
- 确保在发送消息前 WebSocket 已成功连接
- 正确处理临时密钥过期的情况
- 合理设置心跳间隔,避免频繁连接
- 注意网络环境变化对 WebSocket 连接的影响
- 在生产环境中使用安全的 WebSocket 连接(wss://)
常见问题
Q: WebSocket 连接失败怎么办?
A: 检查网络连接、服务器地址、认证信息是否正确,查看控制台错误信息。
Q: 消息发送失败如何处理?
A: SDK 会自动将失败的消息放入缓存池,当连接恢复时会自动重发。
Q: 如何确保消息按顺序处理?
A: WebSocket 保证消息的传输顺序,但应用层需自行处理消息的处理顺序。
