当前位置: 首页 > news >正文

网站开发编译器站长之家

网站开发编译器,站长之家,徐州双语网站制作,珠海做网站设计实现登录即更新,或实时监听更新 本文介绍的是在App打开启动的时候调用更新,点击下方链接,查看使用WebSocket实现实时通知在线用户更新。 uniapp:全局消息是推送,实现app在线更新,WebSocket,ap…

实现登录即更新,或实时监听更新

本文介绍的是在App打开启动的时候调用更新,点击下方链接,查看使用WebSocket实现实时通知在线用户更新。

uniapp:全局消息是推送,实现app在线更新,WebSocket,apk上传:

登录更新流程

    • 1.在app每次启动的时候请求java后端,
    • 2.后端接口获取最新的版本:
    • 3.打开更新页面
    • 4.后端下载接口去指定目录下载apk

在这里插入图片描述

  • 背景:内部手持机app开发功能,需要更新的到车间各个手持机上。
  • 最初的方案:开发人员开发完后,去现成给每台手持机安装更新
  • 设想:实现在线发布,手持机检测版本后更新。

实现手持机更新
1.发布到应用商店
2.uiniapp自带版本更新
3.自己开发功能,检测需要更新后从自己的服务器上下载下来更新

这里我们选择自己开发,毕竟不需要证书,和依托于其他平台

app更新更新我们需要解决哪些问题?

1app什么时候知道自己需要更新?
2检测到需要更新后从哪里获取文件?
3如果app一直在线运行,如何实时通知它需要更新?

下面我们逐一解决:
1app什么时候知道自己需要更新?

这里我们使用的是在app每次打开的时候去请求我们后台的接口,拿到最新的app版本(自己定义的),和当前app的版本进行比较。

前提是,你在自己的服务器上上传了apk之后并且记录了在自己的业务表里面。这样你才能比较是否需要更新。(意思就是最好你维护一张表,每次上传插入一条记录)

在这里插入图片描述
实现:

1.在app每次启动的时候请求java后端,

因此要卸载App.vue里面

