zhongtianhaoyuan %!s(int64=2) %!d(string=hai) anos
pai
achega
f495f2c310

+ 18 - 2
App.vue

@@ -6,10 +6,20 @@
 		mapMutations
 	} from 'vuex';
 	import * as config from '@/config'
-	import appUpdate from 'common/appUpdate.js'
+	// import appUpdate from 'common/appUpdate.js'
+	// #ifdef APP-PLUS
+	import APPUpdate, {
+		getCurrentNo
+	} from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';
+	// #endif
 	import app_push from './components/APPPush/app_push.js'
 	const pushLive = uni.requireNativePlugin('service-keep-live');
 	export default {
+		data(){
+			return{
+				version:"",
+			}
+		},
 		methods: {
 			...mapMutations(['login']),
 			nvueRequst: function(method, url, data, header) {
@@ -276,10 +286,16 @@
 
 		},
 		onShow: function() {
+			// #ifdef APP-PLUS
+			getCurrentNo(res => {
+				// 进页面获取当前APP版本号(用于页面显示)
+				this.version = res.versionName;
+			});
+			// #endif
 			let type = uni.getSystemInfoSync().platform
 			console.log(type)
 			if (type == "android") {
-				// appUpdate()
+				AppUpdate()
 			}
 			console.log('App Show')
 		},

+ 58 - 2
pages/user/setUp.vue

@@ -41,18 +41,27 @@
 				</view>
 				<image src="../../static/img/myimg/gengduo1@3x.png" class="arrow"></image>
 			</view>
-			<view class='cu-item' style='margin-bottom:10px;' @click='updataEdition'>
+			<!-- <view class='cu-item' style='margin-bottom:10px;' @click='updataEdition'>
 				<view>
 					<text>检查新版本</text>
 				</view>
 				<image src="../../static/img/myimg/gengduo1@3x.png" class="arrow"></image>
-			</view>
+			</view> -->
 			<view class='cu-item' style='margin-bottom:10px;' @click='unsubscribe'>
 				<view>
 					<text>注销账户</text>
 				</view>
 				<image src="../../static/img/myimg/gengduo1@3x.png" class="arrow"></image>
 			</view>
+			<view class='cu-item' style='margin-bottom:10px;'>
+				<view>
+					<text>检查更新</text>
+				</view>
+				<view class="version_css" @click="onAPPUpdate">
+					{{version}}
+					<image src="../../static/img/myimg/gengduo1@3x.png" class="arrow"></image>
+				</view>
+			</view>
 		</view>
 		<view class='exitloginwrap'>
 			<button @click='logout()' class='exitlogin'>退出登录</button>
@@ -68,6 +77,12 @@
 	import {
 		mapState
 	} from 'vuex';
+	// #ifdef APP-PLUS
+	import APPUpdate, {
+		getCurrentNo
+	} from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';
+	import * as config from '@/config/index.js'
+	// #endif
 	export default {
 		data() {
 			return {
@@ -84,6 +99,7 @@
 					url: '',
 					show: true
 				}, ],
+				version:"1.1.0"
 			}
 		},
 		computed: {
@@ -91,9 +107,43 @@
 		},
 		onShow() {
 			this.getList()
+			// #ifdef APP-PLUS
+			this.version = plus.runtime.version
+			console.log("当前版本为:",plus.runtime.version)
+			this.checkVersion()
+			// #endif
 		},
 		onLoad() {},
 		methods: {
+			// 检查APP是否有新版本
+			onAPPUpdate() {
+				// true 没有新版本的时候有提示,默认:false
+				if (this.version == "发现新版本,立即更新") {
+					// #ifdef APP-PLUS
+					APPUpdate(true);
+					// #endif
+				}
+			},
+			checkVersion() {
+				const baseUrlNew = config.def().baseUrlNew
+				uni.request({
+					url: baseUrlNew + '/appVersion/selectInfo',
+					data: {
+						appid: plus.runtime.appid,
+						version: plus.runtime.version,
+						imei: "1",
+					},
+					method: 'GET',
+					success: (res) => {
+						var versionNo = plus.runtime.version
+						if (versionNo == res.data.data.version) {
+							this.version = "当前为最新版" + res.data.data.version
+						} else {
+							this.version = "发现新版本,立即更新"
+						}
+					}
+				})
+			},
 			updataEdition() {
 				// #ifdef APP-PLUS
 				let type = uni.getSystemInfoSync().platform
@@ -418,4 +468,10 @@
 	.exitlogin:after {
 		border: none;
 	}
+	.version_css {
+		// margin-right: 10rpx;
+		color: #9D9D9D;
+		font-size: 32rpx;
+		text-align: center;
+	}
 </style>

+ 5 - 0
uni_modules/zhouWei-APPUpdate/changelog.md

@@ -0,0 +1,5 @@
+## 3.0.1(2021-05-13)
+1. 跳转颜色和图标配置
+2. 新增静默更新
+## 3.0.0(2021-05-12)
+1. 支持uni_modules

+ 830 - 0
uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate.js

@@ -0,0 +1,830 @@
+// #ifdef APP-PLUS 
+import componentConfig from "@/config/componentConfig"
+const platform = uni.getSystemInfoSync().platform;
+// 主颜色
+const $mainColor = componentConfig.appUpdateColor ? componentConfig.appUpdateColor : "FF5B78";
+// 弹窗图标url
+const $iconUrl = componentConfig.appUpdateIcon ? componentConfig.appUpdateIcon : "/uni_modules/zhouWei-APPUpdate/static/ic_ar.png";
+
+// 获取当前应用的版本号
+export const getCurrentNo = function(callback) {
+	// 获取本地应用资源版本号
+	plus.runtime.getProperty(plus.runtime.appid, function(inf) {
+		callback && callback({
+			versionCode: inf.versionCode,
+			versionName: inf.version
+		});
+	});
+}
+// 从服务器下载应用资源包(wgt文件)
+const getDownload = function(data) {
+	let dtask;
+	if(data.updateType == 'forcibly' || data.updateType == 'solicit'){
+		let popupData = {
+			progress: true,
+			buttonNum: 2
+		};
+		if(data.updateType == 'forcibly'){
+			popupData.buttonNum = 0;
+		}
+		let lastProgressValue = 0;
+		let popupObj = downloadPopup(popupData);
+		dtask = plus.downloader.createDownload(data.downloadUrl, {
+			filename: "_doc/update/"
+		}, function(download, status) {
+			if (status == 200) {
+				popupObj.change({
+					progressValue: 100,
+					progressTip:"正在安装文件...",
+					progress: true,
+					buttonNum: 0
+				});
+				plus.runtime.install(download.filename, {}, function() {
+					popupObj.change({
+						contentText: "应用资源更新完成!",
+						buttonNum: 1,
+						progress: false
+					});
+				}, function(e) {
+					popupObj.cancel();
+					plus.nativeUI.alert("安装文件失败[" + e.code + "]:" + e.message);
+				});
+			} else {
+				popupObj.change({
+					contentText: "文件下载失败...",
+					buttonNum: 1,
+					progress: false
+				});
+			}
+		});
+		dtask.start();
+		dtask.addEventListener("statechanged", function(task, status) {
+			switch (task.state) {
+				case 1: // 开始
+					popupObj.change({
+						progressValue:0,
+						progressTip:"准备下载...",
+						progress: true
+					});
+					break;
+				case 2: // 已连接到服务器  
+					popupObj.change({
+						progressValue:0,
+						progressTip:"开始下载...",
+						progress: true
+					});
+					break;
+				case 3:
+					const progress = parseInt(task.downloadedSize / task.totalSize * 100);
+					if(progress - lastProgressValue >= 2){
+						lastProgressValue = progress;
+						popupObj.change({
+							progressValue:progress,
+							progressTip: "已下载" + progress + "%",
+							progress: true
+						});
+					}
+					break;
+			}
+		});
+		// 取消下载
+		popupObj.cancelDownload = function(){
+			dtask && dtask.abort();
+			uni.showToast({
+				title: "已取消下载",
+				icon:"none"
+			});
+		}
+		// 重启APP
+		popupObj.reboot = function(){
+			plus.runtime.restart();
+		}
+	} else if(data.updateType == "silent"){
+		dtask = plus.downloader.createDownload(data.downloadUrl, {
+			filename: "_doc/update/"
+		}, function(download, status) {
+			if (status == 200) {
+				plus.runtime.install(download.filename, {}, function() {
+					console.log("应用资源更新完成");
+				}, function(e) {
+					plus.nativeUI.alert("安装文件失败[" + e.code + "]:" + e.message);
+				});
+			} else {
+				plus.nativeUI.alert("文件下载失败...");
+			}
+		});
+		dtask.start();
+	}
+}
+// 文字换行
+function drawtext(text, maxWidth) {
+	let textArr = text.split("");
+	let len = textArr.length;
+	// 上个节点
+	let previousNode = 0;
+	// 记录节点宽度
+	let nodeWidth = 0;
+	// 文本换行数组
+	let rowText = [];
+	// 如果是字母,侧保存长度
+	let letterWidth = 0;
+	// 汉字宽度
+	let chineseWidth = 14;
+	// otherFont宽度
+	let otherWidth = 7;
+	for (let i = 0; i < len; i++) {
+		if (/[\u4e00-\u9fa5]|[\uFE30-\uFFA0]/g.test(textArr[i])) {
+			if(letterWidth > 0){
+				if(nodeWidth + chineseWidth + letterWidth * otherWidth > maxWidth){
+					rowText.push({
+						type: "text",
+						content: text.substring(previousNode, i)
+					});
+					previousNode = i;
+					nodeWidth = chineseWidth;
+					letterWidth = 0;
+				} else {
+					nodeWidth += chineseWidth + letterWidth * otherWidth;
+					letterWidth = 0;
+				}
+			} else {
+				if(nodeWidth + chineseWidth > maxWidth){
+					rowText.push({
+						type: "text",
+						content: text.substring(previousNode, i)
+					});
+					previousNode = i;
+					nodeWidth = chineseWidth;
+				}else{
+					nodeWidth += chineseWidth;
+				}
+			}
+		} else {
+			if(/\n/g.test(textArr[i])){
+				rowText.push({
+					type: "break",
+					content: text.substring(previousNode, i)
+				});
+				previousNode = i + 1;
+				nodeWidth = 0;
+				letterWidth = 0;
+			}else if(textArr[i] == "\\" && textArr[i + 1] == "n"){
+				rowText.push({
+					type: "break",
+					content: text.substring(previousNode, i)
+				});
+				previousNode = i + 2;
+				nodeWidth = 0;
+				letterWidth = 0;
+			}else if(/[a-zA-Z0-9]/g.test(textArr[i])){
+				letterWidth += 1;
+				if(nodeWidth + letterWidth * otherWidth > maxWidth){
+					rowText.push({
+						type: "text",
+						content: text.substring(previousNode, i + 1 - letterWidth)
+					});
+					previousNode = i + 1 - letterWidth;
+					nodeWidth = letterWidth * otherWidth;
+					letterWidth = 0;
+				}
+			} else{
+				if(nodeWidth + otherWidth > maxWidth){
+					rowText.push({
+						type: "text",
+						content: text.substring(previousNode, i)
+					});
+					previousNode = i;
+					nodeWidth = otherWidth;
+				}else{
+					nodeWidth += otherWidth;
+				}
+			}
+		}
+	}
+	if (previousNode < len) {
+		rowText.push({
+			type: "text",
+			content: text.substring(previousNode, len)
+		});
+	}
+	return rowText;
+}
+// 是否更新弹窗
+function updatePopup(data, callback) {
+	// 弹窗遮罩层
+	let maskLayer = new plus.nativeObj.View("maskLayer", { //先创建遮罩层
+		top: '0px',
+		left: '0px',
+		height: '100%',
+		width: '100%',
+		backgroundColor: 'rgba(0,0,0,0.5)'
+	});
+
+	// 以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心
+	const screenWidth = plus.screen.resolutionWidth;
+	const screenHeight = plus.screen.resolutionHeight;
+	//弹窗容器宽度
+	const popupViewWidth = screenWidth * 0.7;
+	// 弹窗容器的Padding
+	const viewContentPadding = 20;
+	// 弹窗容器的宽度
+	const viewContentWidth = parseInt(popupViewWidth - (viewContentPadding * 2));
+	// 描述的列表
+	const descriptionList = drawtext(data.versionInfo, viewContentWidth);
+	// 弹窗容器高度
+	let popupViewHeight = 80 + 20 + 20 + 90 + 10;
+	
+	let popupViewContentList = [{
+			src: $iconUrl,
+			id: "logo", 
+			tag: "img",
+			position: {
+				top: "0px",
+				left: (popupViewWidth - 124) / 2 + "px",
+				width: "124px",
+				height: "80px",
+			}
+		},
+		{
+			tag: 'font',
+			id: 'title',
+			text: "发现新版本" + data.versionName,
+			textStyles: {
+				size: '18px',
+				color: "#333",
+				weight: "bold",
+				whiteSpace: "normal"
+			},
+			position: {
+				top: '90px',
+				left: viewContentPadding + "px",
+				width: viewContentWidth + "px",
+				height: "30px",
+			}
+		}];
+	const textHeight = 18;
+	let contentTop = 130;
+	descriptionList.forEach((item,index) => {
+		if(index > 0){
+			popupViewHeight += textHeight;
+			contentTop += textHeight;
+		}
+		popupViewContentList.push({
+			tag: 'font',
+			id: 'content' + index + 1,
+			text: item.content,
+			textStyles: {
+				size: '14px',
+				color: "#666",
+				lineSpacing: "50%",
+				align: "left"
+			},
+			position: {
+				top: contentTop + "px",
+				left: viewContentPadding + "px",
+				width: viewContentWidth + "px",
+				height: textHeight + "px",
+			}
+		});
+		if(item.type == "break"){
+			contentTop += 10;
+			popupViewHeight += 10;
+		}
+	});
+	
+	if(data.updateType == "forcibly"){
+		popupViewContentList.push({
+			tag: 'rect', //绘制底边按钮
+			rectStyles:{
+				radius: "6px",
+				color: $mainColor
+			},
+			position:{
+				bottom: viewContentPadding + 'px',
+				left: viewContentPadding + "px",
+				width: viewContentWidth + "px",
+				height: "30px"
+			}
+		});
+		popupViewContentList.push({
+			tag: 'font',
+			id: 'confirmText',
+			text: "立即升级",
+			textStyles: {
+				size: '14px',
+				color: "#FFF",
+				lineSpacing: "0%",
+			},
+			position: {
+				bottom: viewContentPadding + 'px',
+				left: viewContentPadding + "px",
+				width: viewContentWidth + "px",
+				height: "30px"
+			}
+		});
+	} else {
+		// 绘制底边按钮
+		popupViewContentList.push({
+			tag: 'rect',
+			id: 'cancelBox',
+			rectStyles: {
+				radius: "3px",
+				borderColor: "#f1f1f1",
+				borderWidth: "1px",
+			},
+			position: {
+				bottom: viewContentPadding + 'px',
+				left: viewContentPadding + "px",
+				width: (viewContentWidth - viewContentPadding) / 2 + "px",
+				height: "30px",
+			}
+		});
+		popupViewContentList.push({
+			tag: 'rect',
+			id: 'confirmBox',
+			rectStyles: {
+				radius: "3px",
+				color: $mainColor,
+			},
+			position: {
+				bottom: viewContentPadding + 'px',
+				left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+				width: (viewContentWidth - viewContentPadding) / 2 + "px",
+				height: "30px",
+			}
+		});
+		popupViewContentList.push({
+			tag: 'font',
+			id: 'cancelText',
+			text: "暂不升级",
+			textStyles: {
+				size: '14px',
+				color: "#666",
+				lineSpacing: "0%",
+				whiteSpace: "normal"
+			},
+			position: {
+				bottom: viewContentPadding + 'px',
+				left: viewContentPadding + "px",
+				width: (viewContentWidth - viewContentPadding) / 2 + "px",
+				height: "30px",
+			}
+		});
+		popupViewContentList.push({
+			tag: 'font',
+			id: 'confirmText',
+			text: "立即升级",
+			textStyles: {
+				size: '14px',
+				color: "#FFF",
+				lineSpacing: "0%",
+				whiteSpace: "normal"
+			},
+			position: {
+				bottom: viewContentPadding + 'px',
+				left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+				width: (viewContentWidth - viewContentPadding) / 2 + "px",
+				height: "30px",
+			}
+		});
+	}
+	// 弹窗内容
+	let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单
+		tag: "rect",
+		top: (screenHeight - popupViewHeight) / 2 + "px",
+		left: '15%',
+		height: popupViewHeight + "px",
+		width: "70%"
+	});
+	// 绘制白色背景
+	popupView.drawRect({
+		color: "#FFFFFF",
+		radius: "8px"
+	}, {
+		top: "40px",
+		height: popupViewHeight - 40 + "px",
+	});
+	
+	popupView.draw(popupViewContentList);
+	popupView.addEventListener("click", function(e) {
+		let maxTop = popupViewHeight - viewContentPadding;
+		let maxLeft = popupViewWidth - viewContentPadding;
+		let buttonWidth = (viewContentWidth - viewContentPadding) / 2;
+		if (e.clientY > maxTop - 30 && e.clientY < maxTop) {
+			if(data.updateType == "forcibly"){
+				if(e.clientX > viewContentPadding && e.clientX < maxLeft){
+					// 立即升级
+					maskLayer.hide();
+					popupView.hide();
+					callback && callback();
+				}
+			} else {
+				// 暂不升级
+				if (e.clientX > viewContentPadding && e.clientX < maxLeft - buttonWidth - viewContentPadding) {
+					maskLayer.hide();
+					popupView.hide();
+				} else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
+					// 立即升级
+					maskLayer.hide();
+					popupView.hide();
+					callback && callback();
+				}
+			}
+			
+		}
+	});
+	if(data.updateType == "solicit"){
+		// 点击遮罩层
+		maskLayer.addEventListener("click", function() { //处理遮罩层点击
+			maskLayer.hide();
+			popupView.hide();
+		});
+	}
+	// 显示弹窗
+	maskLayer.show();
+	popupView.show();
+}
+// 文件下载的弹窗绘图
+function downloadPopupDrawing(data){
+	// 以下为计算菜单的nview绘制布局,为固定算法,使用者无关关心
+	const screenWidth = plus.screen.resolutionWidth;
+	const screenHeight = plus.screen.resolutionHeight;
+	//弹窗容器宽度
+	const popupViewWidth = screenWidth * 0.7;
+	// 弹窗容器的Padding
+	const viewContentPadding = 20;
+	// 弹窗容器的宽度
+	const viewContentWidth = popupViewWidth - (viewContentPadding * 2);
+	// 弹窗容器高度
+	let popupViewHeight = viewContentPadding * 3 + 60;
+	let progressTip = data.progressTip || "准备下载...";
+	let contentText = data.contentText || "正在为您更新,请耐心等待";
+	let elementList = [
+		{
+			tag: 'rect', //背景色
+			color: '#FFFFFF',
+			rectStyles:{
+				radius: "8px"
+			}
+		},
+		{
+			tag: 'font',
+			id: 'title',
+			text: "升级APP",
+			textStyles: {
+				size: '16px',
+				color: "#333",
+				weight: "bold",
+				verticalAlign: "middle",
+				whiteSpace: "normal"
+			},
+			position: {
+				top: viewContentPadding + 'px',
+				height: "30px",
+			}
+		},
+		{
+			tag: 'font',
+			id: 'content',
+			text: contentText,
+			textStyles: {
+				size: '14px',
+				color: "#333",
+				verticalAlign: "middle",
+				whiteSpace: "normal"
+			},
+			position: {
+				top: viewContentPadding * 2 + 30 + 'px',
+				height: "20px",
+			}
+		}
+	];
+	// 是否有进度条
+	if(data.progress){
+		popupViewHeight += viewContentPadding + 40;
+		elementList = elementList.concat([
+			{
+				tag: 'font',
+				id: 'progressValue',
+				text: progressTip,
+				textStyles: {
+					size: '14px',
+					color: $mainColor,
+					whiteSpace: "normal"
+				},
+				position: {
+					top: viewContentPadding * 4 + 20 + 'px',
+					height: "30px"
+				}
+			},
+			{
+				tag: 'rect', //绘制进度条背景
+				id: 'progressBg',
+				rectStyles:{
+					radius: "4px",
+					borderColor: "#f1f1f1",
+					borderWidth: "1px",
+				},
+				position:{
+					top: viewContentPadding * 4 + 60 + 'px',
+					left: viewContentPadding + "px",
+					width: viewContentWidth + "px",
+					height: "8px"
+				}
+			},
+		]);
+	}
+	if (data.buttonNum == 2) {
+		popupViewHeight += viewContentPadding + 30;
+		elementList = elementList.concat([
+			{
+				tag: 'rect', //绘制底边按钮
+				rectStyles:{
+					radius: "3px",
+					borderColor: "#f1f1f1",
+					borderWidth: "1px",
+				},
+				position:{
+					bottom: viewContentPadding + 'px',
+					left: viewContentPadding + "px",
+					width: (viewContentWidth - viewContentPadding) / 2 + "px",
+					height: "30px"
+				}
+			},
+			{
+				tag: 'rect', //绘制底边按钮
+				rectStyles:{
+					radius: "3px",
+					color: $mainColor
+				},
+				position:{
+					bottom: viewContentPadding + 'px',
+					left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+					width: (viewContentWidth - viewContentPadding) / 2 + "px",
+					height: "30px"
+				}
+			},
+			{
+				tag: 'font',
+				id: 'cancelText',
+				text: "取消下载",
+				textStyles: {
+					size: '14px',
+					color: "#666",
+					lineSpacing: "0%",
+					whiteSpace: "normal"
+				},
+				position: {
+					bottom: viewContentPadding + 'px',
+					left: viewContentPadding + "px",
+					width: (viewContentWidth - viewContentPadding) / 2 + "px",
+					height: "30px",
+				}
+			},
+			{
+				tag: 'font',
+				id: 'confirmText',
+				text: "后台下载",
+				textStyles: {
+					size: '14px',
+					color: "#FFF",
+					lineSpacing: "0%",
+					whiteSpace: "normal"
+				},
+				position: {
+					bottom: viewContentPadding + 'px',
+					left: ((viewContentWidth - viewContentPadding) / 2 + viewContentPadding * 2) + "px",
+					width: (viewContentWidth - viewContentPadding) / 2 + "px",
+					height: "30px",
+				}
+			}
+		]);
+	}
+	if (data.buttonNum == 1) {
+		popupViewHeight += viewContentPadding + 40;
+		elementList = elementList.concat([
+			{
+				tag: 'rect', //绘制底边按钮
+				rectStyles:{
+					radius: "6px",
+					color: $mainColor
+				},
+				position:{
+					bottom: viewContentPadding + 'px',
+					left: viewContentPadding + "px",
+					width: viewContentWidth + "px",
+					height: "40px"
+				}
+			},
+			{
+				tag: 'font',
+				id: 'confirmText',
+				text: "关闭",
+				textStyles: {
+					size: '14px',
+					color: "#FFF",
+					lineSpacing: "0%",
+				},
+				position: {
+					bottom: viewContentPadding + 'px',
+					left: viewContentPadding + "px",
+					width: viewContentWidth + "px",
+					height: "40px"
+				}
+			}
+		]);
+	}
+	return {
+		popupViewHeight:popupViewHeight,
+		popupViewWidth:popupViewWidth,
+		screenHeight:screenHeight,
+		viewContentWidth:viewContentWidth,
+		viewContentPadding:viewContentPadding,
+		elementList: elementList
+	};
+}
+// 文件下载的弹窗
+function downloadPopup(data) {
+	// 弹窗遮罩层
+	let maskLayer = new plus.nativeObj.View("maskLayer", { //先创建遮罩层
+		top: '0px',
+		left: '0px',
+		height: '100%',
+		width: '100%',
+		backgroundColor: 'rgba(0,0,0,0.5)'
+	});
+	let popupViewData = downloadPopupDrawing(data);
+	// 弹窗内容
+	let popupView = new plus.nativeObj.View("popupView", { //创建底部图标菜单
+		tag: "rect",
+		top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",
+		left: '15%',
+		height: popupViewData.popupViewHeight + "px",
+		width: "70%",
+	});
+	let progressValue = 0;
+	let progressTip = 0;
+	let contentText = 0;
+	let buttonNum = 2;
+	if(data.buttonNum >= 0){
+		buttonNum = data.buttonNum;
+	}
+	popupView.draw(popupViewData.elementList);
+    let callbackData = {
+		change: function(res) {
+			let progressElement = [];
+			if(res.progressValue){
+				progressValue = res.progressValue;
+				// 绘制进度条
+				progressElement.push({
+					tag: 'rect', //绘制进度条背景
+					id: 'progressValueBg',
+					rectStyles:{
+						radius: "4px",
+						color: $mainColor
+					},
+					position:{
+						top: popupViewData.viewContentPadding * 4 + 60 + 'px',
+						left: popupViewData.viewContentPadding + "px",
+						width: popupViewData.viewContentWidth * (res.progressValue / 100) + "px",
+						height: "8px"
+					}
+				});
+			}
+			if(res.progressTip){
+				progressTip = res.progressTip;
+				progressElement.push({
+					tag: 'font',
+					id: 'progressValue',
+					text: res.progressTip,
+					textStyles: {
+						size: '14px',
+						color: $mainColor,
+						whiteSpace: "normal"
+					},
+					position: {
+						top: popupViewData.viewContentPadding * 4 + 20 + 'px',
+						height: "30px"
+					}
+				});
+			}
+			if(res.contentText){
+				contentText = res.contentText;
+				progressElement.push({
+					tag: 'font',
+					id: 'content',
+					text: res.contentText,
+					textStyles: {
+						size: '16px',
+						color: "#333",
+						whiteSpace: "normal"
+					},
+					position: {
+						top: popupViewData.viewContentPadding * 2 + 30 + 'px',
+						height: "30px",
+					}
+				});
+			}
+			if(res.buttonNum >= 0 && buttonNum != res.buttonNum){
+				buttonNum = res.buttonNum;
+				popupView.reset();
+				popupViewData = downloadPopupDrawing(Object.assign({
+					progressValue:progressValue,
+					progressTip:progressTip,
+					contentText:contentText,
+				},res));
+				let newElement = [];
+				popupViewData.elementList.map((item,index) => {
+					let have = false;
+					progressElement.forEach((childItem,childIndex) => {
+						if(item.id == childItem.id){
+							have = true;
+						}
+					});
+					if(!have){
+						newElement.push(item);
+					}
+				});
+				progressElement = newElement.concat(progressElement);
+				popupView.setStyle({
+					tag: "rect",
+					top: (popupViewData.screenHeight - popupViewData.popupViewHeight) / 2 + "px",
+					left: '15%',
+					height: popupViewData.popupViewHeight + "px",
+					width: "70%",
+				});
+				popupView.draw(progressElement); 
+			}else{
+				popupView.draw(progressElement);
+			}
+		},
+		cancel: function() { 
+			maskLayer.hide();
+			popupView.hide();
+		}
+	}
+	popupView.addEventListener("click", function(e) {
+		let maxTop = popupViewData.popupViewHeight - popupViewData.viewContentPadding;
+		let maxLeft = popupViewData.popupViewWidth - popupViewData.viewContentPadding;
+		if (e.clientY > maxTop - 40 && e.clientY < maxTop) {
+			if(buttonNum == 1){
+				// 单按钮
+				if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft) {
+					maskLayer.hide();
+					popupView.hide();
+                    callbackData.reboot();
+				}
+			}else if(buttonNum == 2){
+				// 双按钮
+				let buttonWidth = (popupViewData.viewContentWidth - popupViewData.viewContentPadding) / 2;
+				if (e.clientX > popupViewData.viewContentPadding && e.clientX < maxLeft - buttonWidth - popupViewData.viewContentPadding) {
+					maskLayer.hide();
+					popupView.hide();
+                    callbackData.cancelDownload();
+				} else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
+					maskLayer.hide();
+					popupView.hide();
+				}
+			}
+		}
+	});
+	// 显示弹窗
+	maskLayer.show();
+	popupView.show();
+	// 改变进度条
+	return callbackData;
+}
+export default function(isPrompt = false) {
+	getCurrentNo(versionInfo => {
+		componentConfig.getServerNo(versionInfo, isPrompt, res => {
+			if (res.updateType == "forcibly" || res.updateType == "silent") {
+				if (/\.wgt$/i.test(res.downloadUrl)) {
+					getDownload(res);
+				} else if(/\.html$/i.test(res.downloadUrl)){
+					plus.runtime.openURL(res.downloadUrl);
+				} else {
+					if (platform == "android") {
+						getDownload(res);
+					} else {
+						plus.runtime.openURL(res.downloadUrl);
+					}
+				}
+			} else if(res.updateType == "solicit"){
+				updatePopup(res, function() {
+					if (/\.wgt$/i.test(res.downloadUrl)) {
+						getDownload(res);
+					} else if(/\.html$/i.test(res.downloadUrl)){
+						plus.runtime.openURL(res.downloadUrl);
+					} else {
+						if (platform == "android") {
+							getDownload(res);
+						} else {
+							plus.runtime.openURL(res.downloadUrl);
+						}
+					}
+				});
+			}
+		});
+	});
+}
+// #endif

