lilishop-uniapp/plugins/APPUpdate/index.js

901 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// #ifdef APP-PLUS
/**** 此文件说明请看注释 *****/
// 可以用自己项目的请求方法
// 请求配置说明https://ext.dcloud.net.cn/plugin?id=822
import { getAppVersion } from "@/api/message.js";
const platform = uni.getSystemInfoSync().platform;
// 主颜色
const $mainColor = "#1ABC9C";
// 弹窗图标url
const $iconUrl =
"https://lilishop-oss.oss-cn-beijing.aliyuncs.com/app/upgrade.png";
// 获取当前应用的版本号
export const getCurrentNo = function (callback) {
// 获取本地应用资源版本号
plus.runtime.getProperty(plus.runtime.appid, function (inf) {
callback &&
callback({
versionCode: inf.version.replace(/\./g, ""),
version: inf.version,
});
});
};
// 发起ajax请求获取服务端版本号
export const getServerNo = function (callback) {
let type;
platform == "android" ? (type = "ANDROID") : (type = "IOS");
getAppVersion(type).then((res) => {
if (res.data.success && res.data.result.downloadUrl) {
let response = res.data.result;
let result = {};
result.versionCode = response.version;
result.versionName = response.versionName;
result.versionInfo = response.content || "暂无";
result.forceUpdate = response.forceUpdate;
result.downloadUrl = response.downloadUrl;
callback && callback(result);
}
});
};
// 从服务器下载应用资源包wgt文件
export const getDownload = function (data) {
let popupData = {
progress: true,
buttonNum: 2,
};
if (data.forceUpdate) {
popupData.buttonNum = 0;
popupData.forceUpdate = data.forceUpdate;
}
let dtask;
let lastProgressValue = 0;
downloadPopup(
popupData,
function (res) {
dtask = plus.downloader.createDownload(
data.downloadUrl,
{
filename: "_doc/update/",
},
function (download, status) {
if (status == 200) {
res.change({
progressValue: 100,
progressTip: "正在安装文件...",
progress: true,
buttonNum: 0,
});
plus.runtime.install(
download.filename,
{},
function () {
res.change({
contentText: "应用资源更新完成!",
buttonNum: 1,
progress: false,
});
},
function (e) {
res.cancel();
plus.nativeUI.alert(
"安装文件失败[" + e.code + "]" + e.message
);
}
);
} else {
res.change({
contentText: "文件下载失败...",
buttonNum: 1,
progress: false,
});
}
}
);
dtask.start();
dtask.addEventListener("statechanged", function (task, status) {
switch (task.state) {
case 1: // 开始
res.change({
progressValue: 0,
progressTip: "准备下载...",
progress: true,
});
break;
case 2: // 已连接到服务器
res.change({
progressValue: 0,
progressTip: "开始下载...",
progress: true,
});
break;
case 3:
const progress = parseInt(
(task.downloadedSize / task.totalSize) * 100
);
if (progress - lastProgressValue >= 2) {
lastProgressValue = progress;
res.change({
progressValue: progress,
progressTip: "已下载" + progress + "%",
progress: true,
});
}
break;
}
});
},
function () {
// 取消下载
dtask && dtask.abort();
uni.showToast({
title: "已取消下载",
icon: "none",
});
},
function () {
// 重启APP
plus.runtime.restart();
}
);
};
// 文字换行
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)",
});
let downloadUrl = data.downloadUrl;
// 以下为计算菜单的nview绘制布局为固定算法使用者无关关心
const screenWidth = plus.screen.resolutionWidth;
const screenHeight = plus.screen.resolutionHeight;
//弹窗容器宽度
const popupViewWidth = screenWidth * 0.8;
// 弹窗容器的Padding
const viewContentPadding = 20;
// 弹窗容器的宽度
const viewContentWidth = parseInt(popupViewWidth - viewContentPadding * 5);
// 描述的列表
const descriptionList = drawtext(data.versionInfo, viewContentWidth);
// 弹窗容器高度
let popupViewHeight = 400;
let popupViewContentList = [
{
src: $iconUrl,
id: "logo",
tag: "img",
},
{
tag: "font",
id: "title",
text: "V" + data.versionCode,
textStyles: {
size: "26px",
color: "#fff",
weight: "700",
},
position: {
top: "60px",
left: "64px",
height: "20px",
},
},
{
tag: "font",
id: "welcome",
text: "欢迎体验",
textStyles: {
size: "16px",
color: "#fff",
weight: "400",
},
position: {
top: "85px",
left: "64px",
height: "20px",
},
},
];
const textHeight = 18;
let contentTop = popupViewHeight / 2 + 16;
popupViewContentList.push({
tag: "font",
id: "content-title",
text: "新版本特性:",
textStyles: {
size: "20px",
lineSpacing: "50%",
align: "left",
},
position: {
top: popupViewHeight / 2 - 24 + "px",
left: viewContentPadding + "px",
width: viewContentWidth + "px",
height: textHeight + "px",
},
});
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;
}
});
// 弹窗内容
let popupView = new plus.nativeObj.View("popupView", {
//创建底部图标菜单
tag: "rect",
top: (screenHeight - popupViewHeight) / 2 + "px",
left: "10%",
height: popupViewHeight + "px",
width: "80%",
});
// 绘制白色背景
popupView.drawRect(
{
color: "#FFFFFF",
radius: "8px",
},
{
top: "40px",
height: popupViewHeight - 40 + "px",
}
);
// 绘制底边按钮
popupView.drawRect(
{
radius: "3px",
borderColor: "#f1f1f1",
borderWidth: "1px",
},
{
bottom: viewContentPadding + "px",
left: viewContentPadding + "px",
width: (viewContentWidth - viewContentPadding) / 2 + "px",
height: "30px",
}
);
// 绘制底边按钮
popupView.drawRect(
{
radius: "3px",
color: $mainColor,
borderColor: $mainColor,
},
{
bottom: viewContentPadding + "px",
left:
(viewContentWidth - viewContentPadding) / 2 +
viewContentPadding * 2 +
"px",
width: (viewContentWidth - viewContentPadding) / 2 + "px",
height: "30px",
}
);
popupViewContentList.push({
tag: "rect",
id: "confimBtn",
rectStyles: {
color: $mainColor,
radius: "3px",
},
position: {
bottom: viewContentPadding + "px",
left: (viewContentWidth - viewContentPadding) / 3 + "px",
width: viewContentWidth - viewContentPadding + "px",
height: "40px",
},
});
popupViewContentList.push({
tag: "font",
id: "confirmText",
text: "立即更新",
textStyles: {
size: "18px",
color: "#fff",
lineSpacing: "0%",
whiteSpace: "normal",
},
position: {
bottom: viewContentPadding + "px",
left: (viewContentWidth - viewContentPadding) / 3 + "px",
width: viewContentWidth - viewContentPadding + "px",
height: "40px",
},
});
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 (
e.clientX > viewContentPadding &&
e.clientX < maxLeft - buttonWidth - viewContentPadding
) {
// 立即升级
if (platform == "android") {
maskLayer.hide();
popupView.hide();
callback && callback();
} else {
if (!data.forceUpdate) {
maskLayer.hide();
popupView.hide();
}
plus.runtime.openURL(downloadUrl);
}
} else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
// 立即升级
if (platform == "android") {
maskLayer.hide();
popupView.hide();
callback && callback();
} else {
if (!data.forceUpdate) {
maskLayer.hide();
popupView.hide();
}
plus.runtime.openURL(downloadUrl);
}
}
}
});
// 点击遮罩层
maskLayer.addEventListener("click", function () {
//处理遮罩层点击
if (!data.forceUpdate) {
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, callback, cancelCallback, rebootCallback) {
// 弹窗遮罩层
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;
let forceUpdate = data.forceUpdate;
if (data.buttonNum >= 0) {
buttonNum = data.buttonNum;
}
popupView.draw(popupViewData.elementList);
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();
}
} 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();
//cancelCallback && cancelCallback();
} else if (e.clientX > maxLeft - buttonWidth && e.clientX < maxLeft) {
maskLayer.hide();
popupView.hide();
}
}
}
});
// 显示弹窗
maskLayer.show();
popupView.show();
// 改变进度条
callback({
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();
},
});
}
export default function (isPrompt = false) {
getCurrentNo((version) => {
getServerNo((res) => {
if (res.versionCode.replace(/\./g, "") <= version.version) {
return false;
}
if (res.forceUpdate) {
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 {
updatePopup(res, function () {
plus.runtime.openURL(res.downloadUrl);
});
// uni.showLoading({
// title: "升级中......",
// mask: true
// });
// plus.runtime.openURL(res.downloadUrl);
// plus.runtime.restart();
}
}
} else {
updatePopup(res, function () {
if (/\.wgt$/i.test(res.downloadUrl)) {
getDownload(res);
} else if (/\.html$/i.test(res.downloadUrl)) {
plus.runtime.openURL(res.downloadUrl);
} else {
getDownload(res);
// if (platform == "android") {
// getDownload(res);
// } else {
// plus.runtime.openURL(res.downloadUrl);
// }
}
});
}
});
});
}
// #endif