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中的内容为

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

uniapp相关代码

upgrade.vue中存在

javascript 复制代码
<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

javascript 复制代码
/**
 * @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

javascript 复制代码
<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>
相关推荐
guai_guai_guai18 分钟前
uniapp
前端·javascript·vue.js·uni-app
阿伟来咯~6 小时前
一些 uniapp相关bug
uni-app·bug
瑶琴AI前端9 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
mosen86810 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
尚梦17 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
尚学教辅学习资料1 天前
基于SSM+uniapp的营养食谱系统+LW参考示例
java·uni-app·ssm·菜谱
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
qq22951165021 天前
小程序Android系统 校园二手物品交换平台APP
微信小程序·uni-app
qq22951165022 天前
微信小程序uniapp基于Android的流浪动物管理系统 70c3u
微信小程序·uni-app
qq22951165022 天前
微信小程序 uniapp+vue老年人身体监测系统 acyux
vue.js·微信小程序·uni-app