+ 79 - 0
uni_modules/zhouWei-APPUpdate/package.json

@@ -0,0 +1,79 @@
+{
+  "id": "zhouWei-APPUpdate",
+  "displayName": "APP版本更新、强制更新、静默更新、下载进度(wgt更新)",
+  "version": "3.0.1",
+  "description": "APP版本更新、强制更新、静默更新、漂亮弹窗、下载进度(wgt更新)",
+  "keywords": [
+    "APP版本更新",
+    "强制更新",
+    "版本更新",
+    "静默更新"
+],
+  "repository": "https://github.com/zhouwei1994/uni-app-demo",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+  "dcloudext": {
+    "category": [
+        "JS SDK",
+        "通用 SDK"
+    ],
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": "465081029"
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "<uses-permission android:name=\\\"android.permission.INSTALL_PACKAGES\\\"/>  \n<uses-permission android:name=\\\"android.permission.REQUEST_INSTALL_PACKAGES\\\"/>"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "n",
+          "Android Browser": "n",
+          "微信浏览器(Android)": "n",
+          "QQ浏览器(Android)": "n"
+        },
+        "H5-pc": {
+          "Chrome": "n",
+          "IE": "n",
+          "Edge": "n",
+          "Firefox": "n",
+          "Safari": "n"
+        },
+        "小程序": {
+          "微信": "n",
+          "阿里": "n",
+          "百度": "n",
+          "字节跳动": "n",
+          "QQ": "n"
+        },
+        "快应用": {
+          "华为": "n",
+          "联盟": "n"
+        }
+      }
+    }
+  }
+}

