记一次在uniapp中使用websocket

这篇具有很好参考价值的文章主要介绍了记一次在uniapp中使用websocket。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

WebSocket是一种在Web应用程序中实现双向通信的技术,它允许服务器和客户端之间实时交换数据。近期在项目中使用websocket的一个过程,以及遇到的一些问题的解决思路。

1.websocket基本逻辑

连接的建立,处理消息的发送,接收

const SOCKET_URL = 'wss://*****************************'
class mySocket {
	this.socketUrl = SOCKET_URL
	//地址
    this.socketUrl = SOCKET_URL
    //开启socket报错和关闭监听
    this.monitorSocketError()
    this.monitorSocketClose()
    init(callback) {
    const _this = this
    console.log('WebSocket初始化')
    //建立连接
    this.task = uni.connectSocket({
       url: this.socketUrl,
       method: 'GET',
       success: function(res) {
         console.log('WebSocket success', res)
         console.log(SOCKET_URL)
       },
       fail: function(err) {
         console.log('WebSocket fail', err)
       },
     })
	//连接打开
     uni.onSocketOpen(function(res) {
       console.log('WebSocket连接已打开!')
       //监听消息接收
       _this.socketReceive()
       //打开心跳
       _this.getHeartbeat()
       //执行回调
       callback && callback()
     })
   }
   socketReceive() {
    const _this = this
    uni.onSocketMessage(function(res) {
    	console.log('收到消息:', res)
    }
   }
   //监听Socket关闭
  monitorSocketClose() {
    const _this = this
    uni.onSocketClose(function(res) {
      console.log('WebSocket 已关闭!')
    })
  }
  //监听Socket错误
  monitorSocketError() {
    const _this = this
    uni.onSocketError(function(res) {
      console.log('WebSocket连接打开失败,请检查!')
    })
  }
  //心跳
  getHeartbeat() {
    const _this = this
    this.send(
      {
        message: ‘这是心跳’
      },
      (val) => {
        timer = setTimeout(() => {
          if (val) {
            _this.getHeartbeat()
          } else {
            _this.init()
          }
        }, 10000)
      }
    )
  }
}
sendFunc(data, callback) {
    uni.sendSocketMessage({
      data: data,
      success: (res) => {
      console.log('发送成功!')
      },
      fail: (res) => {
        callback && callback(false)
      },
      complete: (res) => {
        console.log(res)
      },
    })
  }
var mySocket = new mySocketF()
export default mySocket
  1. 打开报错关闭监听,报错监听。
  2. 建立连接,连接已建立时监听WebSocket接受到服务器的消息事件,并打开心跳。
    心跳的作用:心跳机制的目的是定期发送小的探测消息,以确保连接仍然有效,如果连接断开或出现问题,可以及时发现并采取措施。
  3. 消息发送的格式,和接收的格式和后端开发人员定义好。

2.使用字节流进行传输

由于后端要求,所以我这边使用arraybuffer进行通信

//字符串转arraybuffer
function stringToUint8Array(str){
  var arr = [];
  for (var i = 0, j = str.length; i < j; ++i) {
    arr.push(str.charCodeAt(i));
  }
 
  var tmpUint8Array = new Uint8Array(arr);
  return tmpUint8Array
}
//arraybuffer转字符串
function arrayBufferToString(arr) {
  if (typeof arr === 'string') {
    return arr
  }
  var dataview = new DataView(arr.data)
  var ints = new Uint8Array(arr.data.byteLength)
  for (var i = 0; i < ints.length; i++) {
    ints[i] = dataview.getUint8(i)
  }
  arr = ints
  var str = '',
    _arr = arr
  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
      v = one.match(/^1+?(?=0)/)
    if (v && one.length == 8) {
      var bytesLength = v[0].length
      var store = _arr[i].toString(2).slice(7 - bytesLength)
      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2)
      }
      str += String.fromCharCode(parseInt(store, 2))
      i += bytesLength - 1
    } else {
      str += String.fromCharCode(_arr[i])
    }
  }
  return str
}

websocket是支持发送string/arraybuffer类型的数据的,可以往消息加入两位或三位去标记消息的类型,长度等信息,可以校验消息的可靠性。

