HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

记录:上架小米应用市场,APP以隐私政策弹窗的形式向用户明示收集使用规则,但未见清晰明示APP收集软件列表被驳回,上架华为应用市场,申请权限未弹框告知目的被驳回问题

隐私政策 华为应用市场 小米应用商店 应用上架

(一)上架小米应用市场被驳回,原因

场景3:APP以隐私政策弹窗的形式向用户明示收集使用规则,但未见清晰明示APP收集软件列表、设备MAC地址等的目的方式范围,用户同意隐私政策后,存在收集软件列表、设备MAC地址的行为。

检测结果: 存在问题

改进建议: APP收集使用个人信息的过程需与其所声明的隐私政策等收集使用规则保持一致。实际收集的个人信息类型、申请打开可收集使用个人信息的权限等与隐
私政策等收集使用规则中相关内容一致,不超出隐私政策等收集使用规则所述范围。

风险信息: APP以隐私政策弹窗的形式向用户明示收集使用规则,但未见清晰明示APP收集读取特定类型传感器列表等的目的方式范围,用户同意隐私政策后,存在收
集读取特定类型传感器列表的行为。

举证信息:
[测试动作] 启动史宾格隐私合规检测
[测试动作] 同意隐私政策
读取特定类型传感器列表

问题一:隐私政策弹窗内未清晰明示APP收集软件列表

解决方式:列举申请权限和目的,类似这样,一一列举

问题二:存在收集读取特定类型传感器列表的行为

原因:使用webview组件,webview组件会在用户进入隐私主页时调用矢量传感器

解决方法:在隐私政策正文内补充获取传感器列表的描述,传感器列表,特定传感器,矢量传感器都可以,只需要您补充关于传感器的描述即可

最后终于上架成功了!!!

(二)上架华为应用市场被驳回,原因

APP在申请敏感权限时,应同步说明权限申请的使用目的,包括但不限于申请权限的名称、服务的具体功能、用途;告知方式不限于弹窗、蒙层、浮窗、或者自定义操作系统权限弹框等,且权限申请使用目的说明不应自动消失。请排查应用内所有权限申请行为,确保均符合要求。

请参考《审核指南》第7.21相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-07#h3-1683701612940-2

解决方式

1、使用监听权限申请API自己处理,官方文档:https://uniapp.dcloud.net.cn/api/system/create-request-permission-listener.html#createrequestpermissionlistener

2、使用官方插件uni-registerRequestPermissionTips:支持android平台全局监听权限的申请。当申请权限时,会在页面顶部显示申请权限的目的。主要解决上架华为应用市场审核要求:APP在调用终端权限时,应同步告知用户申请该权限的目的。

插件地址:https://ext.dcloud.net.cn/plugin?name=uni-registerRequestPermissionTips

3、参考文章:https://ask.dcloud.net.cn/article/40875

继续阅读 »

(一)上架小米应用市场被驳回,原因

场景3:APP以隐私政策弹窗的形式向用户明示收集使用规则,但未见清晰明示APP收集软件列表、设备MAC地址等的目的方式范围,用户同意隐私政策后,存在收集软件列表、设备MAC地址的行为。

检测结果: 存在问题

改进建议: APP收集使用个人信息的过程需与其所声明的隐私政策等收集使用规则保持一致。实际收集的个人信息类型、申请打开可收集使用个人信息的权限等与隐
私政策等收集使用规则中相关内容一致,不超出隐私政策等收集使用规则所述范围。

风险信息: APP以隐私政策弹窗的形式向用户明示收集使用规则,但未见清晰明示APP收集读取特定类型传感器列表等的目的方式范围,用户同意隐私政策后,存在收
集读取特定类型传感器列表的行为。

举证信息:
[测试动作] 启动史宾格隐私合规检测
[测试动作] 同意隐私政策
读取特定类型传感器列表

问题一:隐私政策弹窗内未清晰明示APP收集软件列表

解决方式:列举申请权限和目的,类似这样,一一列举

问题二:存在收集读取特定类型传感器列表的行为

原因:使用webview组件,webview组件会在用户进入隐私主页时调用矢量传感器

解决方法:在隐私政策正文内补充获取传感器列表的描述,传感器列表,特定传感器,矢量传感器都可以,只需要您补充关于传感器的描述即可

最后终于上架成功了!!!

(二)上架华为应用市场被驳回,原因

APP在申请敏感权限时,应同步说明权限申请的使用目的,包括但不限于申请权限的名称、服务的具体功能、用途;告知方式不限于弹窗、蒙层、浮窗、或者自定义操作系统权限弹框等,且权限申请使用目的说明不应自动消失。请排查应用内所有权限申请行为,确保均符合要求。

请参考《审核指南》第7.21相关审核要求:https://developer.huawei.com/consumer/cn/doc/app/50104-07#h3-1683701612940-2

解决方式

1、使用监听权限申请API自己处理,官方文档:https://uniapp.dcloud.net.cn/api/system/create-request-permission-listener.html#createrequestpermissionlistener

2、使用官方插件uni-registerRequestPermissionTips:支持android平台全局监听权限的申请。当申请权限时,会在页面顶部显示申请权限的目的。主要解决上架华为应用市场审核要求:APP在调用终端权限时,应同步告知用户申请该权限的目的。

插件地址:https://ext.dcloud.net.cn/plugin?name=uni-registerRequestPermissionTips

3、参考文章:https://ask.dcloud.net.cn/article/40875

收起阅读 »

星河璀璨,uni-app 亮相华为 HDC2024 开发者大会

鸿蒙 uni-app-x uni-app

