UNIapp实现局域网内在线升级的操作方法

 更新时间:2024年03月05日 09:41:45   作者:走在路上的霍纳奇思  
这篇文章主要介绍了UNIapp实现局域网内在线升级的操作方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

首先是UNIapp 生成apk

用Hbuilder 进行打包

可以从网站https://www.yunedit.com/reg?goto=cert 使用自有证书,目测比直接使用云证书要快一些。

发布apk 网站

用IIS发布即可
注意事项中记录如下内容

第一、需要在 iis 的MiMe 中添加apk 的格式,否则无法下载apk 文件到手持机中。 添加方式 打开MIME 点击添加
分别输入 apk application/vnd.android.package-archive 点击保存即可

第二、发布新的apk 的时候,需要修改应用版本号(往大了修改),同时版本号.json 文件中
newVersionCode对应的值,也要和新的应用版本号相同(方便检测更新) newVersionName 中保存的是当前PDA的版本名称
versionDesc 中可以添加修改的内容 appName 需要添加新发布的apk 名称(用于下载对应的文件)

第三、将对应的文件夹发布在iis中,同时要修改uniapp 中的http.js文件
uni.setStorageSync(‘loadVersion’, ‘http://127.0.0.1:8032/’); 修改内部的url

要在IIS中添加.apk文件的MIME类型,可以按照以下步骤操作:

打开IIS管理器,找到服务器,右键选择“属性”。
在打开的属性窗口中,选择“MIME类型”选项卡。
点击“MIME类型”按钮,打开MIME类型设置窗口。
选择“新建”来添加一个新的MIME类型。
在“扩展名”中填写“.apk”,在“MIME类型”中填写“.apk”的MIME类型“application/vnd.android.package-archive”。
点击“确定”保存设置。
重启IIS服务,以使更改生效。
完成以上步骤后,IIS就能够正确识别和处理.apk文件了

版本号.json中的内容为

{"newVersionCode":223,"newVersionName":"V1.2.0","versionDesc":"升级了部分功能","appName":"android_debug.apk"}

uniapp相关代码

upgrade.vue中存在

<template>
	<view class="upgrade-popup">
		<view class="main">
			<view class="version">发现新版本{{versionName}}</view>
			<view class="content">
				<text class="title">更新内容</text>
				<view class="desc" v-html="versionDesc"></view>
			</view>
			<!--下载状态-进度条显示 -->
			<view class="footer" v-if="isStartDownload">
				<view class="progress-view" :class="{'active':!hasProgress}" @click="handleInstallApp">
					<!-- 进度条 -->
					<view v-if="hasProgress" style="height: 100%;">
						<view class="txt">{{percentText}}</view>
						<view class="progress" :style="setProStyle"></view>
					</view>
					<view v-else>
						<view class="btn upgrade force">{{ isDownloadFinish  ? '立即安装' :'下载中...'}}</view>
					</view>
				</view>
			</view>
			<!-- 强制更新 -->
			<view class="footer" v-else-if="isForceUpdate">
				<view class="btn upgrade force" @click="handleUpgrade">立即更新</view>
			</view>
			<!-- 可选择更新 -->
			<view class="footer" v-else>
				<view class="btn close" @click="handleClose">以后再说</view>
				<view class="btn upgrade" @click="handleUpgrade">立即更新</view>
			</view>
		</view>
	</view>
</template>
<script>
	import {
		downloadApp,
		installApp
	} from './upgrade.js'
	export default {
		data() {
			return {
				isForceUpdate: false, //是否强制更新
				versionName: '', //版本名称
				versionDesc: '', //更新说明
				downloadUrl: '', //APP下载链接
				isDownloadFinish: false, //是否下载完成
				hasProgress: false, //是否能显示进度条
				currentPercent: 0, //当前下载百分比
				isStartDownload: false, //是否开始下载
				fileName: '', //下载后app本地路径名称
			}
		},
		computed: {
			//设置进度条样式,实时更新进度位置
			setProStyle() {
				return {
					width: (510 * this.currentPercent / 100) + 'rpx' //510:按钮进度条宽度
				}
			},
			//百分比文字
			percentText() {
				let percent = this.currentPercent;
				if (typeof percent !== 'number' || isNaN(percent)) return '下载中...'
				if (percent < 100) return `下载中${percent}%`
				return '立即安装'
			}
		},
		onLoad(options) {
			this.init(options)
		},
		onBackPress(options) {
			// 禁用返回
			if (options.from == 'backbutton') {
				return true;
			}
		},
		methods: {
			//初始化获取最新APP版本信息
			init(options) {
				let randomNum = Math.random();
				//模拟接口获取最新版本号,版本号固定为整数
				const baseurl = uni.getStorageSync('loadVersion')+options.appName+'?V='+randomNum;;
				console.log('结果为')
				console.log((baseurl))
				//模拟接口获取
				setTimeout(() => {
                   //演示数据请根据实际修改
					this.versionName = options.versionName; //版本名称
					this.versionDesc = options.versionDesc; //更新说明
					this.downloadUrl = baseurl; //下载链接
					this.isForceUpdate = false; //是否强制更新
				}, 200)
			},
			//更新
			handleUpgrade() {
				console.log('Hello UniApp!-----------------------------------------------')
				uni.getStorage({
					key: 'loadVersion',
					success: function (res) {
						console.log(res.data);
					}
				});
			   //requestTask.abort();
				if (this.downloadUrl) {
					this.isStartDownload = true
					//开始下载App
					downloadApp(this.downloadUrl, current => {
						//下载进度监听
						this.hasProgress = true
						this.currentPercent = current
					}).then(fileName => {
						//下载完成
						this.isDownloadFinish = true
						this.fileName = fileName
						if (fileName) {
							//自动安装App
							this.handleInstallApp()
						}
					}).catch(e => {
						console.log(e, 'e')
					})
				} else {
					uni.showToast({
						title: '下载链接不存在',
						icon: 'none'
					})
				}
			},
			//安装app
			handleInstallApp() {
				//下载完成才能安装,防止下载过程中点击
				if (this.isDownloadFinish && this.fileName) {
					installApp(this.fileName, () => {
						//安装成功,关闭升级弹窗
						uni.navigateBack()
					})
				}
			},
			//关闭返回
			handleClose() {
				uni.navigateBack()
			},
		}
	}
</script>
<style>
	page {
		background: rgba(0, 0, 0, 0.5);/**设置窗口背景半透明*/
	}
</style>
<style lang="scss" scoped>
	.upgrade-popup {
		width: 580rpx;
		height: auto;
		position: fixed;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		background: #fff;
		border-radius: 20rpx;
		box-sizing: border-box;
		border: 1px solid #eee;
	}
	.header-bg {
		width: 100%;
		margin-top: -112rpx;
	}
	.main {
		padding: 10rpx 30rpx 30rpx;
		box-sizing: border-box;
		.version {
			font-size: 36rpx;
			color: #026DF7;
			font-weight: 700;
			width: 100%;
			text-align: center;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
			letter-spacing: 1px;
		}
		.content {
			margin-top: 60rpx;
			.title {
				font-size: 28rpx;
				font-weight: 700;
				color: #000000;
			}
			.desc {
				box-sizing: border-box;
				margin-top: 20rpx;
				font-size: 28rpx;
				color: #6A6A6A;
				max-height: 80vh;
				overflow-y: auto;
			}
		}
		.footer {
			width: 100%;
			display: flex;
			justify-content: center;
			align-items: center;
			position: relative;
			flex-shrink: 0;
			margin-top: 100rpx;
			.btn {
				width: 246rpx;
				display: flex;
				justify-content: center;
				align-items: center;
				position: relative;
				z-index: 999;
				height: 96rpx;
				box-sizing: border-box;
				font-size: 32rpx;
				border-radius: 10rpx;
				letter-spacing: 2rpx;
				&.force {
					width: 500rpx;
				}
				&.close {
					border: 1px solid #E0E0E0;
					margin-right: 25rpx;
					color: #000;
				}
				&.upgrade {
					background-color: #026DF7;
					color: white;
				}
			}
			.progress-view {
				width: 510rpx;
				height: 90rpx;
				display: flex;
				position: relative;
				align-items: center;
				border-radius: 6rpx;
				background-color: #dcdcdc;
				display: flex;
				justify-content: flex-start;
				padding: 0px;
				box-sizing: border-box;
				border: none;
				overflow: hidden;
				&.active {
					background-color: #026DF7;
				}
				.progress {
					height: 100%;
					background-color: #026DF7;
					padding: 0px;
					box-sizing: border-box;
					border: none;
					border-top-left-radius: 10rpx;
					border-bottom-left-radius: 10rpx;
				}
				.txt {
					font-size: 28rpx;
					position: absolute;
					top: 50%;
					left: 50%;
					transform: translate(-50%, -50%);
					color: #fff;
				}
			}
		}
	}
</style>

upgrade.js

/**
 * @description H5+下载App
 * @param downloadUrl:App下载链接
 * @param progressCallBack:下载进度回调
 */
export const downloadApp = (downloadUrl, progressCallBack = () => {}, ) => {
	return new Promise((resolve, reject) => {
		//创建下载任务
		const downloadTask = plus.downloader.createDownload(downloadUrl, {
			method: "GET"
		}, (task, status) => {
			console.log(status,'status')
			if (status == 200) { //下载成功
				resolve(task.filename)
			} else {
				reject('fail')
				uni.showToast({
					title: '下载失败',
					duration: 1500,
					icon: "none"
				});
			}
		})
		//监听下载过程
		downloadTask.addEventListener("statechanged", (task, status) => {
			switch (task.state) {
				case 1: // 开始  
					break;
				case 2: //已连接到服务器  
					break;
				case 3: // 已接收到数据  
					let hasProgress = task.totalSize && task.totalSize > 0 //是否能获取到App大小
					if (hasProgress) {
						let current = parseInt(100 * task.downloadedSize / task.totalSize); //获取下载进度百分比
						progressCallBack(current)
					}
					break;
				case 4: // 下载完成       
					break;
			}
		});
		//开始执行下载
		downloadTask.start();
	})
}
/**
 * @description H5+安装APP
 * @param fileName:app文件名
 * @param callBack:安装成功回调
 */
export const installApp = (fileName, callBack = () => {}) => {
	//注册广播监听app安装情况
	onInstallListening(callBack);
	//开始安装
	plus.runtime.install(plus.io.convertLocalFileSystemURL(fileName), {}, () => {
		//成功跳转到安装界面
	}, function(error) {
		uni.showToast({
			title: '安装失败',
			duration: 1500,
			icon: "none"
		});
	})
}
/**
 * @description 注册广播监听APP是否安装成功
 * @param callBack:安装成功回调函数
 */
const onInstallListening = (callBack = () => {}) => {
	let mainActivity = plus.android.runtimeMainActivity(); //获取activity
	//生成广播接收器
	let receiver = plus.android.implements('io.dcloud.android.content.BroadcastReceiver', {
		onReceive: (context, intent) => { //接收广播回调  
			plus.android.importClass(intent);
			mainActivity.unregisterReceiver(receiver); //取消监听
			callBack()
		}
	});
	let IntentFilter = plus.android.importClass('android.content.IntentFilter');
	let Intent = plus.android.importClass('android.content.Intent');
	let filter = new IntentFilter();
	filter.addAction(Intent.ACTION_PACKAGE_ADDED); //监听APP安装     
	filter.addDataScheme("package");
	mainActivity.registerReceiver(receiver, filter); //注册广播
}

home.vue

<template>
	<view>
		<image style="width: 100%;" mode="widthFix" src="/static/swiper1.png"></image>
		<!-- 	<u-swiper height="360rpx" :list="swiperList" :radius="0"></u-swiper> -->
		<view class="home-content">
			<view class="app-name">WMS手持机系统</view>
			<view class="card-container">
				<view class="fn-title">基础功能</view>
				<u-grid :border="false" @click="gridClick" col="4">
					<u-grid-item v-for="(item,index) in fn" :key="index">
						<view :class="['grid-item-bg','grid-item-bg-'+(index+1)]">
							<u-icon :name='item.icon' :color="item.color" size="28"></u-icon>
						</view>
						<view class="grid-text">{{item.name}}</view>
					</u-grid-item>
				</u-grid>
			</view>
			<view style="padding:30rpx;padding-top:0;">
				<vol-alert type="primary">
				</vol-alert>
			</view>
		</view>
	</view>
</template>
<script>
	export default {
		data() {
			return {
				height: 0,
				swiperList: [
					'/static/swiper1.png',
					'/static/swiper2.png',
					'/static/swiper3.png'
				],
				fn: [{
						name: "有单据组盘1",
						icon: '/static/fc.png',
						path: "/pages/basics/T_In_ReceiptNoticeDetail/T_In_ReceiptNoticeDetail",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "手动入库",
						icon: '/static/fc.png',
						path: "",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "无单据组盘",
						icon: 'edit-pen-fill',
						color: '#8B8989',
						path: "/pages/createbyus/HaveOrderGroup/HaveOrderGroup",
						subPage: true //二级页面
					}, {
						name: "入库计划",
						icon: '/static/fc.png',
						path: "/pages/basics/T_In_ReceiptNotice/T_In_ReceiptNotice",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "确认出库",
						icon: '/static/fc.png',
						path: "/pages/reportvshow/V_OutboundDetail/V_OutboundDetail",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "托盘处理",
						icon: '/static/fc.png',
						path: "/pages/strategy/DealTrayCURD/DealTrayCURD",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "盘点处理",
						icon: '/static/fc.png',
						path: "/pages/strategy/T_InventoryCheckDetail/T_InventoryCheckDetail",
						color: '#EE0000',
						subPage: true //二级页面
					}, {
						name: "出库计划",
						icon: '/static/flow.png',
						color: '#EE0000',
						path: "/pages/basics/T_Out_DeliveryNotice/T_Out_DeliveryNotice",
						subPage: true //二级页面
					},
					{
						name: "审批流程",
						icon: '/static/flow.png',
						color: '#EE0000',
						path: "/pages/flow/flow",
						subPage: false //二级页面
					}, {
						name: "表单示例",
						icon: '/static/form.png',
						color: '#EE0000',
						path: "/pages/form/form",
						subPage: true //二级页面
					},
					{
						name: "Table组件",
						icon: '/static/fc.png',
						color: '#EE0000',
						path: "/pages/form/form",
						subPage: true //二级页面
					},
					{
						name: "菜单列表",
						icon: '/static/table.png',
						color: '#EE0000',
						path: "/pages/menu/menu",
						subPage: false //二级页面
					},
					// {
					// 	name: "地图导航",
					// 	icon: '/static/fc.png',
					// 	color:'#EE0000',
					// 	path: "/pages/map/map",
					// 	subPage: true //二级页面
					// },
					// //待开发功能
					// {
					// 	name: "敬请期待",
					// 	icon: '/static/fc.png',
					// 	path: "pages/basics/T_In_ReceiptNotice/T_In_ReceiptNotice",
					// 	color:'#EE0000',
					// 	subPage: true //二级页面
					// },
					// {
					// 	name: "敬请期待",
					// 	icon: '/static/fc.png',
					// 	color:'#EE0000',
					// 	path: "",
					// }
				],
			}
		},
		onLoad() {
			var _this = this;
			// 获取手机状态栏高度
			uni.getSystemInfo({
				success: function(data) {
					// 将其赋值给this
					_this.height = data.statusBarHeight;
				}
			});
			_this.init();
		},
		onReady(){
			this.checkVersion(1)
		},
		onShow() {
		},
		methods: {
			//初始化
			init() {
			},
			//检查版本更新情况
			checkVersion(indexValue) {
	var _this = this;
				let index=0;
				setTimeout(() => {
					let randomNum = Math.random();
					//模拟接口获取最新版本号,版本号固定为整数
					const baseurl = uni.getStorageSync('loadVersion')+'版本号.json?V='+randomNum;
					console.log(baseurl)
					var requestTask = uni.request({
						url: baseurl, //仅为示例,并非真实接口地址。
						method:'GET',
						success: function(res) {
							index++;
								console.log(res.data);	
								const newVersionName =res.data.newVersionName //线上最新版本名
								const newVersionCode =res.data.newVersionCode; //线上最新版本号
								const selfVersionCode = Number(uni.getSystemInfoSync().appVersionCode) //当前App版本号
								console.log(index+'../index/upgrade?versionName='+newVersionName+'&versionDesc='+res.data.versionDesc)
								console.log(selfVersionCode)
								console.log(newVersionCode)
								//线上版本号高于当前,进行在线升级
								if (selfVersionCode < newVersionCode) {
									let platform = uni.getSystemInfoSync().platform //手机平台
									uni.navigateTo({
										url: '../index/upgrade?versionName='+newVersionName+'&versionDesc='+res.data.versionDesc+'&appName='+res.data.appName
									})
								}
								else
								{
									_this.clickUseInfo(indexValue);
								}
							},
							fail :function(res)
							{
								console.log(res);
							},
							complete: ()=> {}
					});
				}, 200)
			},
			getStyle(item) {
				return {
					paddingTop: 20 + 'rpx',
					background: item.color,
					padding: '50%',
					color: "#ffff",
					'border-radius': '50%',
					left: '-24rpx'
				}
			},
			gridClick(index) {
				this.checkVersion(index)
			},
			clickUseInfo(index)
			{
				const item = this.fn[index];
				console.log(index)
				if (!item.path) {
					this.$toast('开发中')
					return;
				}
			//注意下面的跳转方式,一级页面指pages.json中tabBar配置path
			//具体见uni页面跳转文档
			if (item.subPage) {
				//二级页面用navigateTo跳转
				uni.navigateTo({
					url: this.fn[index].path
				})
				return;
			}
			//一级页面
			uni.switchTab({
				url: this.fn[index].path
			})
			},
			swiperClick(index) {
			}
		}
	}
</script>
<style lang="less" scoped>
	.home-content {
		z-index: 999;
		position: relative;
		margin-top: -220rpx;
	}
	.app-name {
		text-align: center;
		color: #ffff;
		font-weight: bolder;
		font-size: 60rpx;
		top: -40rpx;
		position: relative;
	}
	.card-container {
		box-shadow: 1px 1px 9px #b9b6b629;
		margin: 30rpx 30rpx 30rpx 30rpx;
		border: 1px solid #f1f1f1;
		border-radius: 10rpx;
		padding: 26rpx 10rpx 14rpx 10rpx;
		background: #ffff;
		.fn-title {
			font-family: 黑体;
			font-size: 30rpx;
			font-weight: bold;
			//color: #8f9ca2;
			padding: 4rpx 20rpx 30rpx 20rpx;
		}
		.grid-text {
			padding-top: 8rpx;
			font-size: 26rpx;
			color: #626262;
			padding-bottom: 20rpx;
		}
	}
	.grid-item-bg {
		border-radius: 50%;
		width: 86rpx;
		height: 86rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		box-shadow: 5px 3px 6px #e0ddddb0;
	}
	.grid-item-bg-1 {
		background-image: linear-gradient(to bottom right, #97caff, #47a1fe);
	}
	.grid-item-bg-2 {
		background-image: linear-gradient(to bottom right, #f8bcbc, #f07e7e);
	}
	.grid-item-bg-3 {
		background-image: linear-gradient(to bottom right, #afb5e6, #808cf0);
	}
	.grid-item-bg-4 {
		background-image: linear-gradient(to bottom right, #98e4e2, #56c3bf);
	}
	.grid-item-bg-5 {
		background-image: linear-gradient(to bottom right, #d1d1d1, #c878e7);
	}
	.grid-item-bg-6 {
		background-image: linear-gradient(to bottom right, #97caff, #47a1fe);
	}
	.grid-item-bg-7 {
		background-image: linear-gradient(to bottom right, #98e4e2, #56c3bf);
	}
	.grid-item-bg-8 {
		background-image: linear-gradient(to bottom right, #afb5e6, #808cf0);
	}
</style>

到此这篇关于UNIapp实现局域网内在线升级的文章就介绍到这了,更多相关UNIapp在线升级内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 前端H5微信支付宝支付实现方法(uniapp为例)

    前端H5微信支付宝支付实现方法(uniapp为例)

    最近上线一个项目,手机网站进行调起支付宝App支付,做起来还是满顺手的,在此做个记录,这篇文章主要给大家介绍了关于前端H5微信支付宝支付实现方法的相关资料,需要的朋友可以参考下
    2024-04-04
  • 详解vue中v-model的实现原理

    详解vue中v-model的实现原理

    v-model可以实现数据的双向绑定,也是vue的最突出的优势,其实 v-model 实际上是一个语法糖,本文将给大家介绍一下vue中v-model的实现原理,文中有相关的代码供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2023-12-12
  • vue3.x对echarts的二次封装之按需加载过程详解

    vue3.x对echarts的二次封装之按需加载过程详解

    echarts是我们后台系统中最常用的数据统计图形展示,外界对它的二次封装也不计层数,这篇文章主要介绍了vue3.x对echarts的二次封装之按需加载,需要的朋友可以参考下
    2023-09-09
  • vue常见的通信方式总结

    vue常见的通信方式总结

    我们日常项目开发中,少不了组件之间的通信,我们可能只知道一些常见的方式比如props,emits,其实,实现组件间的通信有很多种方式,本文就给大家总结一些我们常见的通信方式,需要的朋友可以参考下
    2023-08-08
  • vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】

    vue自定义键盘信息、监听数据变化的方法示例【基于vm.$watch】

    这篇文章主要介绍了vue自定义键盘信息、监听数据变化的方法,结合实例形式分析了vue.js基于vm.$watch进行事件监听相关操作技巧,需要的朋友可以参考下
    2019-03-03
  • vue+echarts实现多条折线图

    vue+echarts实现多条折线图

    这篇文章主要为大家详细介绍了vue+echarts实现多条折线图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 浅谈Vue中render中的h箭头函数

    浅谈Vue中render中的h箭头函数

    今天小编就为大家分享一篇浅谈Vue中render中的h箭头函数,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • vue实现简易音乐播放器

    vue实现简易音乐播放器

    这篇文章主要为大家详细介绍了vue实现简易音乐播放器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • 关于vue中标签的属性绑定值渲染问题

    关于vue中标签的属性绑定值渲染问题

    这篇文章主要介绍了关于vue中标签的属性绑定值渲染问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Vue状态管理之使用Pinia代替Vuex

    Vue状态管理之使用Pinia代替Vuex

    这篇文章主要介绍了Vue状态管理。下面文章主要围绕着使用Pinia代替Vuex的相关资料展开具体内容,需要的朋友可以参考一下,希望对你有所帮助
    2021-11-11

最新评论