const bufHeader = new ArrayBuffer(2)
const hearder = new Uint8Array(bufHeader)
hearder[0] = 0xff & 5
hearder[1] = (data.length >> 8) & 0xff
const bufByte = new ArrayBuffer(2 + data.length)
const byte = new Uint8Array(bufByte)
byte[0] = hearder[0]
byte[1] = hearder[1]
for (let i = 0; i < data.length; i++) {
  byte[2 + i] = data[i]
 }
 this.send(byte.buffer)

3.使用protobuf处理消息

这次后端要求使用protobuf对数据进行处理,下面介绍一下protobuf

Protocol Buffers(protobuf)是一种由Google开发的二进制序列化格式,用于在不同系统之间进行有效的数据通信。使用protobuf进行通信有一些优势:

  1. 高效的序列化和反序列化: Protobuf使用二进制格式进行数据序列化,相对于基于文本的格式(如JSON和XML),它的序列化和反序列化速度更快,产生的数据包也更小。这使得它在网络通信中效率更高。
  2. 协议版本兼容性: Protobuf支持在消息结构发生变化时进行向前和向后兼容的演化。通过向消息添加或删除字段,而不影响现有字段的顺序,可以更容易地进行协议的升级。
  3. 跨语言支持: Protobuf定义了一个跨语言的接口描述语言,可以在多种编程语言中生成相应的代码。这意味着你可以使用不同的编程语言开发客户端和服务器端,并且它们可以轻松地进行通信。
  4. 更小的数据大小: 由于使用二进制编码,Protobuf产生的数据包通常比使用文本格式编码的数据包更小。这在网络传输和存储方面都有利。
  5. 可读性: 虽然Protobuf生成的二进制数据不像JSON那样易读,但Protobuf的接口描述文件是可读的,可以用来理解和维护数据结构。
  6. 性能: 由于数据包更小,序列化和反序列化速度更快,因此Protobuf通常在性能方面表现更好,特别是在大规模数据通信的场景中。
  7. 自动代码生成: Protobuf提供了一个编译器(protoc),它可以根据接口描述文件生成相应语言的代码。这简化了开发过程,减少了手动编写序列化和反序列化代码的工作量。
    总体而言,使用Protobuf进行通信的主要优势在于其高效性、兼容性、跨语言支持以及在网络通信和存储方面的性能优势。

使用protobufjs对后端给过来的proto文件进行处理

proto文件大概长这样,类似接口文档,对发送的消息字段和类型进行限制

syntax = "proto3";

option java_outer_classname="SentBodyProto";

message Send {
   string key = 1;
   int64 timestamp = 2;
   map<string,string> data_p = 3;
}

我们是不能直接使用这个文件的,需要使用到protobufjs把这些文件转换为我们能使用的js文件

npx pbjs -t static-module -w commonjs -o ./protobuf/your_proto.js ./protobuf/your_proto.proto

在项目中引入

import { Send } from '../protobuf/your_proto.js'

//数据
const data =  JSON.stringify({
   key: 110,
   timestamp:new Date().getTime(),
   dataP: {
		message: '你好'
	}
})
const message = Send.create(data)
const binaryData = Send.encode(message).finish()

const bufHeader = new ArrayBuffer(2)
const hearder = new Uint8Array(bufHeader)
hearder[0] = 0xff & 5
hearder[1] = (binaryData.length >> 8) & 0xff
const bufByte = new ArrayBuffer(2 + binaryData.length)
const byte = new Uint8Array(bufByte)
byte[0] = hearder[0]
byte[1] = hearder[1]
for (let i = 0; i < binaryData.length; i++) {
  byte[2 + i] = binaryData[i]
 }
 this.send(byte.buffer)

能把string直接转换为uint8Array格式的数据,因此不需要再进行字符串转arraybuffer的操作了

4.分片传输

使用分片传输的原因:

在发送消息的时候,出现了后端接收到的消息不完整的问题,经过多次测试,发现出现的频率随着消息长度的增加逐渐增加,经过讨论,决定采用分片传输的方式去发送消息。

