VersionUpdate.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <template>
  2. <uv-popup
  3. ref="popupRef"
  4. mode="center"
  5. bgColor="none"
  6. round="20rpx"
  7. :close-on-click-overlay="false"
  8. @change="popupChange"
  9. >
  10. <view class="version-update">
  11. <view class="version-update-content">
  12. <view class="content-form">
  13. <view class="title">发现最新版本</view>
  14. <view class="value">V{{ appInfo.version }}</view>
  15. </view>
  16. <view class="content-form">
  17. <view class="title">更新描述:</view>
  18. <view class="value">
  19. <view
  20. class="value-text"
  21. v-for="(item, index) in description"
  22. :key="index"
  23. >{{ item }}</view
  24. >
  25. </view>
  26. </view>
  27. <view v-if="startProgress" class="smallTitle">
  28. <view>下载进度:{{ downloadProgress }}%</view>
  29. <uv-line-progress
  30. active-color="#eb5153"
  31. :percentage="downloadProgress"
  32. >
  33. </uv-line-progress>
  34. </view>
  35. <button class="u-btn-two" @click.stop="handleUpdate">立即更新</button>
  36. </view>
  37. <view class="version-update-close" v-if="!appInfo.status">
  38. <uv-icon
  39. name="close-circle"
  40. color="#c4c4c4"
  41. size="28"
  42. @click="closePopup"
  43. ></uv-icon>
  44. </view>
  45. </view>
  46. </uv-popup>
  47. </template>
  48. <script setup name="VersionUpdate">
  49. import { ref, onMounted, nextTick } from "vue";
  50. import { appVersionNewest_Api } from "@/api/index.js";
  51. const $props = defineProps({
  52. open: { type: Boolean, default: true },
  53. });
  54. const $emit = defineEmits(["setAppInfo"]);
  55. const popupRef = ref(null);
  56. const appInfo = ref({});
  57. const startProgress = ref(false);
  58. const downloadProgress = ref(0);
  59. const packgePath = ref("");
  60. const type = ref(0); // 0: android, 1: ios
  61. const description = ref([]); // 更新描述
  62. const downloadTask = ref(null);
  63. const installed = ref(false);
  64. // 获取更新信息
  65. const getAppInfo = () => {
  66. appVersionNewest_Api({ type: type.value }).then((res) => {
  67. // console.log(res);
  68. if (res && res.code == 200) {
  69. appInfo.value = res.data || {};
  70. const systemInfo = uni.getSystemInfoSync();
  71. // console.log(systemInfo);
  72. if (appInfo.value.description) {
  73. // 将描述按\n分割成数组
  74. description.value = appInfo.value.description.split("\n");
  75. }
  76. let appUpdate = false;
  77. if (
  78. (systemInfo.appVersionCode || 0) * 1 <
  79. (appInfo.value.level || 0) * 1
  80. ) {
  81. appUpdate = true;
  82. if ($props.open) {
  83. nextTick(() => {
  84. popupRef.value.open();
  85. });
  86. try {
  87. uni.hideTabBar();
  88. } catch (error) {}
  89. }
  90. }
  91. nextTick(() => {
  92. $emit("setAppInfo", {
  93. version: systemInfo.appVersion, // app版本号
  94. appUpdate: appUpdate, // 是否有新版本
  95. });
  96. });
  97. }
  98. });
  99. };
  100. // 开始下载任务
  101. const createTask = (downloadLink) => {
  102. console.log("下载链接" + downloadLink);
  103. downloadProgress.value = 0;
  104. startProgress.value = true;
  105. // 创建下载任务对象
  106. downloadTask.value = uni.downloadFile({
  107. url: downloadLink,
  108. success: (res) => {
  109. // console.log("下载成功", res);
  110. if (res.statusCode === 200) {
  111. // 保存下载的安装包
  112. uni.saveFile({
  113. tempFilePath: res.tempFilePath,
  114. success: (res) => {
  115. packgePath.value = res.savedFilePath;
  116. // 进行安装
  117. installPackge();
  118. // 任务完成,关闭下载任务
  119. closeTask();
  120. },
  121. });
  122. }
  123. },
  124. });
  125. downloadTask.value.onProgressUpdate((res) => {
  126. downloadProgress.value = res.progress;
  127. // uni.$forceUpdate();
  128. // console.log(res.progress);
  129. });
  130. };
  131. // 关闭下载任务
  132. const closeTask = () => {
  133. downloadTask.value.abort();
  134. downloadTask.value = null;
  135. startProgress.value = false;
  136. };
  137. const installPackge = () => {
  138. // 安装更新
  139. plus.runtime.install(packgePath.value, {
  140. force: true,
  141. });
  142. installed.value = true;
  143. // 保存更新记录到stroage,方便下次启动app时删除安装包
  144. uni.setStorage({
  145. key: "updated",
  146. data: {
  147. completed: true,
  148. packgePath: packgePath.value,
  149. },
  150. success: (res) => {
  151. console.log("成功保存更新记录");
  152. // console.log(res.data)
  153. },
  154. });
  155. // 判断是否为热更新(判断文件名中是否含有.wgt)
  156. // console.log(8888888888888888888888 + packgePath.value);
  157. if (packgePath.value.match(RegExp(/.wgt/))) {
  158. // console.log("9999999999999");
  159. installed.value = false;
  160. uni.showModal({
  161. title: "提示",
  162. content: "应用将重启以完成更新",
  163. showCancel: false,
  164. complete: () => {
  165. plus.runtime.restart();
  166. },
  167. });
  168. }
  169. };
  170. const handleUpdate = () => {
  171. // console.log("startProgress.value", startProgress.value);
  172. if (startProgress.value) {
  173. uni.$uv.toast("请稍等,正在下载更新");
  174. return;
  175. }
  176. // 判断系统类型
  177. if (plus.os.name.toLowerCase() === "android") {
  178. if (appInfo.value.downloadLink && appInfo.value.downloadLink !== "#") {
  179. createTask(appInfo.value.downloadLink);
  180. } else {
  181. uni.$uv.toast("未找到下载地址");
  182. }
  183. } else {
  184. if (appInfo.value.ios_link && appInfo.value.ios_link !== "#") {
  185. // 我这里默认#也是没有地址,请根据业务自行修改
  186. // 苹果(A):进行热更新(如果iosUrl是wgt更新包的下载地址)判断文件名中是否含有.wgt
  187. if (appInfo.value.ios_link.match(RegExp(/.wgt/))) {
  188. createTask(appInfo.value.ios_link);
  189. } else {
  190. // 苹果(B):打开商店链接(如果iosUrl是苹果商店的地址)
  191. plus.runtime.openURL(appInfo.value.ios_link);
  192. }
  193. } else {
  194. uni.$uv.toast("未找到ios商店地址");
  195. }
  196. }
  197. };
  198. const popupChange = (e) => {
  199. if (!e.show) {
  200. uni.showTabBar();
  201. }
  202. };
  203. const closePopup = () => {
  204. popupRef.value.close();
  205. };
  206. const open = () => {
  207. popupRef.value.open();
  208. };
  209. onMounted(() => {
  210. console.log("onLoad");
  211. // #ifdef APP-PLUS
  212. type.value = plus.os.name.toLowerCase() === "android" ? 0 : 1;
  213. // #endif
  214. getAppInfo();
  215. });
  216. defineExpose({
  217. open,
  218. });
  219. </script>
  220. <style scoped lang="scss">
  221. .version-update {
  222. .version-update-content {
  223. width: 487rpx;
  224. min-height: 451rpx;
  225. border-radius: 20px;
  226. background: url("@/static/version_bg.png") no-repeat;
  227. background-size: 100% 100%;
  228. box-sizing: border-box;
  229. padding: 124rpx 30rpx 67rpx 30rpx;
  230. .content-form {
  231. margin-bottom: 40rpx;
  232. .title {
  233. font-size: 34rpx;
  234. font-family: PingFang SC, PingFang SC-Bold;
  235. font-weight: 700;
  236. text-align: left;
  237. color: #1a1a1a;
  238. margin-bottom: 5rpx;
  239. }
  240. .value {
  241. font-size: 28rpx;
  242. color: #808080;
  243. .value-text {
  244. position: relative;
  245. padding-left: 20rpx;
  246. &::after {
  247. content: "";
  248. width: 8rpx;
  249. height: 8rpx;
  250. background: #808080;
  251. border-radius: 50%;
  252. position: absolute;
  253. left: 0;
  254. top: 16rpx;
  255. }
  256. }
  257. }
  258. }
  259. .smallTitle {
  260. padding-bottom: 30rpx;
  261. text-align: center;
  262. }
  263. .u-btn-two {
  264. }
  265. }
  266. .version-update-close {
  267. display: flex;
  268. justify-content: center;
  269. margin-top: 30rpx;
  270. }
  271. }
  272. </style>