feat: wifi配网相关逻辑+p2p测试

This commit is contained in:
范鹏 2025-04-02 10:48:24 +08:00
parent 9b47ddea95
commit ee584cc262
21 changed files with 4038 additions and 3700 deletions

View File

@ -41,8 +41,17 @@ module.exports = {
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['error', { max: 1 }], // 不允许多个空行
'prefer-const': 'off', // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const
'no-use-before-define': 'off', // 禁止在 函数/类/变量 定义之前使用它们
'no-irregular-whitespace': 'off', // 禁止不规则的空白\
'no-use-before-define': 'error', // 禁止在 函数/类/变量 定义之前使用它们
'no-irregular-whitespace': 'off', // 禁止不规则的空白
'no-undef': 'error', // 禁止使用未声明的变量
'vue/script-setup-uses-vars': 'off', // 关闭此规则因为它可能会干扰no-undef的检测
'vue/no-undef-components': 'off', // 关闭组件未定义的检查
'vue/no-undef-properties': [
'error',
{
ignore: ['getDeviceInfo', 'getBluetoothDevices', 'stopGetBluetoothDevices']
}
], // 忽略特定方法的未定义检查
'import/no-cycle': 0,
'no-nested-ternary': 0,
'import/prefer-default-export': 0,
@ -61,7 +70,6 @@ module.exports = {
'no-debugger': 0,
'no-promise-executor-return': 0,
// vue (https://eslint.vuejs.org/rules)
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用此规则仅在启用该no-unused-vars规则时有效。
'vue/v-slot-style': 'error', // 强制执行 v-slot 指令样式
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/no-v-html': 'off', // 禁止使用 v-html

12
api/sdk.js Normal file
View File

@ -0,0 +1,12 @@
import request from '../utils/request'
// sdk 模块
// 获取SDK Token
export function getSdkToken(data) {
return request({
url: '/wechat/tencentYunBind',
method: 'POST',
data
})
}

View File

@ -91,13 +91,13 @@
<style scoped lang="scss">
.name {
height: 100rpx;
width: 750rpx;
display: flex;
align-items: center;
background-color: #ffffff;
font-weight: bold;
width: 750rpx;
height: 100rpx;
font-size: 32rpx;
font-weight: bold;
background-color: #ffffff;
.name-text {
width: 168rpx;
@ -106,11 +106,11 @@
}
.picker {
margin-right: 32rpx;
text-align: right;
width: 518rpx;
height: 100rpx;
margin-right: 32rpx;
line-height: 100rpx;
text-align: right;
}
}
</style>

View File

@ -53,53 +53,52 @@
from {
transform: rotate(0);
}
to {
transform: rotate(359deg);
}
}
.spinner-box {
display: flex;
justify-content: center;
align-items: center;
background-color: transparent;
position: relative;
display: flex;
align-items: center;
justify-content: center;
background-color: transparent;
}
.circle-border {
padding: 3upx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
background: rgb(99, 184, 175);
background: linear-gradient(0deg, rgba(99, 184, 175, 0.1) 33%, rgba(99, 184, 175, 1) 100%);
animation: spin 0.8s linear 0s infinite;
position: absolute;
z-index: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 3upx;
background: rgb(99, 184, 175);
background: linear-gradient(0deg, rgba(99, 184, 175, 0.1) 33%, rgba(99, 184, 175, 1) 100%);
border-radius: 50%;
animation: spin 0.8s linear 0s infinite;
}
.circle-border-stop {
padding: 3upx;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
background: rgb(99, 184, 175);
position: absolute;
z-index: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 3upx;
background: rgb(99, 184, 175);
border-radius: 50%;
}
.circle-core {
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: #ffffff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
}
</style>

9
config/constants.js Normal file
View File

@ -0,0 +1,9 @@
/**
* 应用全局常量配置
*/
// P2P相关常量
export const P2P_PLAYER_ID = 'p2p-player'
export const P2P_PUSHER_ID = 'p2p-pusher'
// 其他常量可以在这里添加

View File

@ -38,5 +38,13 @@ const SKY = {
buildNumber
}
const GE = {
name: 'ge',
baseUrl: 'http://lock.ge.star-lock.cn/api',
webviewBaseUrl: 'http://lock.ge.star-lock.cn',
version,
buildNumber
}
// 更换环境的时候 切换导出就行
export default { DEV, PRE, XHJ, SKY }
export default { DEV, PRE, XHJ, SKY, GE }

3
exportForPlayerPlugin.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
wx
}