分片传输的实现:

	// 随机生成4个无符号8位整数,生成数组
	function generateRandomIntegers() {
	  const integers = []
	
	  for (let i = 0; i < 4; i++) {
	    // 生成范围在 0 到 255 之间的随机整数
	    const randomInt = Math.floor(Math.random() * 256)
	    integers.push(randomInt)
	  }
	
	  return integers
	}

	const message = Send.create(data)
    const binaryData = Send.encode(message).finish()
	// 分片的顺序
    let index = 0
    // 4个无符号8位整数组成的数组,用来当作消息的id
    const result = generateRandomIntegers()
    while (binaryData.length > 255 * index) {
      index++
      // 对消息进行分隔,内容的长度为255,为什么使用255,因为无符号8位整数最大为255
      const chunk = binaryData.slice((index - 1) * 255, 255 * index)
      // 生成一个arraybuffer容器,长度前8位为头部,放置消息的信息,后255位为消息本体
      const bufByte = new ArrayBuffer(8 + 255)
      const byte = new Uint8Array(bufByte)
      const bufHeader = new ArrayBuffer(2)
      const hearder = new Uint8Array(bufHeader)
      // 消息的长度
      hearder[0] = chunk.length & 0xff
      // 固定为0
      hearder[1] = (chunk.length >> 8) & 0xff
      // 消息类型
      byte[0] = 0xff & 5
      byte[1] = hearder[0]
      byte[2] = hearder[1]
      // 第4位定义分片的顺序,从1开始,当分片为最后一片时设置为0
      if (255 * index > binaryData.length) {
        byte[3] = 0
      } else {
        byte[3] = index
      }
     // 第5-8位设置分片的id,同一消息的分片id都是一样的
      for (let i = 0; i < 4; i++) {
        byte[i + 4] = result[i]
      }
      for (let i = 0; i < chunk.length; i++) {
        byte[8 + i] = chunk[i]
      }
      // 将分片放入数组中
      messageStack.push(byte)
    }
    while (messageStack.length) {
      const byte = messageStack.shift()
      this.send(byte, callback)
    }

前8位是和后端协商过,去进行统一设置的。文章来源地址https://www.toymoban.com/news/detail-790491.html

5.解决粘包和丢包问题

使用分包之后,出现了新的问题,这些分包发送到服务端的时候部分粘到一起了,这导致了服务端不能正确读取数据。解决办法:

  1. 前端设置一个map,以消息的id+分片的顺序为key,发送的内容和时间戳为value。
  2. 服务端接收到后,当消息可读,则对前端进行回复,带上消息的id和分片的顺序,类似 ACK,messageId,Index的字符串,前端收到该消息,则把该消息从map中delete掉;
  3. 如果是丢包,且后端能正确读取消息的id+分片的顺序,则回复前端 ERROR,messageId,Index,前端收到该消息,则从map中取出value中的内容重新进行发送;
  4. 在服务端收到消息,但是内容不可读的时候,不会回复前端,则前端开启定时器,当map的size不为0时,重新将map中的所有内容取出发送,由于前面保存了时间戳,当时间超过2s时自动清除该消息(猜测为消息有问题),避免定时器长期存活,当map为空时关闭定时器。
const bufferMap = new Map()
// 轮询方法
function polling(_this) {
  console.log('我开启了轮询')
  if (pollingTimer) {
    clearInterval(pollingTimer)
  }
  pollingTimer = setInterval(() => {
    if (bufferMap.size > 0) {
      for (const byte of bufferMap) {
        let time = new Date().getTime()
        if (time - byte[1].timestamp > 2000) {
          bufferMap.delete(byte[0])
        } else {
          console.log(byte[0])
          _this.sendFunc(byte[1].byte)
        }
      }
    } else {
      clearInterval(pollingTimer)
    }
  }, 100)
}
	// 消息处理
	{
		const message = Send.create(data)
	    const binaryData = Send.encode(message).finish()
	
	    let index = 0
	    const result = generateRandomIntegers()
	    let messageId = result.join('')
	    while (binaryData.length > 255 * index) {
	      index++
	      const chunk = binaryData.slice((index - 1) * 255, 255 * index)
	      const bufByte = new ArrayBuffer(8 + 255)
	      const byte = new Uint8Array(bufByte)
	      const bufHeader = new ArrayBuffer(2)
	      const hearder = new Uint8Array(bufHeader)
	      hearder[0] = chunk.length & 0xff
	      hearder[1] = (chunk.length >> 8) & 0xff
	      byte[0] = 0xff & 5
	      byte[1] = hearder[0]
	      byte[2] = hearder[1]
	      if (255 * index > binaryData.length) {
	        byte[3] = 0
	      } else {
	        byte[3] = index
	      }
	      for (let i = 0; i < 4; i++) {
	        byte[i + 4] = result[i]
	      }
	      for (let i = 0; i < chunk.length; i++) {
	        byte[8 + i] = chunk[i]
	      }
	      messageStack.push(byte)
	    }
	
	    while (messageStack.length) {
	      const byte = messageStack.shift()
	      const bufferKey = '' + messageId + byte[3]
	      if (!bufferMap.has(bufferKey)) {
	        bufferMap.set(bufferKey, {
	          byte: byte,
	          timestamp: new Date().getTime(),
	        })
	      }
	      this.send(byte.buffer)
	    }
	}
	