2024年6月21日-23日,第六届华为开发者大会(HDC.Together 2024)在东莞松山湖盛大举办,本次盛会重磅发布了万众关注的HarmonyOS NEXT。

作为鸿蒙生态的重要合作伙伴和深度参与者,DCloud CTO 崔红保受邀出席本次大会,并在鸿蒙生态伙伴SDK论坛中发表《uni-app助力开发者快速构建高性能鸿蒙原生应用》的技术演讲,现场反响热烈。

崔红保先从开源指标、插件生态等维度介绍了uni-app的发展现状,以uni-app的功能框架图为例,介绍了uni-app如何在跨平台的过程中,不牺牲平台特色,优雅的调用平台专有能力,真正做到海纳百川、各取所长。

接着,介绍了uni-app的两套鸿蒙化适配方案。

方案一,是对存量uni-app项目的开发者非常友好的webview方案,这套架构是业内主流的Hybrid App架构,即逻辑层、视图层分离架构。老版uni-app在App平台使用的是这套架构,微信等各家小程序使用的也是这套架构。使用本方案,可以帮助开发者快速将之前基于uni-app开发的App、小程序、H5等,快速发布成鸿蒙App,快速入驻鸿蒙生态,抢先接收鸿蒙的流量红利。

方案二,是能获取更高性能、更佳体验的纯原生方案,也就是uni-app x。

每个App跨平台框架诞生时,都曾梦想颠覆原生,但从未成功,原因何在?

uni-app团队有十多年的跨平台框架开发经验,经过漫长的测试和思辨,我们发现关键在于运行时。若想媲美原生,运行时只能且必须也是原生。抛开渲染引擎不谈,业内的rn/weex等框架引入的V8/JS Core等运行环境,导致了逻辑层、视图层在两个进程中的通讯阻塞问题,相比原生开发的逻辑、视图均在一个原生进程中,业内目前的跨平台框架,天生有难以逾越的性能缺陷。

想清楚了这个关键点,跨平台框架就有了新的思路,那就是uni-app x目前的方案:开发态基于Web技术栈进行,但运行时需转化为各平台原生语言。

具体来讲,在web平台和小程序平台,我们将uni-app x编译为JS,这和目前的uni-app基本是一致的。但到了App平台,我们会将JS和Vue代码,编译为对应平台的原生语言。比如iOS平台,我们会将TS编译为swift,在Android平台,我们会将TS编译为Kotlin,到了鸿蒙平台,我们会将TS和Vue编译为arkTS和arkUI。

以uni-app x的鸿蒙化为例,进一步解释:

  1. 开发者依然基于 TS+Vue 的 Web 技术栈来编写代码,编码完毕后,uni-app x 编译器通过 swc 将 TS 和 Vue 代码编译成 arkTS/arkUI;

  2. 编译到鸿蒙开发者工具中的项目,代码已经变成了arkTS/arkUI,那使用的就是arkUI原生渲染,相比webview的渲染,性能更高。同时业务代码转换成arkTS,逻辑和渲染都使用鸿蒙原生,就实现了纯血的鸿蒙App。

  3. 最后,因为开发者在开发态使用的是Vue,用到大量数据响应的机制,所以在运行时,需要实现 arkTS 版的 Vue runtime,从而让开发者的业务数据变化能触发 arkUI 的更新。

使用 uni-app 开发鸿蒙应用,和之前开发各家小程序体验接近。主要编码工作在 HBuilderX 中完成,HBuilderX 支持鸿蒙OS的各种语法提示;编码完成后,将项目运行到鸿蒙开发者工具DevEco Studio,通过 DevEco 完成模拟器测试及hap安装包制作。

鸿蒙时代即将来临,开发鸿蒙的最佳实践是什么?uni-app值得推荐!原因有四,如下图。

面向未来,uni-app团队会持续对鸿蒙开发进行优化,重点会在性能体验、生态支持、开发体验、元服务等维度进行迭代升级。

通过HDC2024华为开发者大会,我们看到华为这次不再是画大饼,鸿蒙真的来了!

uni-app 的鸿蒙版目前处于邀请试用状态,部分开发者的App鸿蒙化适配已接近尾声。下图是基于 uni-app 开发的华为莫塞尔商城的鸿蒙化运行截图,运行体验非常流畅。

支持鸿蒙平台的uni-app Alpha版本,将于7月初面向所有开发者发布,敬请期待。

星河璀璨,基于uni-app加入鸿蒙正当时!

继续阅读 »

2024年6月21日-23日,第六届华为开发者大会(HDC.Together 2024)在东莞松山湖盛大举办,本次盛会重磅发布了万众关注的HarmonyOS NEXT。

作为鸿蒙生态的重要合作伙伴和深度参与者,DCloud CTO 崔红保受邀出席本次大会,并在鸿蒙生态伙伴SDK论坛中发表《uni-app助力开发者快速构建高性能鸿蒙原生应用》的技术演讲,现场反响热烈。

崔红保先从开源指标、插件生态等维度介绍了uni-app的发展现状,以uni-app的功能框架图为例,介绍了uni-app如何在跨平台的过程中,不牺牲平台特色,优雅的调用平台专有能力,真正做到海纳百川、各取所长。

接着,介绍了uni-app的两套鸿蒙化适配方案。

方案一,是对存量uni-app项目的开发者非常友好的webview方案,这套架构是业内主流的Hybrid App架构,即逻辑层、视图层分离架构。老版uni-app在App平台使用的是这套架构,微信等各家小程序使用的也是这套架构。使用本方案,可以帮助开发者快速将之前基于uni-app开发的App、小程序、H5等,快速发布成鸿蒙App,快速入驻鸿蒙生态,抢先接收鸿蒙的流量红利。

