基于uni-app和Node.js實現(xiàn)app更新功能
業(yè)務背景
uniapp 打包 ios,android 之后,有時候緊急修復或修改 ui,還需要走應用市場審核,往往審核時間就需要幾天,如果是有bug需要升級就會很著急,有熱更之后,可以避免應用市場長時間審核,用戶很快就能收到更新。
整體思路:
要在uni-app中實現(xiàn)app更新功能,并使用Node.js作為后端服務,可以按照以下思路和步驟進行:
1、后端服務
- 使用Express創(chuàng)建一個簡單的Web服務器。
- 提供兩個API接口:
/checkForUpdate/:version用于檢查是否有新版本。/downloadApp/:version用于下載app。
2、uni-app前端
- 在頁面加載時調(diào)用checkForUpdate方法檢查是否有新版本。
- 如果有新版本,彈出提示框詢問用戶是否要更新。
- 如果用戶選擇更新,則下載新版本文件并下載安裝過程。
步驟一 創(chuàng)建Node.js后端服務
1、安裝必要依賴:
- 安裝
express或其他 Node.js web 框架來做后端服務。 - 安裝
cors用于處理跨域請求。
npm install express cors
2、創(chuàng)建一個簡單的后端服務:
- 在項目根目錄下創(chuàng)建一個名為
public的文件夾,并在其中創(chuàng)建一個名為apps的文件夾用于存放要更新的App。 - 將app打包好的app命名為:
appx.x.x.wgtapp更新文件放到apps文件夾中。 - 在項目根目錄下創(chuàng)建一個名為
server.js的文件,并寫入以下代碼:
// app更新
const express = require('express'); // 導入 Express 模塊
const cors = require('cors'); // 導入 CORS 模塊,用于處理跨域請求
const fs = require('node:fs'); // node內(nèi)置模塊,用于文件系統(tǒng)操作。
const path = require('node:path');//node內(nèi)置模塊,用于處理文件路徑。
const app = express(); // 創(chuàng)建 Express 應用實例。
app.use(cors()); // 使用 CORS 中間件解決跨越請求。
// 配置靜態(tài)文件服務,使得/public路徑下的文件可以直接訪問,如果沒有請手動創(chuàng)建。
app.use('/public', express.static(path.join(__dirname, 'public')));
// 存放app版本的文件夾,如果沒有請手動創(chuàng)建。
const appDir = path.join(__dirname, 'public/apps');
// 服務器的地址 類似于:http://localhost:3000
let serverAddress = ''
/**
* 根據(jù)客戶端提供的版本號檢查是否有新版本。
*/
app.get('/checkForUpdate/:version', async (req, res) => {
// uniapp當前版本號
const appCurrentVersion = req.params.version
// uniapp最新版本號
let appLatestVersion = ''
try {
// 讀取存放app目錄下的所有文件
const files = fs.readdirSync(appDir);
// 過濾出以app開頭的文件
const appFiles = files.filter(file => path.basename(file).startsWith('app'));
// 對文件列表進行排序,按照版本號從小到大排序
const sortedFiles = appFiles.sort((a, b) => {
const aParts = a.split('.').map(Number);
const bParts = b.split('.').map(Number);
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
if (aParts[i] > bParts[i]) return 1;
if (aParts[i] < bParts[i]) return -1;
}
return 0;
});
// 數(shù)組中最后一項版本就是最大最新的版本
appLatestVersion = sortedFiles.pop()
// 再對當前文件進行處理 ,將 app1.0.3.wgt => '1.0.3'
appLatestVersion = appLatestVersion.replace(/^app/, '').replace(/\.wgt$/, '')
} catch (error) {
throw new Error('Error reading public directory:' + error)
}
// 如果請求的版本小于最新版本,則提供下載鏈接
if (appLatestVersion > appCurrentVersion) {
res.send({
version: appLatestVersion, // 當前最新版本
url: `${serverAddress}/downloadApp/${appLatestVersion}`, // 更新下載地址
update: true, // 是否更新
mandatoryUpdate:true // 強制更新
})
} else {
res.send({
version: '',
url: '',
update: false,
mandatoryUpdate:false
})
}
})
/**
* 提供文件下載
*/
app.get('/downloadApp/:version', async (req, res) => {
// 要下載的 app 版本號
const version = req.params.version
const appName = `app${version}.wgt`
// app 存放路徑
const appFilePath = `${appDir}/${appName}`
// 檢查文件是否存在
fs.stat(appFilePath, (err, stats) => {
if (err) {
throw new Error(`未找到 app${version}版本下載地址`)
}
// 設置響應頭
// 指示瀏覽器以下載的方式處理文件,并設置文件名。
res.setHeader('Content-Disposition', `attachment; filename=${appName}`);
// 表示文件類型未知或二進制文件。
res.setHeader('Content-Type', 'application/octet-stream');
// 創(chuàng)建文件流
const fileStream = fs.createReadStream(appFilePath);
// 當文件流結(jié)束時,關閉響應
fileStream.on('end', () => {
console.log('File download completed.');
});
// 如果發(fā)生錯誤,處理錯誤
fileStream.on('error', (error) => {
throw new Error('Error downloading the file.:' + error)
});
// 將文件流管道發(fā)送到客戶端
fileStream.pipe(res);
});
})
const port = 3000; // 設置應用監(jiān)聽的端口號
// 啟動服務器并監(jiān)聽端口
const server = app.listen(port, () => {
// 獲取服務器綁定的地址信息
const addressInfo = server.address();
const host = addressInfo.address === '::' ? 'localhost' : addressInfo.address;
const port = addressInfo.port;
serverAddress = `http://${host}:${port}`
console.log(`Server is running at http://${host}:${port}`);
});
3. 啟動后端服務
打開終端,進入到項目根目錄,執(zhí)行以下命令:
node server.js
步驟二 創(chuàng)建uni-app前端應用
1、創(chuàng)建uni-app項目
打開HBuilderX 選擇菜單欄上的 [文件] -> [新建] -> [項目] 創(chuàng)建一個新的uni-app項目。

