前言
应用内更新的逻辑是,应用内检测受否需要更新,如果需要更新,安装包下载到本地后,进行打开安装,同时关闭当前应用。
旧版本的API为
代码语言:javascript复制const {shell} = window.require("electron");
shell.openItem(filepath);
旧版本是没有问题的。
新版本变更为
代码语言:javascript复制const {shell} = window.require("electron");
shell.openPath(filepath);
但是这样就出现问题了,新版本打开是在子进程中,安装应用安装包时,应用进程是必须要关闭,如果应用进程关闭,安装包对应的子进程也会关闭,导致安装终止。
node-cmd
所以只能更换一种方式
代码语言:javascript复制npm install node-cmd -s
在Electron中
代码语言:javascript复制const cmd = window.require('node-cmd');
cmd.run('start "" "' filepath '"');
注意启动应用应该这样
代码语言:javascript复制start "" "D:Projectmyapp.exe"
注意
- 路径要添加双引号,否则路径中有空格就无法打开应用。
- start命令后要添加
""
,否则打不开应用,第一个参数会被当做标题,第二个才是文件路径。
node-cmd简介
node-cmd模块中主要有run和get两类命令,其中run是执行cmd命令,get命令除了异步执行cmd命令外,在执行完毕后还会执行回调函数,返回命令行窗口的输出。
代码语言:javascript复制var cmd = require('node-cmd');
cmd.run('touch example.created.file');
cmd.get(
'ls',
function(data){
console.log('the current dir contains these files :nn',data)
}
);
完整示例
完整的下载应用代码示例:
渲染进程中
代码语言:javascript复制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添加一个随机背景颜色
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路径最佳实践
如果渲染进程太多,不建议在渲染进程中获取路径,建议在主进程中设置。
主进程
代码语言:javascript复制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不支持路径中包含中文和空格,这里也做了判断。
渲染进程
代码语言:javascript复制const remote = window.require("electron").remote;
let temp_path = remote.getGlobal("sharedObject").temp_path;