方案二,是能获取更高性能、更佳体验的纯原生方案,也就是uni-app x。

每个App跨平台框架诞生时,都曾梦想颠覆原生,但从未成功,原因何在?

uni-app团队有十多年的跨平台框架开发经验,经过漫长的测试和思辨,我们发现关键在于运行时。若想媲美原生,运行时只能且必须也是原生。抛开渲染引擎不谈,业内的rn/weex等框架引入的V8/JS Core等运行环境,导致了逻辑层、视图层在两个进程中的通讯阻塞问题,相比原生开发的逻辑、视图均在一个原生进程中,业内目前的跨平台框架,天生有难以逾越的性能缺陷。

想清楚了这个关键点,跨平台框架就有了新的思路,那就是uni-app x目前的方案:开发态基于Web技术栈进行,但运行时需转化为各平台原生语言。

具体来讲,在web平台和小程序平台,我们将uni-app x编译为JS,这和目前的uni-app基本是一致的。但到了App平台,我们会将JS和Vue代码,编译为对应平台的原生语言。比如iOS平台,我们会将TS编译为swift,在Android平台,我们会将TS编译为Kotlin,到了鸿蒙平台,我们会将TS和Vue编译为arkTS和arkUI。

以uni-app x的鸿蒙化为例,进一步解释:

  1. 开发者依然基于 TS+Vue 的 Web 技术栈来编写代码,编码完毕后,uni-app x 编译器通过 swc 将 TS 和 Vue 代码编译成 arkTS/arkUI;

  2. 编译到鸿蒙开发者工具中的项目,代码已经变成了arkTS/arkUI,那使用的就是arkUI原生渲染,相比webview的渲染,性能更高。同时业务代码转换成arkTS,逻辑和渲染都使用鸿蒙原生,就实现了纯血的鸿蒙App。

  3. 最后,因为开发者在开发态使用的是Vue,用到大量数据响应的机制,所以在运行时,需要实现 arkTS 版的 Vue runtime,从而让开发者的业务数据变化能触发 arkUI 的更新。

使用 uni-app 开发鸿蒙应用,和之前开发各家小程序体验接近。主要编码工作在 HBuilderX 中完成,HBuilderX 支持鸿蒙OS的各种语法提示;编码完成后,将项目运行到鸿蒙开发者工具DevEco Studio,通过 DevEco 完成模拟器测试及hap安装包制作。

鸿蒙时代即将来临,开发鸿蒙的最佳实践是什么?uni-app值得推荐!原因有四,如下图。

面向未来,uni-app团队会持续对鸿蒙开发进行优化,重点会在性能体验、生态支持、开发体验、元服务等维度进行迭代升级。

通过HDC2024华为开发者大会,我们看到华为这次不再是画大饼,鸿蒙真的来了!

uni-app 的鸿蒙版目前处于邀请试用状态,部分开发者的App鸿蒙化适配已接近尾声。下图是基于 uni-app 开发的华为莫塞尔商城的鸿蒙化运行截图,运行体验非常流畅。

支持鸿蒙平台的uni-app Alpha版本,将于7月初面向所有开发者发布,敬请期待。

星河璀璨,基于uni-app加入鸿蒙正当时!

收起阅读 »

没有mac?在Windows上传ipa 使用XUploader

ipa Appstore上传

使用 XUploader 在Windows(实体机或云主机中)上传 ipa 包到App Store Connect开发者后台

!

1.下载工具XUploader

前往 www.xbeautybay.com 下载windows版

下载Windows版本
2.解压并运行exe

解压下载的压缩包,释放出exe文件并运行

注意:点击运行时系统会提示风险,略过,点击仍然运行(英文系统点击Run any way)

点击更多信息

点击仍然运行

3.填写必要信息

填写开发者账号、专用密码、授权码

选择需要上传的ipa文件(注意文件名中不能包含特殊字符或空格,同时不能上传后台已经上传过的build,每次打包build要 1,否则App Store Connect会验证不通过)

4.点击开始上传按钮

等待日志输出窗口输出上传成功即可

5.登录App Store Connect开发者后台

在testflight查看ipa处理情况,如果处于处理中则等待处理完成即可在提交界面选取build,如果消失了请检查开发者账号绑定的邮件,会有相关提示说明,按说明修复重新打包再次上传即可。

处理成功,可在提交界面选取该build

继续阅读 »

使用 XUploader 在Windows(实体机或云主机中)上传 ipa 包到App Store Connect开发者后台

!

1.下载工具XUploader

前往 www.xbeautybay.com 下载windows版

下载Windows版本
2.解压并运行exe

解压下载的压缩包,释放出exe文件并运行

注意:点击运行时系统会提示风险,略过,点击仍然运行(英文系统点击Run any way)

点击更多信息

点击仍然运行

3.填写必要信息

填写开发者账号、专用密码、授权码

选择需要上传的ipa文件(注意文件名中不能包含特殊字符或空格,同时不能上传后台已经上传过的build,每次打包build要 1,否则App Store Connect会验证不通过)

4.点击开始上传按钮

等待日志输出窗口输出上传成功即可

5.登录App Store Connect开发者后台

在testflight查看ipa处理情况,如果处于处理中则等待处理完成即可在提交界面选取build,如果消失了请检查开发者账号绑定的邮件,会有相关提示说明,按说明修复重新打包再次上传即可。

处理成功,可在提交界面选取该build

收起阅读 »

vue3+vite5网页聊天模板|vite5.x+element-plus仿微信