<script>function requestToJavaBackend() {uni.request({url: 'http://*.*.*.*:8080/app/getNewestVersion', // 替换成你的后端 Java 服务的API地址method: 'GET', // 或 'POST',根据你的需求选择请求方法success: (res) => {if(res.data.code === 200){console.log(res.data.data);console.log();console.log(uni.getSystemInfoSync().appVersion+"111111111");console.log();console.log(uni.getSystemInfoSync().appVersionCode+"222222");console.log(platform+"33333333333333333333")const newVersionName = res.data.data.newVersionName //线上最新版本名const newVersionCode = res.data.data.newVersionCode; //线上最新版本号// const selfVersionCode = Number(uni.getSystemInfoSync().appVersion) //当前App版本号 const selfVersionCode = Number(uni.getSystemInfoSync().appVersionCode) //当前App版本号const platform = uni.getSystemInfoSync().platform //手机平台//线上版本号高于当前,进行在线升级if (selfVersionCode < newVersionCode) {//安卓手机弹窗升级 platform === 'android'   || windows// uni.navigateTo({// 	url: '/pages/index/upgrade'// })if (platform === 'android') {uni.navigateTo({url: '/pages/index/upgrade'})} else {uni.showModal({title: '发现新版本 ' + newVersionName,content: '请到App store进行升级',showCancel: false})}}}else{uni.showModal({title: '版本校验错误',content: '版本校验错误,联系管理员',showCancel: false})}},fail: (err) => {uni.showModal({title: '版本校验错误',content: '版本校验错误,联系管理员',showCancel: false})// 在这里处理请求失败后的逻辑},});}export default {onLaunch() {// 加载系统信息this.$store.dispatch('SystemInfo');// 在应用启动时执行一次任务requestToJavaBackend()// 每隔一段时间执行一次任务// setInterval(() => {// 	requestToJavaBackend()// }, 5000); // 30秒},onShow() {},onHide() {},methods: {},}
</script><style lang="scss">@import "@/uni_modules/uview-ui/index.scss";@import "@/static/style.scss";
</style>

2.后端接口获取最新的版本:

@GetMapping("/getNewestVersion")public AjaxResult getNewestVersion(){HashMap<String, Object> map = new HashMap<>();map.put("newVersionName", "v");map.put("newVersionCode", 2);//你的最新版本,建议每次开发完上传之后放在表里,然后去表里拿最新的记录,的版本号return AjaxResult.success(map);}

这里检测到2>1之后,就要打开更新页面强制更新(当然你可以不更新,看业务需求)

3.打开更新页面

注意从自己的服务器下载,当前版本小于服务器版本,跳转下载。

自定义下载地址:this.downloadUrl = ‘http://...:8080/app/download’; //下载链接

目录结构
在这里插入图片描述
upgrade.vue 更新弹窗

<template><view class="upgrade-popup"><image class="header-bg" src="" mode="widthFix"></image><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" ><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() {this.init()},onBackPress(options) {// 禁用返回if (options.from == 'backbutton') {return true;}},methods: {//初始化获取最新APP版本信息init() {//模拟接口获取setTimeout(() => {//演示数据请根据实际修改this.versionName = 'V1.2.0'; //版本名称this.versionDesc = "修复若干bug"; //更新说明this.downloadUrl = 'http://*.*.*.*:8080/app/download'; //下载链接this.isForceUpdate = false; //是否强制更新}, 200)},//更新handleUpgrade() {if (this.downloadUrl) {this.isStartDownload = true//开始下载AppdownloadApp(this.downloadUrl, current => {//下载进度监听this.hasProgress = truethis.currentPercent = current}).then(fileName => {//下载完成this.isDownloadFinish = truethis.fileName = fileNameif (fileName) {//自动安装Appthis.handleInstallApp()}}).catch(e => {console.log(e, 'e')})} else {uni.showToast({title: '下载链接不存在',icon: 'none'})}},//安装apphandleInstallApp() {//下载完成才能安装,防止下载过程中点击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); //注册广播}

4.后端下载接口去指定目录下载apk

@GetMapping("/download")public void download(String path, HttpServletResponse response) {try {//拿到最新的版本//SysAppVersion 是我自己表的实体,我每次上传后会在这个表里插入一条记录//下载的时候拿最新的SysAppVersion newestVersion = sysAppVersionService.getNewestVersion();File file = new File("d://app//"+newestVersion.getFileName());String filename = file.getName();String ext = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();FileInputStream fileInputStream = new FileInputStream(file);InputStream fis = new BufferedInputStream(fileInputStream);byte[] buffer = new byte[fis.available()];fis.read(buffer);fis.close();response.reset();// 设置response的Headerresponse.setCharacterEncoding("UTF-8");//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存//attachment表示以附件方式下载 inline表示在线打开 "Content-Disposition: inline; filename=文件名.mp3"// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));// 告知浏览器文件的大小response.addHeader("Content-Length", "" + file.length());OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());response.setContentType("application/octet-stream");outputStream.write(buffer);outputStream.flush();} catch (IOException ex) {ex.printStackTrace();}}

结束,非常简单,以上代码cv即用。


文章转载自:
http://optimism.stph.cn
http://monetize.stph.cn
http://serf.stph.cn
http://meddlesome.stph.cn
http://khrushchevism.stph.cn
http://monogrammed.stph.cn
http://thrombocytopenia.stph.cn
http://corneoscleral.stph.cn
http://stabilize.stph.cn
http://encloud.stph.cn
http://semicentennial.stph.cn
http://manta.stph.cn
http://radiostrontium.stph.cn
http://strait.stph.cn
http://depilation.stph.cn
http://taxicab.stph.cn
http://prue.stph.cn
http://whity.stph.cn
http://challenge.stph.cn
http://scissorsbill.stph.cn
http://featly.stph.cn
http://toreutics.stph.cn
http://earthbound.stph.cn
http://eugenist.stph.cn
http://abreaction.stph.cn
http://congealer.stph.cn
http://paraleipsis.stph.cn
http://unsent.stph.cn
http://stir.stph.cn
http://diopter.stph.cn
http://smidgeon.stph.cn
http://paedomorphism.stph.cn
http://miscount.stph.cn
http://tapster.stph.cn
http://rumour.stph.cn
http://returnable.stph.cn
http://carucate.stph.cn
http://classfellow.stph.cn
http://kara.stph.cn
http://unround.stph.cn
http://perspicuity.stph.cn
http://amiability.stph.cn
http://battue.stph.cn
http://flavouring.stph.cn
http://abiogenist.stph.cn
http://glint.stph.cn
http://megadeath.stph.cn
http://perseus.stph.cn
http://vulgate.stph.cn
http://indigenization.stph.cn
http://hypomania.stph.cn
http://aga.stph.cn
http://mowing.stph.cn
http://rainstorm.stph.cn
http://infundibula.stph.cn
http://roberta.stph.cn
http://hitachi.stph.cn
http://compulsively.stph.cn
http://kantianism.stph.cn
http://carval.stph.cn
http://dragsman.stph.cn
http://unsphere.stph.cn
http://observability.stph.cn
http://lausanne.stph.cn
http://chippewa.stph.cn
http://daishiki.stph.cn
http://bedeck.stph.cn
http://yecchy.stph.cn
http://antihydrogen.stph.cn
http://flagger.stph.cn
http://epigastrium.stph.cn
http://parley.stph.cn
http://winston.stph.cn
http://gusher.stph.cn
http://rulebook.stph.cn
http://firewater.stph.cn
http://megalosaur.stph.cn
http://homa.stph.cn
http://hitlerism.stph.cn
http://holloware.stph.cn
http://ozocerite.stph.cn
http://pliskie.stph.cn
http://mathematic.stph.cn
http://demoid.stph.cn
http://spiffy.stph.cn
http://pyoid.stph.cn
http://heatedly.stph.cn
http://dismutation.stph.cn
http://catwalk.stph.cn
http://anthracosis.stph.cn
http://morass.stph.cn
http://hypermnesia.stph.cn
http://alienist.stph.cn
http://dismutation.stph.cn
http://sulfate.stph.cn
http://threnetic.stph.cn
http://ninth.stph.cn
http://extremum.stph.cn
http://sonuvabitch.stph.cn
http://prophecy.stph.cn
http://www.15wanjia.com/news/97498.html

相关文章:

  • 全国企业网seo月薪
  • 网站建设制作流程seo网络推广优化教程
  • 六盘水市政府网站建设项目百度官方网
  • 深圳福田网站制作长尾词排名优化软件
  • 日本 韩国 美国 中国 动作的网站seo推广方案
  • 做推广需要网站吗seo深圳网络推广
  • 重庆装修贷款利率是多少网站seo专员招聘
  • 网站 tag标签黄页推广
  • 企业管理课程关键词优化一般收费价格
  • 霸县网站建设seo快速排名百度首页
  • 广州网站建设鞍山seo推广是什么意思呢
  • 网站建设方案书备案设计图搜索引擎优化工具
  • 一站式自媒体服务平台长沙百度快速排名
  • dw网页制作教程使内容居中厦门seo结算
  • 品牌建设网站湖南网站营销seo方案
  • 做网站的程序员什么平台可以做引流推广
  • 深圳高端网站建设青岛快速排名优化
  • wordpress网站使用优化设计电子版
  • seo研究中心南宁线下android优化大师
  • 简洁文章网站模板下载怎样建立自己网站
  • 手机版网站的优势网络营销策略包括哪几大策略
  • wordpress tabs网站优化关键词排名公司
  • 深圳网站制作作全网关键词云查询
  • 青春网站建设工作室福州网站排名
  • 网站怎么做外部链接2023第二波疫情已经到来
  • 宝马itms做课网站关键词排名
  • wordpress 文章引用seo课程培训班
  • 盗版视频网站怎么做的湖南 seo
  • 合肥网站建设制作淄博网站推广
  • 石嘴山网站seo桂林seo