当前位置: 首页 > news >正文

UNIAPP项目记录

一、通过 vue-cli 创建 uni-app 项目

  • 创建 vue3 项目

    • 创建以 javascript 开发的工程(如命令行创建失败,请直接访问 gitee 下载模板)
      npx degit dcloudio/uni-preset-vue#vite my-vue3-project
      
      复制代码
      npx degit dcloudio/uni-preset-vue#vite-alpha my-vue3-project
      
      复制代码
    • 创建以 typescript 开发的工程(如命令行创建失败,请直接访问 gitee 下载模板)
      npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project

 二、通过命令脚本打wgt文件

官网提示:目前使用npm run build:app-plus会在/dist/build/app-plus下生成app打包资源。如需制作wgt包,将app-plus中的文件压缩成zip(注意:不要包含app-plus目录),再重命名为${appid}.wgt, appidmanifest.json文件中的appid

实际项目中package.json 文件中未找到build:app-plus命令,且发现执行以下俩条命令效果相同,在项目目录下找到dist/build/app文件夹

"build:app-plus": "uni build -p app-plus"
"build:app": "uni build -p app"

制作wgt包,将dist/build/app中的文件压缩成zip(注意:不要包含app目录),再重命名为xxx.wgt

三、通过自定义命令脚本自动打wgt文件

1.在package.json中注册脚本

"scripts": { "build:wgt": "node wgtScripts.js" }

2. 安装archiver

yarn add archiver

3.在项目根目录下增加wgtScripts.js文件

注意manifest.json文件不要有注释,否则会报错
// 脚本执行命令  yarn run build:wgt
const { exec } = require("child_process");
const fs = require("fs");
const archiver = require("archiver"); // 用于压缩文件
const path = require("path");// 获取项目根目录路径
const projectRoot = path.resolve(__dirname);
// 定义要执行的命令,打包 uniapp wgt 资源
const command = "uni build -p app";// 读取 manifest.json
const getManifestJSON = () => {const manifestPath = path.resolve(__dirname, "src/manifest.json");return JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
};// 将资源文件打压缩包
const compress = (manifest) => {console.log("编译成功!!!");const outputDirectory = path.resolve(__dirname, "dist/build/app");const wgtFolderPath = path.resolve(__dirname, "dist/wgt");// 创建 wgt 文件夹if (!fs.existsSync(wgtFolderPath)) {fs.mkdirSync(wgtFolderPath);}const outputZip = path.resolve(__dirname,`dist/wgt/${manifest.versionCode}.wgt`);console.log("正在压缩中...");const output = fs.createWriteStream(outputZip);const archive = archiver("zip", { zlib: { level: 9 } });// 监听输出流关闭事件output.on("close", () => {const wgtPath = path.resolve(__dirname,`dist/wgt/${manifest.name}_${manifest.versionCode}.wgt`);console.log(`压缩成功!!!`);console.log(`${manifest.name}的wgt导出路径 ${wgtPath}`);});// 监听警告事件archive.on("warning", (err) => {err.code === "ENOENT" ? console.warn(err) : console.error(err);});// 监听错误事件archive.on("error", (err) => {console.error(err);});archive.pipe(output);archive.directory(outputDirectory, false);archive.finalize();
};const build = () => {console.log("正在编译中...");exec(command, { cwd: projectRoot }, (error) => {if (error) {console.error(`执行命令时出错: ${error}`);return;}const manifest = getManifestJSON();compress(manifest);});
};build();

4.执行yarn run build:wgt即可获得wgt文件

5.后续优化可以增加上传文件服务器功能

四、Android/IOS权限判断文件