vite5-webchat使用最新前端技术vite5+vue3+vue-router+pinia+sass+element-plus搭建网页端聊天系统。实现了聊天、通讯录、朋友圈、短视频、我的等功能模块。支持收缩侧边栏、背景壁纸换肤、锁屏、最大化等功能。

vue3-vitechat仿微信网页版聊天系统实例

img

img

vite-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发。

img

技术栈

  • 开发工具:Vscode
  • 技术框架:Vite5.2+Vue3.4+vue-router4.3+Pinia2
  • UI组件库:element-plus^2.7.5 (饿了么网页端vue3组件库)
  • 状态管理:pinia^2.1.7
  • 地图插件:@amap/amap-jsapi-loader(高德地图组件)
  • 视频滑动:swiper^11.1.4
  • 图文编辑器:wangeditor^4.7.15(笔记/朋友圈文本编辑器)
  • 样式编译:sass^1.77.4
  • 构建工具:vite^5.2.0

img

img

前段时间有分享一篇flutter3.x桌面端仿微信EXE聊天,感兴趣的可以去看看。
https://segmentfault.com/a/1190000044675519

img

项目结构

img

vite-chat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106226011

img

import { createApp } from 'vue'  
import './style.scss'  
import App from './App.vue'  

// 引入组件库  
import ElementPlus from 'element-plus'  
import 'element-plus/dist/index.css'  
import VEPlus from 've-plus'  
import 've-plus/dist/ve-plus.css'  

// 引入路由/状态管理  
import Router from './router'  
import Pinia from './pinia'  

const app = createApp(App)  

app  
.use(ElementPlus)  
.use(VEPlus)  
.use(Router)  
.use(Pinia)  
.mount('#app')

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

项目布局模板

img

<template>  
  <div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">  
    <div class="vu__layout">  
      <div class="vu__layout-body">  
        <!-- 菜单栏 -->  
        <slot v-if="!route?.meta?.hideMenuBar" name="menubar">  
          <MenuBar />  
        </slot>  

        <!-- 侧边栏 -->  
        <div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar" :class="{'hidden': appstate.config.collapsed}">  
          <aside class="vu__layout-sidebar__body flexbox flex-col">  
            <slot name="sidebar">  
              <SideBar />  
            </slot>  

            <!-- 折叠按钮 -->  
            <Collapse />  
          </aside>  
        </div>  

        <!-- 主内容区 -->  
        <div class="vu__layout-main flex1 flexbox flex-col">  
          <Winbtn v-if="!route?.meta?.hideWinBar" />  
          <router-view v-slot="{ Component, route }">  
            <keep-alive>  
              <component :is="Component" :key="route.path" />  
            </keep-alive>  
          </router-view>  
        </div>  
      </div>  
    </div>  
  </div>  
</template>

vue3-chat短视频模块

img

img

<!-- 短视频模块 -->  
<div class="vu__video-container">  
    <!-- tabs操作栏 -->  
    <div class="vu__video-tabswrap flexbox">  
        <el-tabs v-model="activeName" class="vu__video-tabs">  
            <el-tab-pane label="关注" name="attention" />  
            <el-tab-pane label="推荐" name="recommend" />  
        </el-tabs>  
    </div>  
    <swiper-container  
        class="vu__swiper"  
        direction="vertical"  
        :speed="150"  
        :grabCursor="true"  
        :mousewheel="{invert: true}"  
        @swiperslidechange="onSlideChange"  
    >  
        <swiper-slide v-for="(item, index) in videoList" :key="index">  
            <!-- 视频层 -->  
            <video  
                class="vu__player"  
                :id="'' + index"  
                :src="item.src"  
                :poster="item.poster"  
                loop  
                preload="auto"  
                :autoplay="index == currentVideo"  
                webkit-playsinline="true"   
                x5-video-player-type="h5-page"  
                x5-video-player-fullscreen="true"  
                playsinline  
                @click="handleVideoClicked"  
            >  
            </video>  
            <div v-if="!isPlaying" class="vu__player-btn" @click="handleVideoClicked"></div>  

            <!-- 右侧操作栏 -->  
            <div class="vu__video-toolbar">  
                ...  
            </div>  

            <!-- 底部信息区域 -->  
            <div class="vu__video-footinfo flexbox flex-col">  
                <div class="name">@{{item.author}}</div>  
                <div class="content">{{item.desc}}</div>  
            </div>  
        </swiper-slide>  
    </swiper-container>  
    <!-- ///底部进度条 -->  
    <el-slider class="vu__video-progressbar" v-model="progressBar" @input="handleSlider" @change="handlePlay" />  
    <div v-if="isDraging" class="vu__video-duration">{{videoTime}} / {{videoDuration}}</div>  
</div>

vue3聊天功能

img

<template>  
  <!-- 顶部导航 -->  
  ...  

  <!-- 内容区 -->  
  <div class="vu__layout-main__body">  
    <Scrollbar ref="scrollRef" autohide gap="2">  
      <!-- 渲染聊天内容 -->  
      <div class="vu__chatview" @dragenter="handleDragEnter" @dragover="handleDragOver" @drop="handleDrop">  
        ...  
      </div>  
    </Scrollbar>  
  </div>  

  <!-- 底部操作栏 -->  
  <div class="vu__footview">  
    <div class="vu__toolbar flexbox">  
      ...  
    </div>  
    <div class="vu__editor">  
      <Editor ref="editorRef" v-model="editorValue" @paste="handleEditorPaste" />  
    </div>  
    <div class="vu__submit">  
      <button @click="handleSubmit">发送(S)</button>  
    </div>  
  </div>  

  ...  
