前言
应用内更新的逻辑是,应用内检测受否需要更新,如果需要更新,安装包下载到本地后,进行打开安装,同时关闭当前应用。
旧版本的API为
1 2
| const {shell} = window.require("electron"); shell.openItem(filepath);
|
旧版本是没有问题的。
新版本变更为
1 2
| const {shell} = window.require("electron"); shell.openPath(filepath);
|
但是这样就出现问题了,新版本打开是在子进程中,安装应用安装包时,应用进程是必须要关闭,如果应用进程关闭,安装包对应的子进程也会关闭,导致安装终止。
node-cmd
所以只能更换一种方式
在Electron中
1 2
| const cmd = window.require('node-cmd'); cmd.run('start "" "' + filepath + '"');
|
注意启动应用应该这样
1
| start "" "D:\Project\myapp.exe"
|
注意
- 路径要添加双引号,否则路径中有空格就无法打开应用。
- start命令后要添加
"",否则打不开应用,第一个参数会被当做标题,第二个才是文件路径。
node-cmd简介
node-cmd模块中主要有run和get两类命令,其中run是执行cmd命令,get命令除了异步执行cmd命令外,在执行完毕后还会执行回调函数,返回命令行窗口的输出。
1 2 3 4 5 6 7 8 9 10
| var cmd = require('node-cmd');
cmd.run('touch example.created.file');
cmd.get( 'ls', function(data){ console.log('the current dir contains these files :\n\n',data) } );
|
完整示例
完整的下载应用代码示例:
渲染进程中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| const path = window.require("path"); const {app} = window.require("electron").remote; const cmd = window.require('node-cmd');
async update_app_action() { let versionpath = this.version_obj["versionpath"]; let versioncode = this.version_obj["versioncode"]; let file_url = `${filedownloadUrl}${versionpath}`; let temp_path = remote.getGlobal("sharedObject").temp_path; try { if (!fs.existsSync(temp_path)) { fs.mkdirSync(temp_path, {recursive: true}); } } catch (e) { } let filename = versioncode + "_" + versionpath.substring(versionpath.lastIndexOf("/") + 1); let temp_filename = "temp_" + filename;
const filepath = path.join( temp_path, filename );
const temp_filepath = path.join( temp_path, temp_filename ); if (fs.existsSync(filepath)) { cmd.run('start "" "' + filepath + '"'); } else { if (fs.existsSync(temp_filepath)) { fs.unlinkSync(temp_filepath); } this.version_down = true; try { await this.download_file(file_url, temp_filepath); this.version_down = false; this.version_flag = false; fs.renameSync(temp_filepath, filepath) cmd.run('start "" "' + filepath + '"'); } catch (e) { console.info("更新失败!") } } }
download_file(file_url, path) { return new Promise((resolve, reject)=>{ const url = require("url"); const {http, https} = require("follow-redirects"); let myhttp = http; if (file_url.indexOf("https:") !== -1) { myhttp = https; } const options = url.parse(file_url); let filldiv = document.getElementById("filldiv"); try { const request = myhttp.request(options, (response)=>{ const file_length = response.headers["content-length"]; let downd_length = 0; let m_stream = fs.createWriteStream(path); response.on("data", (chunk)=>{ downd_length += chunk.length; let down_progress = Math.ceil((downd_length * 100) / file_length); this.version_progress = down_progress; filldiv.style.width = down_progress * 4 + "px"; filldiv.style.background = "#33C5B3"; m_stream.write(chunk); }); response.on("end", function() { m_stream.end(); m_stream.on('close', ()=>{ resolve(path); }) }); }); request.end(); } catch (e) { reject("下载失败!"); } }) },
|
Electron路径最佳实践
如果渲染进程太多,不建议在渲染进程中获取路径,建议在主进程中设置。
主进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| const {app} = require("electron"); const path = require("path"); const fs = require("fs");
global.sharedObject = { temp_path: "", }
let basepath = "";
try { basepath = app.getPath("downloads"); } catch (e) { basepath = path.dirname(app.getPath("exe")); }
if (/.*[\u4e00-\u9fa5 ]+.*$/.test(basepath)) { basepath = "C:\\"; }
let temp_path = path.join( basepath, "school_live_temp" )
try { if (!fs.existsSync(temp_path)) { fs.mkdirSync(temp_path, {recursive: true}); } } catch (e) { }
console.info("temp_path", temp_path); global.sharedObject.temp_path = temp_path;
|
注意
在有些电脑上竟然无法使用app.getPath("downloads")获取路径,所以这里进行异常捕获。
有些电脑用户名是中文,而某些SDK不支持路径中包含中文和空格,这里也做了判断。
渲染进程
1 2
| const remote = window.require("electron").remote; let temp_path = remote.getGlobal("sharedObject").temp_path;
|