send(byte, callback) {
    const _this = this
    if (pollingTimer) {
      clearInterval(pollingTimer)
    }
    polling(_this)
    uni.sendSocketMessage({
      data: byter,
      success: (res) => {
      },
      fail: (res) => {
        callback && callback(false)
      },
      complete: (res) => {
        console.log(res)
      },
    })
  }

	//Socket接收服务器发送过来的消息
  socketReceive() {
    const _this = this
    uni.onSocketMessage(function(res) {
    	const ackString = arrayBufferToString({
          data: res.data,
         })
         const ackArr = ackString.split(',')
         const bufferKey = ackArr[1] + ackArr[3]
         if (bufferMap.get(bufferKey) && ackArr[0] === 'ACK') {
           bufferMap.delete(bufferKey)
         } else if (bufferMap.get(bufferKey) && ackArr[0] === 'ERROR') {
           let bufferItem = bufferMap.get(bufferKey)
           _this.send(bufferItem.byte.buffer)
         }
    })
  }

6.完整代码

import { SOCKET_URL } from './conster.js'
// proto转换
import protobuf from 'protobufjs'
import { Send, Reply } from '../protobuf/your_proto.js'

let timer
let pollingTimer
// 分片栈
let messageStack = []
// 缓冲区
const bufferMap = new Map()

function generateRandomIntegers() {
  const integers = []

  for (let i = 0; i < 4; i++) {
    // 生成范围在 0 到 255 之间的随机整数
    const randomInt = Math.floor(Math.random() * 256)
    integers.push(randomInt)
  }

  return integers
}

function arrayBufferToString(arr) {
  if (typeof arr === 'string') {
    return arr
  }
  var dataview = new DataView(arr.data)
  var ints = new Uint8Array(arr.data.byteLength)
  for (var i = 0; i < ints.length; i++) {
    ints[i] = dataview.getUint8(i)
  }
  arr = ints
  var str = '',
    _arr = arr
  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
      v = one.match(/^1+?(?=0)/)
    if (v && one.length == 8) {
      var bytesLength = v[0].length
      var store = _arr[i].toString(2).slice(7 - bytesLength)
      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2)
      }
      str += String.fromCharCode(parseInt(store, 2))
      i += bytesLength - 1
    } else {
      str += String.fromCharCode(_arr[i])
    }
  }
  return str
}

function polling(_this) {
  console.log('我开启了轮询')
  if (pollingTimer) {
    clearInterval(pollingTimer)
  }
  pollingTimer = setInterval(() => {
    if (bufferMap.size > 0) {
      for (const byte of bufferMap) {
        let time = new Date().getTime()
        if (time - byte[1].timestamp > 2000) {
          bufferMap.delete(byte[0])
        } else {
          console.log(byte[0])
          _this.sendFunc(byte[1].byte)
        }
      }
    } else {
      clearInterval(pollingTimer)
    }
  }, 100)
}

class mySocketF {
  constructor(options) {
    //地址
    this.socketUrl = SOCKET_URL
    this.task = null
    this.monitorSocketError()
    this.monitorSocketClose()
  }
  init(callback) {
    const _this = this
    console.log('WebSocket初始化')
		this.task = uni.connectSocket({
			url: SOCKET_URL,
			method: 'GET',
			success: function(res) {
				console.log('WebSocket success', res)
			},
			fail: function(err) {
				console.log('WebSocket fail', err)
			},
		})

		uni.onSocketOpen(function(res) {
			console.log('WebSocket连接已打开!')
			if (pollingTimer) {
				clearInterval(pollingTimer)
			}
			polling(_this)
			_this.socketReceive()
			setTimeout(() => {
				_this.getHeartbeat()
			}, 10000)
			callback && callback()
		})
  }