</template>

综上就是vue3+vite5实战开发仿微信聊天系统一些知识分享,希望对大家有些帮助~

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000044984067
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

继续阅读 »

vite5-webchat使用最新前端技术vite5+vue3+vue-router+pinia+sass+element-plus搭建网页端聊天系统。实现了聊天、通讯录、朋友圈、短视频、我的等功能模块。支持收缩侧边栏、背景壁纸换肤、锁屏、最大化等功能。

vue3-vitechat仿微信网页版聊天系统实例

img

img

vite-wechat使用vite5.x构建工具搭建项目模板,采用vue3 setup语法开发。

img

技术栈

  • 开发工具:Vscode
  • 技术框架:Vite5.2+Vue3.4+vue-router4.3+Pinia2
  • UI组件库:element-plus^2.7.5 (饿了么网页端vue3组件库)
  • 状态管理:pinia^2.1.7
  • 地图插件:@amap/amap-jsapi-loader(高德地图组件)
  • 视频滑动:swiper^11.1.4
  • 图文编辑器:wangeditor^4.7.15(笔记/朋友圈文本编辑器)
  • 样式编译:sass^1.77.4
  • 构建工具:vite^5.2.0

img

img

前段时间有分享一篇flutter3.x桌面端仿微信EXE聊天,感兴趣的可以去看看。
https://segmentfault.com/a/1190000044675519

img

项目结构

img

vite-chat聊天已经同步到我的最新原创作品集,有需要的可以去看看。
https://gf.bilibili.com/item/detail/1106226011

img

import { createApp } from 'vue'  
import './style.scss'  
import App from './App.vue'  

// 引入组件库  
import ElementPlus from 'element-plus'  
import 'element-plus/dist/index.css'  
import VEPlus from 've-plus'  
import 've-plus/dist/ve-plus.css'  

// 引入路由/状态管理  
import Router from './router'  
import Pinia from './pinia'  

const app = createApp(App)  

app  
.use(ElementPlus)  
.use(VEPlus)  
.use(Router)  
.use(Pinia)  
.mount('#app')

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

img

项目布局模板

img

<template>  
  <div class="vu__container" :style="{'--themeSkin': appstate.config.skin}">  
    <div class="vu__layout">  
      <div class="vu__layout-body">  
        <!-- 菜单栏 -->  
        <slot v-if="!route?.meta?.hideMenuBar" name="menubar">  
          <MenuBar />  
        </slot>  

        <!-- 侧边栏 -->  
        <div v-if="route?.meta?.showSideBar" class="vu__layout-sidebar" :class="{'hidden': appstate.config.collapsed}">  
          <aside class="vu__layout-sidebar__body flexbox flex-col">  
            <slot name="sidebar">  
              <SideBar />  
            </slot>  

            <!-- 折叠按钮 -->  
            <Collapse />  
          </aside>  
        </div>  

        <!-- 主内容区 -->  
        <div class="vu__layout-main flex1 flexbox flex-col">  
          <Winbtn v-if="!route?.meta?.hideWinBar" />  
          <router-view v-slot="{ Component, route }">  
            <keep-alive>  
              <component :is="Component" :key="route.path" />  
            </keep-alive>  
          </router-view>  
        </div>  
      </div>  
    </div>  
  </div>  
</template>

vue3-chat短视频模块

img

img

<!-- 短视频模块 -->  
<div class="vu__video-container">  
    <!-- tabs操作栏 -->  
    <div class="vu__video-tabswrap flexbox">  
        <el-tabs v-model="activeName" class="vu__video-tabs">  
            <el-tab-pane label="关注" name="attention" />  
            <el-tab-pane label="推荐" name="recommend" />  
        </el-tabs>  
    </div>  
    <swiper-container  
        class="vu__swiper"  
        direction="vertical"  
        :speed="150"  
        :grabCursor="true"  
        :mousewheel="{invert: true}"  
        @swiperslidechange="onSlideChange"  
    >  
        <swiper-slide v-for="(item, index) in videoList" :key="index">  
            <!-- 视频层 -->  
            <video  
                class="vu__player"  
                :id="'' + index"  
                :src="item.src"  
                :poster="item.poster"  
                loop  
                preload="auto"  
                :autoplay="index == currentVideo"  
                webkit-playsinline="true"   
                x5-video-player-type="h5-page"  
                x5-video-player-fullscreen="true"  
                playsinline  
                @click="handleVideoClicked"  
            >  
            </video>  
            <div v-if="!isPlaying" class="vu__player-btn" @click="handleVideoClicked"></div>  

            <!-- 右侧操作栏 -->  
            <div class="vu__video-toolbar">  
                ...  
            </div>  

            <!-- 底部信息区域 -->  
            <div class="vu__video-footinfo flexbox flex-col">  
                <div class="name">@{{item.author}}</div>  
                <div class="content">{{item.desc}}</div>  
            </div>  
        </swiper-slide>  
    </swiper-container>  
    <!-- ///底部进度条 -->  
    <el-slider class="vu__video-progressbar" v-model="progressBar" @input="handleSlider" @change="handlePlay" />  
    <div v-if="isDraging" class="vu__video-duration">{{videoTime}} / {{videoDuration}}</div>  
</div>

vue3聊天功能

img