+ 162 - 0
uni_modules/zhouWei-APPUpdate/readme.md

@@ -0,0 +1,162 @@
+# APP版本更新、强制更新、漂亮的更新界面、IOS更新(跳转IOS store)、wgt更新
+
+| `QQ交流群(607391225)`         | `微信交流群(加我好友备注"进群")`                  |
+| ----------------------------|--------------------------- |
+|![QQ交流群](http://qn.kemean.cn//upload/202004/14/15868301778472k7oubi6.png)|![微信交流群](https://qn.kemean.cn/upload/202010/13/weiXin_group_code.jpg)|
+| QQ群号:607391225 |微信号:zhou0612wei|
+
+### [点击跳转-插件示例](https://ext.dcloud.net.cn/plugin?id=2009)
+### [点击跳转-5年的web前端开源的uni-app快速开发模板-下载看文档](https://ext.dcloud.net.cn/plugin?id=2009)
+ 
+### 常见问题
+1.安卓apk下载完成后没有更新APP?
+
+答:问题是因为没有添加APP安装应用的权限,解决方法在`manifest.json`文件里面`APP模块权限配置`的`Android打包权限配置`勾选以下权限
+```
+<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
+<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>
+```
+若还有问题请看[安装apk无法执行的解决方案](https://ask.dcloud.net.cn/article/35703 "安装apk无法执行的解决方案")
+
+2.APP更新后版本号没变,还是之前的版本号?
+
+答:可能是更新的安装包没有升级版本号,`manifest.json`文件里面基本设置`应用版本号`和`应用版本名称`需要升高(保持一直减少问题)
+
+3.APP更新后没有覆盖之前的APP?
+
+答:可能是更新的安装包`包名`和APP的`包名`不一样
+
+4.弹窗的图标不显示?
+
+答:检查图片是不是放项目资源文件`static`,然后重新运行项目
+
+5.版本号是在前端对比还是在后端接口对比?
+
+答:当前案例是本地的版本号通过接口传递给后台,是后台对比的,若需要前端对比,请在接口返回数据的地方修改,不更新就不要调用`callback`方法
+
+6.本地的版本号比接口的版本号高还弹窗升级窗口?
+
+答:当前案例是本地的版本号通过接口传递给后台,后台对比是否需要升级,不需要升级就不要返回数据(特别是需要wgt更新的,建议这种方式)
+
+### 第一步`关键`配置APP更新接口(可以参考上面的示例)
+在项目目录下`config/componentConfig.js`里面如下配置
+```
+// 此方法是接口请求方法
+import $http from '@/config/requestConfig'
+export default {
+	// 发起ajax请求获取服务端版本号
+	getServerNo: (version, isPrompt = false, callback) => {
+		let httpData = {
+			version: version.versionCode,
+			// 版本名称
+		    versionName: version.versionName,
+			// setupPage参数说明(判断用户是不是从设置页面点击的更新,如果是设置页面点击的更新,有不要用静默更新了,不然用户点击没反应很奇怪的)
+			setupPage: isPrompt   
+		};
+		if (platform == "android") {
+			httpData.type = 1101;
+		} else {
+			httpData.type = 1102;
+		}
+		/* 接口入参说明
+		 * version: 应用当前版本号(已自动获取)
+		 * versionName: 应用当前版本名称(已自动获取)
+		 * type:平台(1101是安卓,1102是IOS)
+		 */
+		/****************以下是示例*******************/
+		// 可以用自己项目的请求方法(接口自己找后台要,插件不提供)
+		$http.get("api/common/v1/app_version", httpData,{
+			isPrompt: isPrompt
+		}).then(res => {
+			/* res的数据说明
+			 * | 参数名称	     | 一定返回 	| 类型	    | 描述
+			 * | -------------|--------- | --------- | ------------- |
+			 * | versionCode	 | y	    | int	    | 版本号        |
+			 * | versionName	 | y	    | String	| 版本名称      |
+			 * | versionInfo	 | y	    | String	| 版本信息      |
+			 * | updateType	     | y	    | String	| forcibly = 强制更新, solicit = 弹窗确认更新, silent = 静默更新 |
+			 * | downloadUrl	 | y	    | String	| 版本下载链接(IOS安装包更新请放跳转store应用商店链接,安卓apk和wgt文件放文件下载链接)  |
+			 */
+			if (res && res.downloadUrl) {
+				// 兼容之前的版本(updateType是新版才有的参数)
+				if(res.updateType){
+					callback && callback(res);
+				} else {
+					if(res.forceUpdate){
+						res.updateType = "forcibly";
+					} else {
+						res.updateType = "solicit";
+					}
+					callback && callback(res);
+				}
+			} else if (isPrompt) {
+				uni.showToast({
+					title: "暂无新版本",
+					icon: "none"
+				});
+			}
+		});
+		/****************以上是示例*******************/
+	},
+	// 弹窗主颜色(不填默认粉色)
+	appUpdateColor: "f00",
+	// 弹窗图标(不填显示默认图标,链接配置示例如: '/static/demo/ic_attention.png')
+	appUpdateIcon: ''
+}
+```
+
+### 第二步 使用方法
+``` 
+// App.vue页面
+
+// #ifdef APP-PLUS
+import APPUpdate from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';
+// #endif
+
+onLaunch: function(e) {
+	// #ifdef APP-PLUS
+	APPUpdate();
+	// #endif
+}
+```
+
+### 第三步 添加APP安装应用的权限
+在`manifest.json`文件里面`APP模块权限配置`的`Android打包权限配置`勾选以下权限
+```
+<uses-permission android:name=\"android.permission.INSTALL_PACKAGES\"/>  
+<uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\"/>
+```
+
+### 修改弹窗的主题色或弹窗图标
+在`APPUpdate/index.js`里面上面`$mainColor`常量中定义主题颜色,`$iconUrl`常量中定义图标地址
+
+### 检查APP是否有新版本(一般在设置页面使用)
+```
+// #ifdef APP-PLUS
+import APPUpdate, { getCurrentNo } from '@/uni_modules/zhouWei-APPUpdate/js_sdk/appUpdate';
+// #endif
+export default {
+	data() {
+		return {
+			version: "" // 版本号
+		};
+	},
+	//第一次加载
+	onLoad(e) {
+		// #ifdef APP-PLUS
+		getCurrentNo(res => {
+			// 进页面获取当前APP版本号(用于页面显示)
+			this.version = res.version;
+		});
+		// #endif
+	},
+	//方法
+	methods: {
+		// 检查APP是否有新版本
+		onAPPUpdate() {
+			// true 没有新版本的时候有提示,默认:false
+			APPUpdate(true);
+		}
+	}
+}
+```

BIN=BIN
uni_modules/zhouWei-APPUpdate/static/ic_ar.png