22
exportForXp2pPlugin.js Normal file
View File

@ -0,0 +1,22 @@
const appParams = {
appid: 123,
appOauthId: 'xxx',
appKey: 'xxx',
appSecretKey: 'xxx',
appPackage: 'ios.test.com'
}
module.exports = {
wx,
getXp2pAppParams() {
return appParams
},
getXp2pConfig() {
return {
enableCrypto: true
}
},
getPlayerPlugin() {
return requirePlugin('wechat-p2p-player')
}
}

View File

@ -4,7 +4,6 @@
"description": "",
"versionName": "1.2.0",
"versionCode": "35",
"transformPx": false,
"mp-weixin": {
"appid": "wx9829a39e65550757",
"setting": {
@ -24,6 +23,22 @@
"lazyCodeLoading": "requiredComponents",
"optimization": {
"subPackages": true
},
"plugins": {
"xp2p": {
"version": "latest",
"provider": "wx1319af22356934bf",
"export": "exportForXp2pPlugin.js"
},
"wechat-p2p-player": {
"version": "latest",
"provider": "wx9e8fbc98ceac2628",
"export": "exportForPlayerPlugin.js"
},
"wmpf-voip": {
"version": "latest",
"provider": "wxf830863afde621eb"
}
}
},
"vueVersion": "3"

6968
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,10 @@
"dependencies": {
"pinia": "^2.2.0",
"pinia-plugin-unistorage": "^0.1.2",
"qcloud-iotexplorer-appdev-plugin-wificonf-blecombo": "^3.0.118",
"qcloud-iotexplorer-appdev-plugin-wificonf-core": "^3.0.118",
"qcloud-iotexplorer-appdev-sdk": "^3.0.118",
"qcloud-iotexplorer-bluetooth-adapter": "^3.0.118",
"uview-plus": "^3.3.12"
},
"devDependencies": {
@ -19,6 +23,7 @@
"husky": "^9.1.7",
"js-md5": "^0.8.3",
"lint-staged": "^15.4.3",
"postcss-scss": "^4.0.9",
"prettier": "^3.4.2",
"sm-crypto": "^0.3.13",
"stylelint": "^16.14.1",
@ -28,8 +33,7 @@
"stylelint-config-standard": "^37.0.0",
"unocss": "^65.4.3",
"unocss-preset-weapp": "^65.4.1",
"vite-plugin-eslint": "^1.8.1",
"postcss-scss": "^4.0.9"
"vite-plugin-eslint": "^1.8.1"
},
"scripts": {
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,vue,json,css,scss}\"",

View File

@ -8,6 +8,23 @@
}
},
"subPackages": [
{
"root": "pages/p2p",
"pages": [
{
"path": "p2pPlayer",
"style": {
"navigationBarTitleText": "监控",
"mp-weixin": {
"usingComponents": {
"iot-p2p-player-with-mjpg": "plugin://xp2p/iot-p2p-player-with-mjpg",
"iot-p2p-voice": "plugin://xp2p/iot-p2p-voice"
}
}
}
}
]
},
{
"root": "pages/addDeviceForWiFi",
"pages": [
@ -574,7 +591,7 @@
],
"preloadRule": {
"pages/main/home": {
"packages": ["pages/others", "pages/addDeviceForBluetooth"]
"packages": ["pages/others", "pages/addDeviceForBluetooth", "pages/p2p"]
},
"pages/main/lockDetail": {
"packages": ["pages/lockUserManage", "pages/featureForBluetooth", "pages/settingForBluetooth"]

View File

@ -175,16 +175,16 @@
}
.device {
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
height: 100rpx;
background: #ffffff;
.device-lock {
margin-left: 24rpx;
width: 72rpx;
height: 72rpx;
margin-left: 24rpx;
}
.device-name {

View File

@ -6,12 +6,11 @@
<up-steps-item title="连接设备蓝牙" :itemStyle="{ fontSize: '48rpx' }"></up-steps-item>
<up-steps-item title="开始配网" :itemStyle="{ fontSize: '48rpx' }"></up-steps-item>
</up-steps>
<view class="mt-8 mx-8">
<view class="mt-8 mx-8 flex flex-col h-[calc(100vh-300rpx)]">
<view v-if="current === 0">
<view class="text-lg font-bold mb-4">请选择WiFi并输入密码</view>
<view class="py-2 border-b border-gray-200">
<view class="pt-2 pb-3 border-b-2 border-b-solid border-gray-200">
<picker
v-if="wifiList.length > 0"
mode="selector"
:range="wifiList"
:value="wifiIndex"
@ -20,22 +19,86 @@
>
<view class="flex items-center">
<view class="mr-4">WiFi</view>
<view>{{ wifiList[wifiIndex].SSID }}</view>
<view>{{ wifiList[wifiIndex]?.SSID ?? '加载中...' }}</view>
<view class="ml-a">
<up-icon name="arrow-right" size="24rpx"></up-icon>
</view>
</view>
</picker>
</view>
<view class="py-2 border-b border-gray-200">
<view class="py-2 border-b-2 border-b-solid border-gray-200 flex items-center">
<view>密码</view>
<view>
<up-input v-model="password" placeholder="请输入密码" type="password" />
<view class="flex-1">
<up-input
:customStyle="{
padding: '0 28rpx',
outline: 'none',
height: '80rpx',
backgroundColor: '#FFFFFF',
border: 0
}"
placeholder-class="!text-base !line-height-[80rpx]"
v-model="password"
placeholder="请输入密码"
:type="showPassword ? 'text' : 'password'"
>
<template #suffix>
<up-icon
:name="showPassword ? 'eye-fill' : 'eye-off'"
size="42rpx"
@click="togglePassword"
></up-icon>
</template>
</up-input>
</view>
</view>
</view>
<view v-if="current === 1" class="flex flex-col h-[calc(100vh-230rpx)]">
<view class="text-lg font-bold mb-2">请连接设备蓝牙</view>
<view class="text-[#999999]">已发现设备如下</view>
<scroll-view scroll-y class="flex-1 mt-4 overflow-hidden">
<view
v-for="item in deviceList"
:key="item.deviceId"
@click="connectDevice(item)"
class="bg-[#efedf1] rounded-xl py-4 px-3 mt-2 flex justify-between"
>
<view>{{ item.name }}</view>
<view class="text-[#63b8af]">连接</view>
</view>
</scroll-view>
<view class="flex justify-center items-center mt-2">
<up-loading-icon
size="70rpx"
text="搜索中"
:vertical="true"
textSize="28rpx"
></up-loading-icon>
</view>
</view>
<view v-if="current === 2">
<view class="flex justify-center mt-10">
<image
src="https://oss-lock.xhjcn.ltd/mp/cloud_server.png"
mode="aspectFill"
class="w-200rpx h-200rpx p-4"
></image>
</view>
<view
v-for="(item, index) in stepList"
:key="item"
class="flex items-center mt-4 justify-center w-full"
>
<view class="flex items-center justify-start w-400rpx">
<up-loading-icon mode="circle" v-if="step < index + 1" size="36rpx"></up-loading-icon>
<up-icon name="checkbox-mark" color="#63b8af" size="36rpx" v-else></up-icon>
<view class="ml-3">{{ item }}</view>
</view>
</view>
</view>
</view>
<view
v-if="current === 0"
class="fixed bottom-[calc(env(safe-area-inset-bottom)+32rpx)] w-686rpx mx-4 h-88rpx text-center text-white bg-[#63b8af] leading-[88rpx] rounded-44rpx font-bold"
@click="handleNext"
>下一步</view
@ -46,13 +109,46 @@
<script setup>
import { onMounted, ref } from 'vue'
import { constants as WifiConfConstants } from 'qcloud-iotexplorer-appdev-plugin-wificonf-core'
import { BlueToothAdapter } from 'qcloud-iotexplorer-bluetooth-adapter'
import {
BleComboEspDeviceAdapter,
BleComboLLSyncDeviceAdapter
} from 'qcloud-iotexplorer-appdev-plugin-wificonf-blecombo'
import { useBasicStore } from '@/stores/basic'
import { useSdkStore } from '@/stores/sdk'
const bluetoothAdapter = new BlueToothAdapter({
deviceAdapters: [BleComboEspDeviceAdapter, BleComboLLSyncDeviceAdapter]
})
const { WifiConfStepCode, WifiConfErrorMsg } = WifiConfConstants
const $basic = useBasicStore()
const $sdk = useSdkStore()
const current = ref(0)
const wifiList = ref([])
const wifiIndex = ref(0)
const wifiIndex = ref()
const password = ref('')
const step = ref(1)
const deviceList = ref([])
const showPassword = ref(false)
const stepList = ref([
'手机与设备连接成功',
'向设备发送信息成功',
'设备连接云端成功',
'初始化成功'
])
const wifiInfo = ref({
SSID: '',
password: ''
})
const deviceInfo = $basic.deviceInfo
@ -82,7 +178,7 @@
return acc
}, [])
wifiList.value = uniqueWifiList
console.log('WiFi列表', wifiList.value)
wifiIndex.value = 0
})
},
fail: err => {
@ -126,18 +222,134 @@
})
})
const togglePassword = () => {
showPassword.value = !showPassword.value
}
const changeWifi = e => {
wifiIndex.value = e.detail.value
}
const handleNext = () => {
if (current.value === 0) {
uni.offGetWifiList()
if (deviceInfo.platform === 'android') {
uni.stopWifi()
}
current.value++
function bleComboConfigure({ token, wifiInfo, familyId = 'default', roomId, deviceAdapter }) {
const onStepChange = progress => {
step.value = progress
}
const onProgress = data => {
console.info(data.code, data.detail)
switch (data.code) {
case WifiConfStepCode.PROTOCOL_START:
onStepChange(1)
break
case WifiConfStepCode.PROTOCOL_SUCCESS:
onStepChange(2)
break
case WifiConfStepCode.BUSINESS_QUERY_TOKEN_STATE_SUCCESS:
onStepChange(3)
break
case WifiConfStepCode.WIFI_CONF_SUCCESS:
onStepChange(4)
break
default:
break
}
}
const onComplete = ({ productId, deviceName }) => {
console.log('配网成功', productId, deviceName)
}
const onError = async ({ code, detail }) => {
const msg = WifiConfErrorMsg[code]
console.log('配网错误(onError)', code, msg, detail)
}
$sdk.getSdk().plugins.wifiConfBleCombo.start({
wifiConfToken: token,
targetWifiInfo: wifiInfo,
deviceAdapter,
familyId,
roomId,
onProgress,
onError,
onComplete
})
}
const connectDevice = async device => {
try {
const deviceAdapter = await bluetoothAdapter.connectDevice(device)
console.log(1111, deviceAdapter)
bleComboConfigure({
token: '1234567890',
wifiInfo: wifiInfo.value,
familyId: 'default',
roomId: 'default',
deviceAdapter
})
current.value++
} catch (err) {
console.error('连接设备出错', err)
}
}
const searchDevice = async () => {
try {
await bluetoothAdapter.startSearch({
onError: error => {
console.log('搜索设备出错', error)
bluetoothAdapter.stopSearch()
},
onSearch: devices => {
if (devices.length > 0) {
console.log('搜索到设备', devices)
deviceList.value = devices
}
},
timeout: 1.4 * 15 * 1000
})
} catch (error) {
console.log('搜索设备出错1', error)
}
}
const handleNext = () => {
current.value++
searchDevice()
if (wifiIndex.value === undefined) {
uni.showToast({
title: '请选择WiFi',
icon: 'none'
})
return
}
if (password.value === '') {
uni.showToast({
title: '请输入密码',
icon: 'none'
})
return
}
if (password.value.length < 8) {
uni.showToast({
title: '密码长度不能小于8位',
icon: 'none'
})
return
}
wifiInfo.value = {
SSID: wifiList.value[wifiIndex.value].SSID,
password: password.value
}
uni.offGetWifiList()
if (deviceInfo.platform === 'android') {
uni.stopWifi()
}
current.value++
searchDevice()
}
</script>

View File

@ -182,6 +182,7 @@
import { deleteKeyRequest } from '@/api/key'
import { deleteLockRequest } from '@/api/lock'
import { setStorage, getStorage } from '@/utils/storage'
import { useSdkStore } from '@/stores/sdk'
export default {
data() {
@ -224,7 +225,11 @@
this.deviceInfo = await this.getDeviceInfo()
const token = getStorage('token')
if (token) {
await Promise.all([this.getLockList(this.lockSearch), this.getUserInfo()]).then(res => {
await Promise.all([
this.getLockList(this.lockSearch),
this.getUserInfo(),
this.initSdk()
]).then(res => {
this.pending = false
uni.hideLoading()
const list = getStorage('lockList')
@ -272,6 +277,7 @@
'resetDevice'
]),
...mapActions(useBasicStore, ['routeJump', 'getDeviceInfo', 'getNetworkType', 'shareJump']),
...mapActions(useSdkStore, ['initSdk']),
async deleteLock(lock, groupIndex, lockIndex) {
const that = this
const netWork = await this.getNetworkType()
@ -416,6 +422,7 @@
that.getLockList(that.lockSearch)
await that.getUserInfo()
that.updateLoginStatus(true)
that.initSdk()
resolve(true)
} else {
that.updateLoginStatus(false)
@ -530,8 +537,11 @@
this.focus = false
},
async toSearchDevice() {
// this.routeJump({
// name: 'selectDeviceType'
// })
this.routeJump({
name: 'selectDeviceType'
name: 'p2pPlayer'
})
},
async toLockDetail(lock) {

View File

@ -156,7 +156,7 @@
removeStorage('userInfo')
removeStorage('lockList')
uni.reLaunch({
url: '/pages/home/home'
url: '/pages/main/home'
})
},
async changePhone(res) {
@ -273,30 +273,30 @@
<style scoped lang="scss">
.background-image {
margin-top: 32rpx;
margin-left: 20rpx;
width: 710rpx;
height: 156rpx;
margin-top: 32rpx;
margin-left: 20rpx;
border-radius: 32rpx;
}
.view {
margin-top: 32rpx;
border-radius: 32rpx;
width: 710rpx;
margin-top: 32rpx;
margin-left: 20rpx;
background: #ffffff;
border-radius: 32rpx;
}
.view-button {
padding: 0 20rpx 0 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
color: #292826;
justify-content: space-between;
padding: 0 20rpx 0 40rpx;
font-size: 32rpx;
font-weight: bold;
line-height: 80rpx;
color: #292826;
}
.icon-arrow {
@ -312,60 +312,60 @@
.switch-account {
position: absolute;
border-radius: 46rpx;
bottom: 60rpx;
width: 600rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
background: #63b8af;
color: #ffffff;
font-size: 40rpx;
font-weight: bold;
line-height: 80rpx;
color: #ffffff;
text-align: center;
background: #63b8af;
border-radius: 46rpx;
}
.env {
position: absolute;
bottom: 180rpx;
width: 600rpx;
margin-left: 75rpx;
line-height: 80rpx;
text-align: center;
margin-left: 75rpx;
.env-text {
font-size: 30rpx;
font-weight: bold;
color: #999999;
font-size: 30rpx;
}
.env-button {
background: inherit;
color: #022b7c;
font-size: 0.8rem;
color: #022b7c;
text-align: right;
text-decoration: underline;
background: inherit;
}
}
.button-login {
border-radius: 46rpx;
width: 650rpx;
height: 120rpx;
line-height: 120rpx;
text-align: center;
margin-left: 50rpx;
background: #63b8af;
color: #ffffff;
font-size: 48rpx;
font-weight: bold;
line-height: 120rpx;
color: #ffffff;
text-align: center;
background: #63b8af;
border-radius: 46rpx;
}
.tips {
margin-top: 25vh;
padding: 32rpx 0;
text-align: center;
margin-top: 25vh;
font-size: 28rpx;
color: #999999;
text-align: center;
}
</style>

92
pages/p2p/p2pPlayer.vue Normal file
View File

@ -0,0 +1,92 @@
<template>
<view>
<iot-p2p-player-with-mjpg
ref="playerRef"
:deviceInfo="deviceInfo"
:xp2pInfo="xp2pInfo"
:rotate="90"
:fill="true"
orientation="horizontal"
>
</iot-p2p-player-with-mjpg>
<iot-p2p-voice
:deviceInfo="deviceInfo"
:xp2pInfo="xp2pInfo"
class="w-5 h-5"
voiceType="Pusher"
id="voiceComponent"
:showLog="true"
@voicestatechange="handleVoiceStateChange"
@voiceerror="handleVoiceError"
>
</iot-p2p-voice>
<view class="fixed bottom-20">
<button v-if="!isVoice" @click="startVoice">开始语音</button>
<button v-else @click="stopVoice">停止语音</button>
</view>
</view>
</template>
<script setup>
import { getXp2pManager } from './xp2pManager'
import { onMounted, ref } from 'vue'
let xp2pManager = null
const playerRef = ref(null)
const deviceInfo = ref({
deviceId: 'NIHQMTTLM4/1000000000',
productId: 'NIHQMTTLM4',
deviceName: '1000000000'
})
const xp2pInfo = ref('XP2Pd2ZwIis8ld9kRmeZSH+6vQ==%2.4.49')
const isVoice = ref(false)
onMounted(async () => {
if (!xp2pManager) {
xp2pManager = getXp2pManager()
}
const servicePromise = await xp2pManager.startP2PService({
deviceInfo: deviceInfo.value,
xp2pInfo: xp2pInfo.value,
caller: 1
})
})
const handleVoiceStateChange = state => {
console.log(111111, state)
}
const handleVoiceError = error => {
console.log(1111113, error)
}0
const startVoice = () => {
console.log(1111113, playerRef.value)
// const voiceNode = res[0].node
// if (voiceNode) {
// voiceNode.startVoice({
// needRecord: false,
// customPusher: {}
// })
// }
}
const stopVoice = () => {
isVoice.value = false
const query = uni.createSelectorQuery()
query
.select('#voiceComponent')
.node()
.exec(res => {
const voiceNode = res[0].node
if (voiceNode) {
voiceNode.stopVoice()
}
})
}
</script>

29
pages/p2p/utils.js Normal file
View File

@ -0,0 +1,29 @@
export const getUserId = () => {
return 1
}
export function compareVersion(ver1, ver2) {
const v1 = ver1.split('.')
const v2 = ver2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}

118
pages/p2p/xp2pManager.js Normal file
View File

@ -0,0 +1,118 @@
import { getUserId, compareVersion } from './utils'
let xp2pManager = null
export const getXp2pManager = () => {
if (!xp2pManager) {
let xp2pPlugin = requirePlugin('xp2p')
console.log(11111, xp2pPlugin)
const iotExports = xp2pPlugin.iot
const app = getApp()
// 用户id微信用户在此小程序中的唯一标识
iotExports?.setUserId?.(getUserId() || 'demo')
// 开发版才打插件log
if (app.pluginLogger && uni.getAccountInfoSync().miniProgram.envVersion === 'develop') {
iotExports?.setPluginLogger?.(app.pluginLogger)
}
// 设置优先使用的打洞协议
if (
compareVersion(uni.getSystemInfoSync().SDKVersion, '3.4.1') >= 0 &&
xp2pPlugin.p2p.setTcpFirst
) {
const tcpFirstKey = 'tcpFirst'
const tcpFirstTime = parseInt(uni.getStorageSync(tcpFirstKey), 10)
const tcpFirst = !!(tcpFirstTime && Date.now() - tcpFirstTime < 3600000 * 24) // 24小时内有效
console.log('tcpFirst', tcpFirst)
xp2pPlugin.p2p.setTcpFirst(tcpFirst)
// 给index页用方便测试时调整tcpFirst
app.tcpFirst = tcpFirst
app.toggleTcpFirst = async () => {
const modalRes = await uni.showModal({
title: '确定切换 tcpFirst 吗?',
content: '切换后需要重新进入小程序'
})
if (!modalRes || !modalRes.confirm) {
return
}
uni.setStorageSync(tcpFirstKey, tcpFirst ? '' : Date.now())
app.restart()
}
}
// 设置是否连接对端stun
if (xp2pPlugin.p2p.setCrossStunTurn) {
const crossStunTurnKey = 'crossStunTurn'
const crossStunTurnTime = parseInt(uni.getStorageSync(crossStunTurnKey), 10)
const crossStunTurn = !!(crossStunTurnTime && Date.now() - crossStunTurnTime < 3600000 * 24) // 24小时内有效
xp2pPlugin.p2p.setCrossStunTurn(crossStunTurn)
// 给index页用方便测试时调整crossStunTurn
app.crossStunTurn = crossStunTurn
app.toggleCrossStunTurn = async () => {
const modalRes = await uni.showModal({
title: '确定切换 crossStunTurn 吗?',
content: '切换后需要重新进入小程序'
})
if (!modalRes || !modalRes.confirm) {
return
}
uni.setStorageSync(crossStunTurnKey, crossStunTurn ? '' : Date.now())
app.restart()
}
}
// 设置切换端口
if (xp2pPlugin.p2p.updateStunPort) {
const portKey = 'STUN_PORT'
const stunPort = uni.getStorageSync(portKey) || 20002
xp2pPlugin.p2p.updateStunPort(stunPort)
app.stunPort = stunPort
app.togglePort = async port => {
const modalRes = await uni.showModal({
title: '确定切换 stunPort 吗?',
content: '切换后需要重新进入小程序'
})
if (!modalRes || !modalRes.confirm) {
return
}
uni.setStorageSync(portKey, port)
app.restart()
}
}
// 设置切换配置跟随
if (xp2pPlugin.p2p.setUseDeliveryConfig) {
const useDeliveryConfigKey = 'useDeliveryConfig'
const useDeliveryConfigTime = parseInt(uni.getStorageSync(useDeliveryConfigKey), 10)
const useDeliveryConfig = !!(
useDeliveryConfigTime && Date.now() - useDeliveryConfigTime < 3600000 * 24
) // 24小时内有效
xp2pPlugin.p2p.setUseDeliveryConfig(useDeliveryConfig)
app.useDeliveryConfig = useDeliveryConfig
app.toggleUseDeliveryConfig = async () => {
const modalRes = await uni.showModal({
title: '确定切换 使用设备跟随 吗?',
content: '切换后需要重新进入小程序'
})
if (!modalRes || !modalRes.confirm) {
return
}
uni.setStorageSync(useDeliveryConfigKey, useDeliveryConfig ? '' : Date.now())
app.restart()
}
}
xp2pManager = iotExports.getXp2pManager()
app.logger?.log('xp2pManager', {
P2PPlayerVersion: xp2pManager.P2PPlayerVersion,
XP2PVersion: xp2pManager.XP2PVersion,
// uuid插件随机生成的id存储在小程序本地删除小程序后会重新生成
uuid: xp2pManager.uuid
})
}
return xp2pManager
}

View File

@ -391,6 +391,11 @@ const pages = [
name: 'distributionNetwork',
path: '/pages/addDeviceForWiFi/distributionNetwork',
tabBar: false
},
{
name: 'p2pPlayer',
path: '/pages/p2p/p2pPlayer',
tabBar: false
}
]

45
stores/sdk.js Normal file
View File

@ -0,0 +1,45 @@
import { defineStore } from 'pinia'
import { AppDevSdk } from 'qcloud-iotexplorer-appdev-sdk'
import { getSdkToken } from '@/api/sdk'
export const useSdkStore = defineStore('sdk', {
state() {
return {
sdk: null
}
},
actions: {
async getSdk() {
if (this.sdk.loginManager.isLogin) {
return this.sdk
}
await this.initSdk()
return this.sdk
},
async initSdk() {
try {
const getAccessToken = async () => {
const { code, data, message } = await getSdkToken()
if (code === 0) {
return data
}
uni.showToast({
title: message,
icon: 'none'
})
return null
}
this.sdk = await new AppDevSdk({
appKey: 'mtBfaXFtISXFYVVsd',
getAccessToken
})
this.sdk.init()
} catch (error) {
console.log(111, this.sdk)
console.log('error', error)
}
}
}
})