<template>  
  <!-- 顶部导航 -->  
  ...  

  <!-- 内容区 -->  
  <div class="vu__layout-main__body">  
    <Scrollbar ref="scrollRef" autohide gap="2">  
      <!-- 渲染聊天内容 -->  
      <div class="vu__chatview" @dragenter="handleDragEnter" @dragover="handleDragOver" @drop="handleDrop">  
        ...  
      </div>  
    </Scrollbar>  
  </div>  

  <!-- 底部操作栏 -->  
  <div class="vu__footview">  
    <div class="vu__toolbar flexbox">  
      ...  
    </div>  
    <div class="vu__editor">  
      <Editor ref="editorRef" v-model="editorValue" @paste="handleEditorPaste" />  
    </div>  
    <div class="vu__submit">  
      <button @click="handleSubmit">发送(S)</button>  
    </div>  
  </div>  

  ...  
</template>

综上就是vue3+vite5实战开发仿微信聊天系统一些知识分享,希望对大家有些帮助~

作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000044984067
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

收起阅读 »

寻找成品体育赛事直播的源码然后外包二开

新需求 外包接单 招聘

需要一款成品的体育赛事直播的源码。
然后根据要求进行二开即可。
没有成品的勿扰,有的带演示
有预算V:bapi919

需要一款成品的体育赛事直播的源码。
然后根据要求进行二开即可。
没有成品的勿扰,有的带演示
有预算V:bapi919

Vue H5网页唤起基于uniapp开发的app应用如果未安装则下载安装

1、App配置 scheme 标识(安卓和ios尽量配置成一样的名称)

    1.1、如果只是唤起app则可以直接打包自定义基座  
    1.2、如果需要唤起指定的app页面,如打开商品详情,则需要完成第6步再进行打包操作  

2、下载安装callapp-lib 下载命令 npm install callapp-lib -S
3、引入 callapp-lib 插件 import CallApp from "callapp-lib";
4、配置 相关参数

配置参数
const arouseAPP = () => {
const options = {
scheme: {
protocol: "", //ios schema标识
},
intent: {
//打开安卓标识
package: "com.tencent.mm", //安卓协议 com.tencent.mm(应用包名)
scheme: "",
},
appstore: '', //App Store地址
yingyongbao: '', //应用宝地址
timeout: 3000, //等待唤端的时间(单位: ms),超时则判断为唤端失败。
};
const callLib = new CallApp(options);
callLib.open({
path: "pages/index/productDetail/productDetail",//打开App指定页面(页面路径,不打开指定页面就不填)
param: {
id: productId //打开App页面携带的参数
},
fallback: function () {
console.warn("警告-------------:唤起APP失败");
//打不开具体处理

},  

});
};
5、App端被唤起后跳转逻辑需要处理一下

继续阅读 »

1、App配置 scheme 标识(安卓和ios尽量配置成一样的名称)

    1.1、如果只是唤起app则可以直接打包自定义基座  
    1.2、如果需要唤起指定的app页面,如打开商品详情,则需要完成第6步再进行打包操作  

2、下载安装callapp-lib 下载命令 npm install callapp-lib -S
3、引入 callapp-lib 插件 import CallApp from "callapp-lib";
4、配置 相关参数

配置参数
const arouseAPP = () => {
const options = {
scheme: {
protocol: "", //ios schema标识
},
intent: {
//打开安卓标识
package: "com.tencent.mm", //安卓协议 com.tencent.mm(应用包名)
scheme: "",
},
appstore: '', //App Store地址
yingyongbao: '', //应用宝地址
timeout: 3000, //等待唤端的时间(单位: ms),超时则判断为唤端失败。
};
const callLib = new CallApp(options);
callLib.open({
path: "pages/index/productDetail/productDetail",//打开App指定页面(页面路径,不打开指定页面就不填)
param: {
id: productId //打开App页面携带的参数
},
fallback: function () {
console.warn("警告-------------:唤起APP失败");
//打不开具体处理

},  

});
};
5、App端被唤起后跳转逻辑需要处理一下

收起阅读 »

uni-grid第二次进入样式问题

uni-grid组件第一次进入正常,第二次进入就挤成一排了。
解决办法

  1. 如果你不需要边框,直接在组件上加上:show-border="false"即可
  2. 如果你需要边框的情况下有两种解决办法
    第一,给uni-grid组件外层的view组件加固定宽度,很显然这种办法只能解决一个端的问题,如需多端运行,看第二种办法;
    第二,修改uni-grid组件中的uni-grid 类样式,添加width:100%;即可,这个应该是该组件的一个小bug
继续阅读 »

uni-grid组件第一次进入正常,第二次进入就挤成一排了。
解决办法

  1. 如果你不需要边框,直接在组件上加上:show-border="false"即可
  2. 如果你需要边框的情况下有两种解决办法
    第一,给uni-grid组件外层的view组件加固定宽度,很显然这种办法只能解决一个端的问题,如需多端运行,看第二种办法;
    第二,修改uni-grid组件中的uni-grid 类样式,添加width:100%;即可,这个应该是该组件的一个小bug
收起阅读 »

Android抓包配置

1、创建network_security_config.xml文件,并将其拷贝到应用资源nativeResources\android\res\xml目录下

<?xml version="1.0" encoding="utf-8"?>  
<network-security-config>  
  <base-config cleartextTrafficPermitted="true">  
    <trust-anchors>  
      <certificates src="system" />  
      <certificates src="user" />  
    </trust-anchors>  
  </base-config>  
</network-security-config>

2、创建AndroidManifest.template.xml文件

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"   
  package="你自己的包名">  

    <!-- 信任用户证书,用于非生产环境抓包 -->  
    <application android:networkSecurityConfig="@xml/network_security_config">  

    </application>  
</manifest>

3、修改vue.config.js或vite.config.js