2、實現(xiàn)檢查更新邏輯
打開項目根目錄下的pages/index/index.vue文件,新增checkForUpdate方法,并在onLoad生命周期中調(diào)用該方法。
<template>
<text class="title" style="text-align: center;">
當前app資源版本為:{{appWgtVersion}}
</text>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const appWgtVersion = ref('')
// 在頁面加載時調(diào)用checkForUpdate方法檢查是否有新版本。
onLoad(() => {
checkForUpdate()
})
/**
* 檢查是否需要更新app
*/
function checkForUpdate() {
// 只在 app 中才會執(zhí)行以下代碼
// #ifdef APP-PLUS
// 獲取手機系統(tǒng)信息
const systemInfo = uni.getSystemInfoSync()
// 獲取到 app 資源包版本
appWgtVersion.value = systemInfo.appWgtVersion
// 向 Node.js 后端發(fā)送請求檢查是否需要更新
uni.request({
url: 'http://192.168.43.245:3000/checkForUpdate/' + appWgtVersion.value,
success: (res) => {
console.log('request-res', res);
if (res.data && res.data.update) {
uni.showModal({
title: '新版本發(fā)布',
content: '檢查到當前有新版本,需要更新嗎?',
showCancel: true,
confirmText: '立即更新',
cancelText: '暫不更新',
// 接口調(diào)用成功
success: (modalRes) => {
if (modalRes.confirm) {
// 立即更新app操作
uni.showLoading({
title: '正在下載'
})
console.log('res.data.url',res.data.url);
// 開始下載任務
const downloadTask = uni.downloadFile({
url: res.data.url,
success: (downloadRes) => {
if (downloadRes.statusCode === 200) {
uni.showLoading({
title: '正在安裝更新...'
});
plus.runtime.install(downloadRes.tempFilePath, {
force: true
}, () => {
console.log('install success...');
uni.hideLoading()
plus.runtime.restart();
}, (e) => {
console.log('install fail...', e);
uni.hideLoading()
uni.showToast({
title: '安裝失敗:' + JSON.stringify(e),
icon: 'fail',
duration: 1500
});
});
setTimeout(() => {
uni.hideLoading();
uni.showToast({
title: '安裝成功!',
icon: 'none'
});
}, 3000);
}
},
// 接口調(diào)用失敗
fail: (fail) => {
console.log('網(wǎng)絡錯誤,下載失?。?, fail);
uni.hideLoading();
},
// 接口調(diào)用結(jié)束
complete: () => {
console.log('----------------Complete----------------:', downloadTask)
downloadTask.offProgressUpdate(); //取消監(jiān)聽加載進度
}
});
//監(jiān)聽下載進度
downloadTask.onProgressUpdate(res => {
// console.log('下載進度百分比:' + res.progress); // 下載進度百分比
// console.log('已經(jīng)下載的數(shù)據(jù)長度:' + res.totalBytesWritten); // 已經(jīng)下載的數(shù)據(jù)長度,單位 Bytes
// console.log('預期需要下載的數(shù)據(jù)總長度:' + res.totalBytesExpectedToWrite); // 預期需要下載的數(shù)據(jù)總長度,單位 Bytes
});
} else {
// 暫不更新app操作
// 如果是你的發(fā)布需要強制更新的話,不更新app可以直接退出 APP 不讓使用
if(res.data.mandatoryUpdate){
if (systemInfo.platform === 'android') {
// 安卓退出app
plus.runtime.quit();
} else {
// 判斷為ios的手機,退出App
plus.ios.import("UIApplication").sharedApplication().performSelector("exit");
}
}
}
}
});
}
},
fail: (fail) => {
console.log('檢查更新請求失?。?, fail);
}
});
// #endif
}
</script>
3、制作應用wgt包
1、打開項目根目錄下的manifest.json配置文件,在基礎設置中將應用版本名稱設置為1.0.2。

2、選擇菜單欄上的 [發(fā)行] -> [原生App-制作應用wgt包]

3、將打包好的wgt包更名為app1.0.2.wgt。
后端是按照這個命名規(guī)范來進行升級的,所以我們按照這個規(guī)范來。

4、將打包好的app1.0.2.wgt包放在后端服務器的/public/apps文件夾中。
4、測試app更新功能
1、打開項目根目錄下的manifest.json配置文件,在基礎設置中將應用版本名稱設置為1.0.0,只要低于服務器中的版本即可。
2、運行app到手機
運行到手機后,頁面會彈出更新提示框
點擊“立即更新”按鈕
app會自動下載并安裝更新,安裝更新后的app后,會自動啟動并運行。

點擊“稍后更新”按鈕
在App非強制更新的情況下則關閉更新提示框。

點擊“稍后更新”按鈕
在App強制更新的情況下則退出App。

注意事項
- 確保Node.js后端服務和uni-app前端應用在同一網(wǎng)絡環(huán)境中運行。
- 測試時,請確保文件路徑和URL正確無誤。
以上步驟提供了一個基本的uni-app和Node.js實現(xiàn)app更新功能的示例。你可以根據(jù)具體需求進行調(diào)整和擴展。
以上就是基于uni-app和Node.js實現(xiàn)app更新功能的詳細內(nèi)容,更多關于uni-app和Node.js app更新的資料請關注腳本之家其它相關文章!
相關文章
Node.js創(chuàng)建HTTP文件服務器的使用示例
我們的目的比較簡單,使用Node.js創(chuàng)建一個HTTP協(xié)議的文件服務器,你可以使用瀏覽器或其它下載工具到文件服務器上下載文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-05-05
node.js程序作為服務并在windows下開機自啟動(用forever)
這篇文章主要介紹了node.js程序作為服務并在windows下開機自啟動的相關資料,因為實現(xiàn)的功能比較簡單,沒有選擇功能比較強大的pm2,文中選擇利用了forever,需要的朋友可以參考借鑒,下面來一起看看吧。2017-03-03
node.js中的fs.createReadStream方法使用說明
這篇文章主要介紹了node.js中的fs.createReadStream方法使用說明,本文介紹了fs.createReadStream方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12
Node.js與Sails ~項目結(jié)構與Mvc實現(xiàn)及日志機制
Sails是一個Node.js的中間架構,很方便的幫助我們搭建web應用程序。還有node.js與Sails日志機制在本文中也講到了,需要的朋友可以一起學習下2015-10-10
node.js中的fs.createWriteStream方法使用說明
這篇文章主要介紹了node.js中的fs.createWriteStream方法使用說明,本文介紹了fs.createWriteStream方法說明、語法、接收參數(shù)、使用實例和實現(xiàn)源碼,需要的朋友可以參考下2014-12-12
Node.js中的npm單獨與批量升級依賴包的方式超詳細講解
npm outdated僅檢查所有已安裝包的依賴關系,并將當前版本遠程倉庫中的最新版本進行對比,不會升級,這篇文章主要介紹了Node.js中的npm單獨與批量升級依賴包的方式超詳細講解,需要的朋友可以參考下2024-02-02
nodejs進階(6)—連接MySQL數(shù)據(jù)庫示例
本篇文章主要介紹了nodejs進階(6)—連接MySQL數(shù)據(jù)庫示例,詳細的介紹了NodeJS操作MySQL數(shù)據(jù)庫,作為應用最為廣泛的開源數(shù)據(jù)庫則成為我們的首選,有興趣的可以了解一下。2017-01-01
使用Node.js實現(xiàn)ORM的一種思路詳解(圖文)
這篇文章主要介紹了用Node.js實現(xiàn)ORM的一種思路詳解(圖文),需要的朋友可以參考下2017-10-10