  //Socket给服务器发送消息
  send(data, callback) {
    const _this = this
    console.log('发送消息:', JSON.stringify(data))

    const message = Send.create(data)
    const binaryData = Send.encode(message).finish()

    let index = 0
    const result = generateRandomIntegers()
    let messageId = result.join('')
    while (binaryData.length > 255 * index) {
      index++
      const chunk = binaryData.slice((index - 1) * 255, 255 * index)
      const bufByte = new ArrayBuffer(8 + 255)
      const byte = new Uint8Array(bufByte)
      const bufHeader = new ArrayBuffer(2)
      const hearder = new Uint8Array(bufHeader)
      hearder[0] = chunk.length & 0xff
      hearder[1] = (chunk.length >> 8) & 0xff
      byte[0] = 0xff & 5
      byte[1] = hearder[0]
      byte[2] = hearder[1]
      if (255 * index > binaryData.length) {
        byte[3] = 0
      } else {
        byte[3] = index
      }
      for (let i = 0; i < 4; i++) {
        byte[i + 4] = result[i]
      }
      for (let i = 0; i < chunk.length; i++) {
        byte[8 + i] = chunk[i]
      }
      messageStack.push(byte)
    }

    while (messageStack.length) {
      const byte = messageStack.shift()
      const bufferKey = '' + messageId + byte[3]
      if (!bufferMap.has(bufferKey)) {
        bufferMap.set(bufferKey, {
          byte: byte,
          timestamp: new Date().getTime(),
        })
      }
      _this.sendFunc(byte, callback)
    }
  }

  sendFunc(byte, callback) {
    const _this = this
    if (pollingTimer) {
      clearInterval(pollingTimer)
    }
    polling(_this)
    uni.sendSocketMessage({
      data: byte.buffer,
      success: (res) => {
      },
      fail: (res) => {
        callback && callback(false)
        if (pollingTimer) {
          clearInterval(pollingTimer)
        }
      },
      complete: (res) => {
        console.log(res)
      },
    })
  }

  //Socket接收服务器发送过来的消息
  socketReceive() {
    const _this = this
    uni.onSocketMessage(function(res) {
			const ackString = arrayBufferToString({
				data: res.data,
			})
			const ackArr = ackString.split(',')
			const bufferKey = ackArr[1] + ackArr[3]
			if (bufferMap.get(bufferKey) && ackArr[0] === 'ACK') {
				bufferMap.delete(bufferKey)
			} else if (bufferMap.get(bufferKey) && ackArr[0] === 'ERROR') {
				let bufferItem = bufferMap.get(bufferKey)
				_this.sendFunc(bufferItem.byte)
			}
    })
  }
  //关闭Socket
  closeSocket() {
    const _this = this
    let code = 4000
    uni.closeSocket({
      code: code,
      success(res) {
        console.log('WebSocket关闭成功!', res)
        clearTimeout(timer)
        if (pollingTimer) {
          clearInterval(pollingTimer)
        }
      },
      fail: function(res) {
        console.log('WebSocket关闭失败!', res)
        clearTimeout(timer)
        if (pollingTimer) {
          clearInterval(pollingTimer)
        }
      },
    })
  }
  //监听Socket关闭
  monitorSocketClose() {
    const _this = this
    uni.onSocketClose(function(res) {
      clearTimeout(timer)
      if (pollingTimer) {
        clearInterval(pollingTimer)
      }
      console.log('WebSocket 已关闭!')
    })
  }
  //监听Socket错误
  monitorSocketError() {
    const _this = this
    uni.onSocketError(function(res) {
      console.log('WebSocket连接打开失败,请检查!')
    })
  }
  //心跳
  getHeartbeat() {
    const _this = this
    this.send(
      {
      },
      (val) => {
        timer = setTimeout(() => {
          if (val) {
            _this.getHeartbeat()
          } else {
            _this.closeSocket()
            _this.init()
          }
        }, 10000)
      }
    )
  }
}
var mySocket = new mySocketF()
export default mySocket