var isIos
// #ifdef APP-PLUS  
isIos = (plus.os.name == "iOS")
// #endif  // 判断推送权限是否开启  
function judgeIosPermissionPush() {var result = false;var UIApplication = plus.ios.import("UIApplication");var app = UIApplication.sharedApplication();var enabledTypes = 0;if (app.currentUserNotificationSettings) {var settings = app.currentUserNotificationSettings();enabledTypes = settings.plusGetAttribute("types");console.log("enabledTypes1:" + enabledTypes);if (enabledTypes == 0) {console.log("推送权限没有开启");} else {result = true;console.log("已经开启推送功能!")}plus.ios.deleteObject(settings);} else {enabledTypes = app.enabledRemoteNotificationTypes();if (enabledTypes == 0) {console.log("推送权限没有开启!");} else {result = true;console.log("已经开启推送功能!")}console.log("enabledTypes2:" + enabledTypes);}plus.ios.deleteObject(app);plus.ios.deleteObject(UIApplication);return result;
}// 判断定位权限是否开启  
function judgeIosPermissionLocation() {var result = false;var cllocationManger = plus.ios.import("CLLocationManager");var status = cllocationManger.authorizationStatus();result = (status != 2)console.log("定位权限开启:" + result);// 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation  /* var enable = cllocationManger.locationServicesEnabled();  var status = cllocationManger.authorizationStatus();  console.log("enable:" + enable);  console.log("status:" + status);  if (enable && status != 2) {  result = true;  console.log("手机定位服务已开启且已授予定位权限");  } else {  console.log("手机系统的定位没有打开或未给予定位权限");  } */plus.ios.deleteObject(cllocationManger);return result;
}// 判断麦克风权限是否开启  
function judgeIosPermissionRecord() {var result = false;var avaudiosession = plus.ios.import("AVAudioSession");var avaudio = avaudiosession.sharedInstance();var permissionStatus = avaudio.recordPermission();console.log("permissionStatus:" + permissionStatus);if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {console.log("麦克风权限没有开启");} else {result = true;console.log("麦克风权限已经开启");}plus.ios.deleteObject(avaudiosession);return result;
}// 判断相机权限是否开启  
function judgeIosPermissionCamera() {var result = false;var AVCaptureDevice = plus.ios.import("AVCaptureDevice");var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');console.log("authStatus:" + authStatus);if (authStatus == 3) {result = true;console.log("相机权限已经开启");} else {console.log("相机权限没有开启");}plus.ios.deleteObject(AVCaptureDevice);return result;
}// 判断相册权限是否开启  
function judgeIosPermissionPhotoLibrary() {var result = false;var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");var authStatus = PHPhotoLibrary.authorizationStatus();console.log("authStatus:" + authStatus);if (authStatus == 3) {result = true;console.log("相册权限已经开启");} else {console.log("相册权限没有开启");}plus.ios.deleteObject(PHPhotoLibrary);return result;
}// 判断通讯录权限是否开启  
function judgeIosPermissionContact() {var result = false;var CNContactStore = plus.ios.import("CNContactStore");var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);if (cnAuthStatus == 3) {result = true;console.log("通讯录权限已经开启");} else {console.log("通讯录权限没有开启");}plus.ios.deleteObject(CNContactStore);return result;
}// 判断日历权限是否开启  
function judgeIosPermissionCalendar() {var result = false;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);if (ekAuthStatus == 3) {result = true;console.log("日历权限已经开启");} else {console.log("日历权限没有开启");}plus.ios.deleteObject(EKEventStore);return result;
}// 判断备忘录权限是否开启  
function judgeIosPermissionMemo() {var result = false;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);if (ekAuthStatus == 3) {result = true;console.log("备忘录权限已经开启");} else {console.log("备忘录权限没有开启");}plus.ios.deleteObject(EKEventStore);return result;
}// Android权限查询  
function requestAndroidPermission(permissionID) {return new Promise((resolve, reject) => {plus.android.requestPermissions(permissionID.split(","),// [permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装  function(resultObj) {var result = 0;for (var i = 0; i < resultObj.granted.length; i++) {var grantedPermission = resultObj.granted[i];console.log('已获取的权限:' + grantedPermission);result = 1}for (var i = 0; i < resultObj.deniedPresent.length; i++) {var deniedPresentPermission = resultObj.deniedPresent[i];console.log('拒绝本次申请的权限:' + deniedPresentPermission);result = 0}for (var i = 0; i < resultObj.deniedAlways.length; i++) {var deniedAlwaysPermission = resultObj.deniedAlways[i];console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);result = -1}resolve(result);// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限  // if (result != 1) {  // gotoAppPermissionSetting()  // }  },function(error) {console.log('申请权限错误:' + error.code + " = " + error.message);resolve({code: error.code,message: error.message});});});
}// 使用一个方法,根据参数判断权限  
function judgeIosPermission(permissionID) {if (permissionID == "location") {return judgeIosPermissionLocation()} else if (permissionID == "camera") {return judgeIosPermissionCamera()} else if (permissionID == "photoLibrary") {return judgeIosPermissionPhotoLibrary()} else if (permissionID == "record") {return judgeIosPermissionRecord()} else if (permissionID == "push") {return judgeIosPermissionPush()} else if (permissionID == "contact") {return judgeIosPermissionContact()} else if (permissionID == "calendar") {return judgeIosPermissionCalendar()} else if (permissionID == "memo") {return judgeIosPermissionMemo()}return false;
}// 跳转到**应用**的权限页面  
function gotoAppPermissionSetting() {if (isIos) {var UIApplication = plus.ios.import("UIApplication");var application2 = UIApplication.sharedApplication();var NSURL2 = plus.ios.import("NSURL");// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");       var setting2 = NSURL2.URLWithString("app-settings:");application2.openURL(setting2);plus.ios.deleteObject(setting2);plus.ios.deleteObject(NSURL2);plus.ios.deleteObject(application2);} else {// console.log(plus.device.vendor);  var Intent = plus.android.importClass("android.content.Intent");var Settings = plus.android.importClass("android.provider.Settings");var Uri = plus.android.importClass("android.net.Uri");var mainActivity = plus.android.runtimeMainActivity();var intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);intent.setData(uri);mainActivity.startActivity(intent);}
}// 检查系统的设备服务是否开启  
// var checkSystemEnableLocation = async function () {  
function checkSystemEnableLocation() {if (isIos) {var result = false;var cllocationManger = plus.ios.import("CLLocationManager");var result = cllocationManger.locationServicesEnabled();console.log("系统定位开启:" + result);plus.ios.deleteObject(cllocationManger);return result;} else {var context = plus.android.importClass("android.content.Context");var locationManager = plus.android.importClass("android.location.LocationManager");var main = plus.android.runtimeMainActivity();var mainSvr = main.getSystemService(context.LOCATION_SERVICE);var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);console.log("系统定位开启:" + result);return result}
}let permissionMap = {"android": {"CALL_PHONE": {"name": "android.permission.CALL_PHONE","title": "拨打电话权限说明","mtitle": "拨打电话权限","content": "向您获取拨打电话权限,便于联系客服等"},"CAMERA&STORAGE": {"name": "android.permission.WRITE_EXTERNAL_STORAGE,android.permission.CAMERA","title": "相机/相册权限说明","mtitle": "相机/相册权限","content": "便于您使用该功能上传您的照片/图片,用于上传证件等场景中读取和写入相册和文件内容"},"CAMERA": {"name": "android.permission.CAMERA","title": "相机权限说明","mtitle": "相机权限","content": "便于您使用该功能上传您的照片/图片,用于上传证件等场景中拍摄内容"},"PHOTO": {"name": "android.permission.READ_EXTERNAL_STORAGE","title": "相册权限说明","mtitle": "相册权限","content": "便于您使用该功能上传您的照片/图片,用于上传证件等场景中选择相册内容"},"Location": {"name": "android.permission.ACCESS_COARSE_LOCATION,android.permission.ACCESS_FINE_LOCATION","title": "获取当前定位权限说明","mtitle": "获取当前定位权限","content": "向您获取当前的地理位置信息,便于查看位置、地图选点与导航等功能"},"STORAGE": {"name": "android.permission.WRITE_EXTERNAL_STORAGE","title": "存储权限申请说明","mtitle": "存储权限","content": "为了将图片保存到手机,我们需要向您申请存储权限。"}},"ios": {}
}let view = null;function showViewDesc(permission) {let plat = isIos ? "ios" : "android";view = new plus.nativeObj.View('per-modal', {top: '0px',left: '0px',width: '100%',backgroundColor: 'rgba(0,0,0,0.2)',//opacity: '.9'     })view.drawRect({color: '#fff',radius: '5px'}, {top: '30px',left: '5%',width: '90%',height: "100px",})view.drawText(permissionMap[plat][permission]["title"], {top: '40px',left: "8%",height: "30px"}, {align: "left",color: "#000",}, {onClick: function(e) {console.log(e);}})view.drawText(permissionMap[plat][permission]["content"], {top: '65px',height: "60px",left: "8%",width: "84%"}, {whiteSpace: 'normal',size: "14px",align: "left",color: "#656563"})view.show()
}function premissionCheck(permission) {console.log('premissionCheck')return new Promise(async (resolve, reject) => {let plat = isIos ? "ios" : "android";if (isIos) { // ios  // const camera = permission.judgeIosPermission("camera");//判断ios是否给予摄像头权限  // //ios相册没权限,系统会自动弹出授权框  // //let photoLibrary = permission.judgeIosPermission("photoLibrary");//判断ios是否给予相册权限  // if(camera){  //     resolve();  // }else{  //     reject('需要开启相机使用权限');  // }  resolve(1)} else { // android  console.log('android')let permission_arr = permissionMap[plat][permission]["name"].split(",");let flag = true;for (let i = 0; i < permission_arr.length; i++) {let status = plus.navigator.checkPermission(permission_arr[i]);if (status == "undetermined") {flag = false;}}console.log("flag", flag)if (flag == false) { // 未完全授权  showViewDesc(permission);requestAndroidPermission(permissionMap[plat][permission]["name"]).then((res) => {view.close();if (res == -1) {uni.showModal({title: '提示',content: permissionMap[plat][permission]["mtitle"] + '已被拒绝,请手动前往设置',confirmText: "立即设置",success: (res) => {if (res.confirm) {gotoAppPermissionSetting()}}})}resolve(res)})} else {resolve(1)}}})
}export default {judgeIosPermission: judgeIosPermission,requestAndroidPermission: requestAndroidPermission,checkSystemEnableLocation: checkSystemEnableLocation,gotoAppPermissionSetting: gotoAppPermissionSetting,premissionCheck: premissionCheck
}

五、热更新wgt

1.下载弹窗

<template><view class="mask flex-center"><view class="content"><view style="position: relative;"><image class="content-img" src="./card.png" /><view class="content-version" v-if="data?.edition_name">版本号:{{data?.edition_name}}</view></view><view class="content-body"><view class="content-body-row" v-for="(item,index) of data.describe.split(';')" :key="new Date().getTime()"><view class="dot" /><view class="content-body-lable">{{item}}</view></view><view v-if="showProgress"><u-line-progress :striped="true" :percent="percent" active-color="#E80A1E" :striped-active="true" /><view>正在下载,请稍后</view></view><view v-else><view v-if="!cancleBtn"><view class="content-button-now content-button" @click="confirm">立即更新</view></view><view class="content-button-row" v-else><view class="content-button-cancel content-button" @click="cancel">以后再说</view><view class="content-button-confirm content-button" @click="confirm">立即更新</view></view></view></view></view></view>
</template><script setup>import {ref,reactive,toRefs} from 'vue'import {onLoad,onBackPress} from '@dcloudio/uni-app'const dataMap = reactive({percent: 0, //进度条百分比cancleBtn: true, //是否强制立即更新showProgress: false, //是否显示按钮data: {describe: '1. 修复已知问题;2. 优化用户体验',edition_url: 'http://download.rongtongkeji.com/荣煤宝.apk', //安装包下载地址或者通用应用市场地址edition_force: 1, //是否强制更新 0代表否 1代表是package_type: 1 //0是整包升级 1是wgt升级}})const {percent,cancleBtn,data,showProgress} = toRefs(dataMap)onLoad((e) => {if (e?.obj) {dataMap.data = JSON.parse(e.obj);}dataMap.cancleBtn = !dataMap.data.edition_force;})onBackPress((e) => {// 强制更新不允许返回if (dataMap.data.edition_force || dataMap.percent > 0) {return true;}})const cancel = () => {//取消升级 返回上一页uni.navigateBack({delta: 1});}const confirm = () => {// const packageName = ''// let url = ''// let deviceBrand = uni.getSystemInfoSync()?.deviceBrand?.toLowerCase() || ''// if (dataMap.data.package_type == 0) {// 	if (uni.getSystemInfoSync().platform != 'android') {// 		url = "https://apps.apple.com/cn/app/xxx"// 	} else {// 		if (deviceBrand.indexOf("huawei") > -1) {// 			url = "appmarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("oppo") > -1) {// 			url = "market://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("vivo") > -1) {// 			url = "vivoMarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("mi") > -1) {// 			url = "mimarket://details?id=" + packageName;// 		} else if (deviceBrand.indexOf("samsung") > -1) {// 			url = "samsungapps://ProductDetail/" + packageName;// 		} else if (deviceBrand.indexOf("lenovo") > -1) {// 			url = "http://market.lenovomm.com/details?id=" + packageName;// 		} else {// 			// url = "https://a.app.qq.com/o/simple.jsp?pkgname="+packageName;// 			url = "http://download/xx.apk";// 		}// 	}// 	//apk整包升级// 	if (url.includes('.apk')) {// 		download();// 	} else {// 		plus.runtime.openURL(url);// 	}// } else {// 	//wgt资源包升级// 	download();// }download();}const download = () => {dataMap.data.edition_force = 0dataMap.showProgress = trueconst downloadTask = uni.downloadFile({url: dataMap.data.edition_url,success: res => {if (res.statusCode === 200) {plus.runtime.install(res.tempFilePath, {force: true //true表示强制安装,不进行版本号的校验;false则需要版本号校验,},function() {if (dataMap.data.package_type == 1) {// wgt升级需要重启plus.runtime.restart();}else {plus.runtime.quit();}},function(e) {console.error('install fail...');});}}});downloadTask.onProgressUpdate(res => {dataMap.percent = res.progress;});}
</script><style lang="scss">page {background: transparent;}.flex-center {display: flex;justify-content: center;align-items: center;}.mask {position: fixed;left: 0;top: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.65);}.content {width: 600rpx;background: #FFFFFF;border-radius: 32rpx;.content-img {width: 600rpx;height: 344rpx;}.content-version {position: absolute;bottom: 22rpx;left: 70rpx;font-size: 28rpx;font-family: PingFangSC-Medium, PingFang SC;font-weight: 500;color: #E90F21;}.content-body {padding: 0 40rpx 40rpx 40rpx;.content-body-row {display: flex;.dot {width: 14rpx;height: 14rpx;background-color: #E90D20;border-radius: 50px;margin-top: 16rpx;margin-right: 16rpx;}.content-body-lable {width: 506rpx;font-size: 28rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #333333;}}.content-button-now {width: 520rpx;color: #FFFFFF;background: linear-gradient(90deg, #FF775B 0%, #E80A1E 100%);margin-top: 32rpx;}.content-button-row {display: flex;justify-content: space-between;margin-top: 32rpx;.content-button-confirm {width: 244rpx;background: linear-gradient(90deg, #FF775B 0%, #E80A1E 100%);color: #FFFFFF;}.content-button-cancel {width: 244rpx;border: 2rpx solid #999999;color: #999999;}}.content-button {height: 80rpx;border-radius: 40rpx;font-size: 28rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;display: flex;justify-content: center;align-items: center;}}}
</style>

2.silence-update文件从服务器判断是否需要更新

import { config } from '@/config/config';
export const silenceUpdate = (url) => {uni.downloadFile({url,success: res => {if (res.statusCode === 200) {plus.runtime.install(res.tempFilePath, {force: true //true表示强制安装,不进行版本号的校验;false则需要版本号校验,},function() {uni.showModal({title: '更新提示',content: '新版本已经准备好,请重启应用',showCancel: false,success: function(res) {if (res.confirm) {plus.runtime.restart()}}});// console.log('install success...');},function(e) {console.error('install fail...');});}}});
}export const checkVersion = (appid, platform, version_code, loadding) => {loadding && uni.showLoading({title: '加载中',mask: true})let url = config.baseUrl + '/edition/get_renew_edition'//获取服务器的版本号uni.request({url: url,method: 'POST',data: {edition_type: appid,version_type: platform,edition_number: version_code,},header: {"content-type": "application/json",},success: (res) => {console.log(res, 'res')if (res.statusCode == 200 && res.data.ok) {//判断后台返回版本号是否大于当前应用版本号 && 是否发行if (Number(res.data.data.edition_number) == version_code && res.data.data.edition_issue && loadding) {uni.showToast({title: '已是最新版本',icon: 'none',mask: true})return}if (Number(res.data.data.edition_number) > version_code && res.data.data.edition_issue) {//注意 这里obj尽量不要修改,如果非要修改,rt-uni-update里的onload的obj也得改if (res.data.data.package_type == '1' && res.data.data.edition_silence) {//调用静默更新方法 传入下载地址silenceUpdate(res.data.data.edition_url)} else {const pages = getCurrentPages()let flag = falsefor (let s of pages) {if(s.route == 'components/hot-update-gc/index') flag = true}!flag && uni.navigateTo({url: '/components/hot-update-gc/index?obj=' + JSON.stringify(res.data.data)})}}}},fail: (err) => {console.log(err, 'err')},complete: () => {loadding && uni.hideLoading()}})
}

3.调用checkVersion 

import { checkVersion } from "@/xxx/silence-update.js"
plus.runtime.getProperty(plus.runtime.appid!, async (inf) => {let version_code = +inf.versionCode!checkVersion(plus.runtime.appid, uni.getSystemInfoSync().platform, version_code, false)
})

相关文章:

  • Transformer-LSTM-SVM回归
  • 学习基本咖啡知识
  • C# 中重启程序通常意味着关闭当前运行的应用程序实例
  • 豪越科技消防立库方案:实现应急物资高效管理
  • 基于STM32、HAL库的DS28E15P安全验证及加密芯片驱动程序设计
  • 纯C协程框架NtyCo
  • 智慧交警系统架构设计方案
  • RHCE第七章:SElinux
  • leetcode继续c++10/100
  • NOC科普一
  • 明远智睿SSD2351开发板:开启嵌入式开发新篇程
  • CertiK创始人顾荣辉出席Unchained Summit,探讨Web3.0安全与合规路径
  • 数据采集脱硫脱硝除尘实验装置
  • 【Linux】g++安装教程
  • 各服务日志: Grok正则解析
  • 图片识别为提示词,背景信息提取 -从头设计数字生命第7课, demucs——仙盟创梦IDE
  • 【PyTorch动态计算图实战解析】从原理到高效开发
  • stm32 g031g8 flash擦除函数被坑
  • 从传统到现代:Endpoint Central 控制台一站式管理全解析
  • MCP协议简单拆解
  • 白云山一季度营收净利双降,此前称今年将挖掘盘活自身资源
  • 保利发展去年净利润约50亿元,在手现金1342亿元
  • 亮剑浦江丨上海网信部门处罚一批医疗服务类互联网企业,三大类问题值得关注
  • 伊朗港口爆炸已致46人死亡
  • 报告显示2024年全球军费开支增幅达冷战后最大
  • 国家税务总局:“二套转首套”可以享受贷款利息个税专项扣除