const fs = require('fs');  
const path = require('path');  
const templateFilePath = path.join(__dirname, 'AndroidManifest.template.xml');  
const outputFilePath = path.join(__dirname, 'AndroidManifest.xml');  
const config = require('./config.js')  

// #ifdef APP  
// 非生产环境,添加网络安全配置,用于抓包  
if(config.env !== 'prod'){  
    fs.copyFileSync(templateFilePath, outputFilePath);  
}else if(fs.existsSync(outputFilePath)){  
    fs.unlinkSync(outputFilePath)  
}  
// #endif

4、下载抓包工具Reqable
下载地址:https://reqable.com/zh-CN/download

继续阅读 »

1、创建network_security_config.xml文件,并将其拷贝到应用资源nativeResources\android\res\xml目录下

<?xml version="1.0" encoding="utf-8"?>  
<network-security-config>  
  <base-config cleartextTrafficPermitted="true">  
    <trust-anchors>  
      <certificates src="system" />  
      <certificates src="user" />  
    </trust-anchors>  
  </base-config>  
</network-security-config>

2、创建AndroidManifest.template.xml文件

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"   
  package="你自己的包名">  

    <!-- 信任用户证书,用于非生产环境抓包 -->  
    <application android:networkSecurityConfig="@xml/network_security_config">  

    </application>  
</manifest>

3、修改vue.config.js或vite.config.js

const fs = require('fs');  
const path = require('path');  
const templateFilePath = path.join(__dirname, 'AndroidManifest.template.xml');  
const outputFilePath = path.join(__dirname, 'AndroidManifest.xml');  
const config = require('./config.js')  

// #ifdef APP  
// 非生产环境,添加网络安全配置,用于抓包  
if(config.env !== 'prod'){  
    fs.copyFileSync(templateFilePath, outputFilePath);  
}else if(fs.existsSync(outputFilePath)){  
    fs.unlinkSync(outputFilePath)  
}  
// #endif

4、下载抓包工具Reqable
下载地址:https://reqable.com/zh-CN/download

收起阅读 »

唤醒锁

// 在uniapp中调用原生API启用唤醒锁
function enableWakeLock() {
// 判断当前环境是否支持
if (plus.os.name.toLowerCase() === 'android') {
// 尝试获取唤醒锁
var wakeLock = plus.android.invoke('android.os.PowerManager', 'newWakeLock', plus.android.getContext().POWER_SERVICE);
if (wakeLock) {
// 获取到唤醒锁后,设置为不释放锁的标志位,即保持屏幕常亮
wakeLock.setReferenceCounted(false);
wakeLock.acquire();
console.log('Wake lock acquired');
} else {
console.log('Failed to acquire wake lock');
}
} else {
console.log('Wake lock feature is only supported on Android devices');
}
}

// 在适当的时候释放唤醒锁,比如用户离开应用时
function releaseWakeLock() {
if (wakeLock && plus.os.name.toLowerCase() === 'android') {
wakeLock.release();
console.log('Wake lock released');
}
}

// 在适当的时候调用enableWakeLock函数来启用唤醒锁

2.方法
// 判断是否为Android平台
if (plus.os.name.toLowerCase() === 'android') {
// 获取当前的Activity
var main = plus.android.runtimeMainActivity();
var Window = plus.android.importClass('android.view.Window');
var PowerManager = plus.android.importClass('android.os.PowerManager');

// 获取PowerManager服务
var pm = main.getSystemService(Window.POWER_SERVICE);
var wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, 'my_wakelock_tag');

// 启用wakelock
wl.acquire();

// 在需要关闭wakelock的时候,调用release方法
// wl.release();
}

继续阅读 »

// 在uniapp中调用原生API启用唤醒锁
function enableWakeLock() {
// 判断当前环境是否支持
if (plus.os.name.toLowerCase() === 'android') {
// 尝试获取唤醒锁
var wakeLock = plus.android.invoke('android.os.PowerManager', 'newWakeLock', plus.android.getContext().POWER_SERVICE);
if (wakeLock) {
// 获取到唤醒锁后,设置为不释放锁的标志位,即保持屏幕常亮
wakeLock.setReferenceCounted(false);
wakeLock.acquire();
console.log('Wake lock acquired');
} else {
console.log('Failed to acquire wake lock');
}
} else {
console.log('Wake lock feature is only supported on Android devices');
}
}

// 在适当的时候释放唤醒锁,比如用户离开应用时
function releaseWakeLock() {
if (wakeLock && plus.os.name.toLowerCase() === 'android') {
wakeLock.release();
console.log('Wake lock released');
}
}

// 在适当的时候调用enableWakeLock函数来启用唤醒锁

2.方法
// 判断是否为Android平台
if (plus.os.name.toLowerCase() === 'android') {
// 获取当前的Activity
var main = plus.android.runtimeMainActivity();
var Window = plus.android.importClass('android.view.Window');
var PowerManager = plus.android.importClass('android.os.PowerManager');

// 获取PowerManager服务
var pm = main.getSystemService(Window.POWER_SERVICE);
var wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, 'my_wakelock_tag');

// 启用wakelock
wl.acquire();

// 在需要关闭wakelock的时候,调用release方法
// wl.release();
}

收起阅读 »

支持文字,图片,文件。视频。语音通话,视频通话吗? 如果支持,在那几个端支持?比如H5,小程序,安卓,IOS

uni_im

支持文字,图片,文件。视频。语音通话,视频通话吗?
如果支持,在那几个端支持?比如H5,小程序,安卓,IOS

支持文字,图片,文件。视频。语音通话,视频通话吗?
如果支持,在那几个端支持?比如H5,小程序,安卓,IOS