到了这里,关于记一次在uniapp中使用websocket的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Uni-App】uniapp使用uview实现弹出键盘输入密码/验证码功能

    组件使用的是uview组件,Keyboard 键盘和MessageInput 验证码输入两个组件配合使用。 通过mode参数定义键盘的类型,v-model绑定一个值为布尔值的变量,我绑定的是showKeyboard变量,控制键盘的弹出与收起; mode = number (默认值)为数字键盘,此时顶部工具条中间的提示文字为\\\"数字键盘

    2023年04月16日
    浏览(66)
  • 记一次在OrangePiZero2(香橙派zero 2)上部署Redroid(云手机)的过程

    这次换一种写作风格,尝试一下轻松的行文方式。 很久以前看见有群友讨论关于docker部署Redroid,拿来挂机玩游戏一类的。当时听了感觉很有意思,后面粗浅地在zero2上部署了一下,容器虽然是跑起来了,但是scrcpy连接总是黑屏,后来我试着帮助一个群友部署,也部署失败了。

    2023年04月18日
    浏览(54)
  • uni-app + SpringBoot +stomp 支持websocket 打包app

    websocket 协议是在http 协议的基础上的升级,通过一次http 请求建立长连接,转而变为TCP 的全双工通信;而http 协议是一问一答的请求方式方式。 websocket-uni.js

    2024年02月11日
    浏览(49)
  • uni-app 封装 websocket 并且监听心跳机制

    新建 socket.js , 将以下代码复制进去 ,向外暴露。 在入口文件中 将 socketIO 挂载在 Vue 原型上 , 也可以按需引入置顶页面 。 在需要用到webSocket的页面中使用如下方法(可根据自身业务需求进行整改) 离开页面,记得断开连接。

    2024年02月11日
    浏览(44)
  • miniprogram-to-uniapp使用指南(各种小程序项目转换为uni-app项目)

    小程序分类:uni-app qq小程序 支付宝小程序 百度小程序 钉钉小程序 微信小程序 小程序转成uni_app 小程序转为uni_app 小程序转uni_app 小程序转换 工具现在支持npm全局库、HBuilderX插件两种方式使用,任君选择,HBuilderX插件地址:https://ext.dcloud.net.cn/plugin?id=2656 【miniprogram-to-uniapp】

    2024年02月08日
    浏览(55)
  • 『UniApp』uni-app-打包成App

    大家好,我是 BNTang, 在上一节文章中,我给大家详细的介绍了如何将我开发好的项目打包为微信小程序并且发布到微信小程序商店 趁热打铁,在来一篇文章,给大家详细的介绍如何将项目打包成APP。 打包 App 也是一样的,首先需要配置关于 App 应用的基础信息,打开 manifest

    2024年02月04日
    浏览(99)
  • 【UniApp】-uni-app-网络请求

    经过上个章节的介绍,大家可以了解到 uni-app-pinia存储数据的基本使用方法 那本章节来给大家介绍一下 uni-app-网络请求 的基本使用方法 首先我们打开官方文档,我先带着大家看一下官方文档的介绍:https://uniapp.dcloud.net.cn/api/request/request.html 从官方文档中我们可以看到,可以

    2024年02月04日
    浏览(50)
  • 【UniApp】-uni-app-打包成网页

    经过上一篇文章的介绍,已经将这个计算器的计算功能实现了,接下来就是我们项目当中的一个发包上线阶段,我模拟一下,目的就是为了给大家介绍一下,uni-app是如何打包成网页的。 除了可以打包成网页,uni-app还可以打包成小程序、App、H5、快应用等等,后面在单独开文

    2024年02月04日
    浏览(68)
  • Uniapp uni-app学习与快速上手

    个人开源uni-app开源项目地址:准备中 在线展示项目地址:准备中 什么是uni-app uni,读 you ni ,是统一的意思。 Dcloud即数字天堂(北京)网络技术有限公司是W3C成员及HTML5中国产业联盟发起单位,致力于推进HTML5发展构建,HTML5生态。 2012年,DCloud开始研发小程序技术,优化webvie

    2024年02月09日
    浏览(58)
  • uni-app使用plus本地推送通知栏信息,不使用第三方个推实现消息在线统一推送、消息通知(MQTT、WebSocket、setInterval定时器)

    plus.push.createMessage() 因项目一直是运行在内网,所以不支持使用uni-push等运行在公网的第三方个推渠道。 那就只能使用 plus.push.createMessage() ,示例代码如下: 参数解释: content : ( String 类型) 必选,消息显示的内容,在系统通知中心中显示的文本内容。 payload : ( String 类型 ) 可

    2024年02月15日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包