手把手编写儿童手机远程监控App之MQTT嘟宝绑定流程
·
概述
上节讲解开发嘟宝,Android studio如何配置github copilot,使用ai agent开发。
目前为止,嘟宝完成的基本功能设计包括
- MQTT 基础通信
- 后台驻留
- SQLite数据存储
- 二维码显示身份识别码
- 开启自启动前台服务
- 任务栏消息发送与点击
- 高德定位实时更新
- webrtc点对点通信
- mAgentWeb控件封装解决全屏与获取视频权限问题
嘟妈采用vue3编写它的核心需求已完成包含以下部分: - 完成登录注册页面
- 完成二维码扫描完成与嘟宝绑定
- 与嘟妈建立音视频通信
- 查看嘟宝桌面共享视频
项目地址在github上。
嘟宝地址
嘟妈地址
绑定流程
- 嘟妈通过相机扫描二维码,获取到嘟宝的uuid,
- 检验uuid是否合法
- 校验uuid是否已经绑定
- 若合法未绑定,通过mqtt发送绑定信令
- 嘟宝收到绑定信令,检测是否已经和嘟妈绑定,
- 若已绑定过,通过mqtt发送已经绑定的信令
- 若未绑定,弹出消息,引导用户确定绑定,建立绑定关系,发送信令给嘟宝
- 嘟妈收到嘟宝的同意绑定信令,建立绑定关系
扫描二维码
二维码工具库qr-scanner,
<template>
<div class="scanbox">
<video
ref="videoRef"
class="scanner-video"
muted
playsinline
></video>
<van-icon
name="arrow-left"
class="back-btn"
size="24"
@click="goBack"
/>
<div class="result">
{{ qrResult || '请将二维码放入镜头中' }}
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import QrScanner from 'qr-scanner'
import { validate as uuidValidate } from 'uuid'
// 定义 emits
const emit = defineEmits<{
(e: 'scan-success', data: string): void
(e: 'scan-error', error: string): void
(e: 'close'): void
}>()
// 校验是否为有效的UUID
const isValidUUID = (str: string): boolean => {
return uuidValidate(str)
}
const videoRef = ref(null)
const qrResult = ref('')
let scanner:any = null
const startScan = async () => {
if (!scanner && videoRef.value) {
scanner = new QrScanner(
videoRef.value,
result => {
qrResult.value = result.data
if (isValidUUID(result.data)) {
emit('scan-success', result.data)
}
},
{
returnDetailedScanResult: true,
highlightScanRegion: true,
highlightCodeOutline: true,
}
)
}
await scanner?.start()
}
const stopScan = () => {
scanner?.stop()
}
onMounted(() => {
startScan()
})
onUnmounted(() => {
scanner?.destroy()
})
const goBack = () => {
stopScan()
// 向父组件传递关闭事件
emit('close')
}
</script>
解析uuid
校验uuid,用的是uuid库
import { validate as uuidValidate } from 'uuid'
if (!uuidValidate(dubaoId.value)) {
showToast('请扫描或者输入正确的嘟宝ID')
return
}
使用pinna存储uuid
import { defineStore } from 'pinia'
import { reactive } from 'vue';
import { getdubaoID,setdubaoID } from '@/api/storge'
interface dubaointerface {
dubaoId: string;
dubaoName: string;
cover: string;
}
export const useDubaoStore = defineStore('dubao', () => {
let dubaoId: dubaointerface[] = reactive(JSON.parse(getdubaoID() as string)||[]);
function add(d: dubaointerface) {
for (let i = 0; i < dubaoId.length; i++) {
if (dubaoId[i]?.dubaoId === d.dubaoId) {
return false;
}
}
dubaoId.push(d)
console.log(d);
setdubaoID(JSON.stringify(dubaoId));
return true;
}
function getDuBao(id: string) {
return dubaoId.find((item) => item.dubaoId === id);
}
function remove(id: string) {
const index = dubaoId.findIndex((item) => item.dubaoId === id);
if (index !== -1) {
dubaoId.splice(index, 1);
setdubaoID(JSON.stringify(dubaoId));
return true;
}
return false;
}
function unbind(id: string) {
return remove(id);
}
function checkaddrepeat(d: dubaointerface) {
for (let i = 0; i < dubaoId.length; i++) {
if (dubaoId[i]?.dubaoId === d.dubaoId) {
return true;
}
}
return false;
}
return { dubaoId,add,getDuBao,remove,unbind,checkaddrepeat };
})
绑定页面
<template>
<div class="container">
<!-- 扫一扫头部 - 调整布局使图标和标题水平对齐 -->
<div class="scan-header">
<div class="scan-icon-wrapper">
<div @click="scan" class="icon-wrapper">
<van-icon name="scan" size="80px" color="#fff" />
</div>
</div>
<span class="scan-title">扫一扫</span>
</div>
<!-- 输入区域 - 完全按照图片设计 -->
<div class="input-wrapper">
<van-field v-model="dubaoId" placeholder="请输入或者点击上面按钮扫描" clearable class="input-field" />
<br />
<van-field v-model="dubaoName" placeholder="昵称" clearable class="input-field" />
<van-button type="primary" size="large" class="add-btn" @click="handleAdd"> 添加 </van-button>
<!-- 底部装饰 - 与图片风格保持一致 -->
<div class="footer-decoration">
<span class="footer-text">扫一扫,请输入嘟宝ID</span>
</div>
</div>
<scanner @scan-success="handleScanSuccess" @close="showscanner = !showscanner" class="scanner" v-if="showscanner" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { showToast } from 'vant'
import Scanner from '@/components/scanner .vue'
import { validate as uuidValidate } from 'uuid'
import { useDubaoStore } from '@/store/dubao'
import { useMQTTStore } from '@/store/mqtt'
const mqtt = useMQTTStore()
mqtt.$subscribe(async (mutate: any, state) => {
if (typeof mutate.events.newValue === 'boolean') {
console.log('是布尔类型')
return
}
let data = JSON.parse(state.datamsg)
let msg = JSON.parse(data.msg)
switch (msg.code) {
case 'binded':
showToast('已经绑定过了')
let d = {
dubaoId: dubaoId.value,
dubaoName: dubaoName.value,
cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
}
store.add(d)
dubaoId.value = ''
dubaoName.value = ''
break
case 'bindok':
let d1 = {
dubaoId: dubaoId.value,
dubaoName: dubaoName.value,
cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
}
store.add(d1)
dubaoId.value = ''
dubaoName.value = ''
showToast('绑定成功')
break
default:
break
}
})
let store = useDubaoStore()
// 输入框绑定值
const dubaoName = ref('')
const dubaoId = ref('')
let showscanner = ref(false)
// 添加按钮点击处理
const handleAdd = () => {
console.log(1212)
if (!uuidValidate(dubaoId.value)) {
showToast('请扫描或者输入正确的嘟宝ID')
return
}
let d = {
dubaoId: dubaoId.value,
dubaoName: dubaoName.value,
cover: 'https://img.yzcdn.cn/vant/cat.jpeg',
}
if (!store.checkaddrepeat(d)) {
showToast('该嘟宝ID已存在')
return
}
mqtt.pushmsg(dubaoId.value, 'bind', '')
// store.add(d)
// showToast('添加完成')
}
function scan() {
showscanner.value = true
}
function handleScanSuccess(uuid: string) {
dubaoId.value = uuid
showscanner.value = false
}
</script>
<style scoped>
.container {
padding-top: 100px;
}
.scan-header {
height: 30%;
text-align: center;
}
.scan-title {
font-size: 20px;
}
.input-wrapper {
font-size: 15px;
text-align: center;
padding: 50px;
}
.input-field {
border: 2px solid #1989fa;
border-radius: 4px;
}
.add-btn {
margin-top: 30px;
width: 100%;
}
.footer-decoration {
margin: 10px;
font-size: 15x;
text-align: right;
}
.icon-wrapper {
display: inline-flex;
justify-content: center;
align-items: center;
background: #1989fa;
border-radius: 50%;
padding: 10px;
}
.scanner {
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
</style>
演示实例
由于之前已经绑定过,提示设备已经绑定,删除还是完成。
更多推荐
所有评论(0)