app使用webview嵌入h5,h5和app通信或者在操作后自动返回app

Webview

第一:首先下载官方最新的uni.webview.js,下载链接在这儿找 官方文档

第二:将下载好的webview.js放在h5的static文件夹下,

第三:在h5的index.html引入,然后写如下代码

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <meta charset="UTF-8" />  
    <script>  
      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||  
        CSS.supports('top: constant(a)'))  
      document.write(  
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +  
        (coverSupport ? ', viewport-fit=cover' : '') + '" />')  
    </script>  
    <title></title>  
    <!--preload-links-->  
    <!--app-context-->  
  </head>  
  <body>  
    <div id="app"><!--app-html--></div>  
    <script type="module" src="/main.js"></script>  
    <script type="text/javascript" src="./static/webview.js"></script>  
    <script type="text/javascript" >  
        const webViewJs = uni.webView  
        console.log('webViewJs',webViewJs);  
    </script>  

  </body>  
</html>  

在vue文件使用webviewjs返回app或者和app通信,vue代码如下

<template>  
    <view class="content">  
        <image class="logo" src="/static/logo.png"></image>  
        <button type="primary" @click="back">返回app</button>  
        <button type="primary" @click="sendMsg">发消息给app</button>  
        <button type="primary" @click="toIndex">跳转到app首页</button>  
    </view>  
</template>  

<script>  
export default {  
    data() {  
        return {  
            title: 'Hello'  
        };  
    },  
    onLoad() {},  
    methods: {  
        back() {  
            webViewJs.navigateBack();  
        },  
        sendMsg(){  
            webViewJs.postMessage({  
                data: {  
                    action: 'postMessage'  
                }  
            });  
        },  
        toIndex(){  
            webViewJs.navigateTo({  
                url:'/pages/index/index'  
            })  
            // 如果是tabar,使用switchTab跳转  
            // webViewJs.switchTab({  
            //  url:'/pages/index/index'  
            // })  
        }  
    }  
};  
</script>  

<style>  
.content {  
    display: flex;  
    flex-direction: column;  
    align-items: center;  
    justify-content: center;  
}  

.logo {  
    height: 200rpx;  
    width: 200rpx;  
    margin-top: 200rpx;  
    margin-left: auto;  
    margin-right: auto;  
    margin-bottom: 50rpx;  
}  

button {  
    margin: 20rpx;  
}  
</style>

app的webview页面接收h5传过来的值,代码如下

<template>  
    <view class="content">  
        <web-view src="http://localhost:5173/" @message="onMessage"></web-view>  
    </view>  
</template>  

<script>  
export default {  
    data() {  
        return {  
        };  
    },  
    methods: {  
        onMessage(e){  
            console.log('e',e.detail.data);  
        }  
    }  
};  
</script>  

<style lang="scss" scoped>  

</style>  
继续阅读 »

第一:首先下载官方最新的uni.webview.js,下载链接在这儿找 官方文档

第二:将下载好的webview.js放在h5的static文件夹下,

第三:在h5的index.html引入,然后写如下代码

<!DOCTYPE html>  
<html lang="en">  
  <head>  
    <meta charset="UTF-8" />  
    <script>  
      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||  
        CSS.supports('top: constant(a)'))  
      document.write(  
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +  
        (coverSupport ? ', viewport-fit=cover' : '') + '" />')  
    </script>  
    <title></title>  
    <!--preload-links-->  
    <!--app-context-->  
  </head>  
  <body>  
    <div id="app"><!--app-html--></div>  
    <script type="module" src="/main.js"></script>  
    <script type="text/javascript" src="./static/webview.js"></script>  
    <script type="text/javascript" >  
        const webViewJs = uni.webView  
        console.log('webViewJs',webViewJs);  
    </script>  

  </body>  
</html>  

在vue文件使用webviewjs返回app或者和app通信,vue代码如下

<template>  
    <view class="content">  
        <image class="logo" src="/static/logo.png"></image>  
        <button type="primary" @click="back">返回app</button>  
        <button type="primary" @click="sendMsg">发消息给app</button>  
        <button type="primary" @click="toIndex">跳转到app首页</button>  
    </view>  
</template>  

<script>  
export default {  
    data() {  
        return {  
            title: 'Hello'  
        };  
    },  
    onLoad() {},  
    methods: {  
        back() {  
            webViewJs.navigateBack();  
        },  
        sendMsg(){  
            webViewJs.postMessage({  
                data: {  
                    action: 'postMessage'  
                }  
            });  
        },  
        toIndex(){  
            webViewJs.navigateTo({  
                url:'/pages/index/index'  
            })  
            // 如果是tabar,使用switchTab跳转  
            // webViewJs.switchTab({  
            //  url:'/pages/index/index'  
            // })  
        }  
    }  
};  
</script>  

<style>  
.content {  
    display: flex;  
    flex-direction: column;  
    align-items: center;  
    justify-content: center;  
}  

.logo {  
    height: 200rpx;  
    width: 200rpx;  
    margin-top: 200rpx;  
    margin-left: auto;  
    margin-right: auto;  
    margin-bottom: 50rpx;  
}  

button {  
    margin: 20rpx;  
}  
</style>

app的webview页面接收h5传过来的值,代码如下

<template>  
    <view class="content">  
        <web-view src="http://localhost:5173/" @message="onMessage"></web-view>  
    </view>  
</template>  

<script>  
export default {  
    data() {  
        return {  
        };  
    },  
    methods: {  
        onMessage(e){  
            console.log('e',e.detail.data);  
        }  
    }  
};  
</script>  

<style lang="scss" scoped>  

</style>  
收起阅读 »