毫无难度掌握自动更新

时间:2023-02-10 05:59:43

为了尽快的完成模块的编写,我使用Node.js编写这个模块,桌面级处理为Electron。

先展示一下效果,HTML就不去精益求精了。

毫无难度掌握自动更新

毫无难度掌握自动更新

毫无难度掌握自动更新

OK,我们先想一下,要怎么做。首先,现在的网络空间说便宜吧,也没到满大街都是,更何况是一个持续可用的空间。

对于我这种学生党,自然是不乐意去花钱买空间了。所以吧,我们借一下Github的空间好了,如何?是不是感觉很新颖?

但是Github的空间是不支持动态解析的哦!也就是说你只能下载静态资源,OK,没问题,动态解析可以放到客户端嘛,需要下载哪些更新文件就下载什么好了。

我们先创建一个Electron项目好了。

先看一下架构:

毫无难度掌握自动更新

src[folder] => 自然是存放js代码的地方咯。

    AutoUP[folder] => 自动更新模块

UpdateStorage[folder] => 更新数据存放点

    tmp[folder] => 临时数据区

    release.json[file] => 这个是由服务器进行维护的文件,可以在客户端删除,为了方便git推送,我留着的。

    version.json[file] => 当前的版本信息

index.html[file] => Electron的主界面

LICENSE.md[file] => 许可

剩余的就没什么好看的了。

好了,现在我们来想一下该怎么实现,Github的空间理论上来说是无限的,所以不用节省,JS代码想节省都难吧。

毫无难度掌握自动更新

我们来看看怎么将在github上的文件下载下来。

毫无难度掌握自动更新

注意,我们可以直接从raw.githubusercontent.com拉取文件,当然,这个必须要有确切的文件名。

有了解过的应该都知道,电脑软件更新,比如VS Studio,总不能全部重新下载然后再全部重新安装吧?所以一般我们都会做一个更新索引,为什么呢?因为需要什么下载什么就好了!

好,我们先构想一下,Node对于JSON的处理那简直是爽炸啊!一个require就导入进来了。

所以这个索引,和传统的索引不同,我们不使用XML格式,而是采用JSON了。

好,那么我们该怎样来设计这个JSON呢?

首先,最新的版本号得在里面吧?

OK,那么更新所需下载的文件或者更新所需要更新的文件也得存在里面吧?

但是问题来了?我怎么知道要下载什么啊?我可没有PHP,JSP动态的返回一个JSON告诉你你应该下载啥吧?

既然这样,那倒不如直接把每次更新所需要的文件都放到JSON里,反正一个JSON也不大,相比起其他的软件更新,动挪30多MB的XML索引,总不会差的。

OK,那么更新总得专业点吧?更新的说明是不是该加上?

太棒了,这么一想,这个文件就搞定了。

毫无难度掌握自动更新

我设计的就是这样子,我们来看看占用多少,毫无难度掌握自动更新

连1KB都不到哦!

所以这样做肯定是没什么大问题的。

OK,那么软件更新第一步是干什么?

下载更新索引对吧?那么下载总得要吧!

先拿request写一个下载函数。

const electron = require( ' electron ');
const request = require( ' request ');
const fs = require( ' fs ');
var app = null;
if ( electron. app == null) {
app = electron. remote. app;
} else {
app = electron. app;
}

function downloadFile( uri, filename, callback) {
var stream = fs. createWriteStream( filename);
request( uri). pipe( stream). on( ' close ', callback);
}

接下来就是去下载索引文件了,我是从https://raw.githubusercontent.com/1426652334/AutoUpdate/master/UpdateStorage/release.json这里下载索引,注意自己的Github地址需要更换的。

那么下载的代码就是:

var fileUri = ' https://raw.githubusercontent.com/1426652334/AutoUpdate/master/UpdateStorage/release.json ';
var filename = ' release.json ';
var path = app. getAppPath() + ' \\ UpdateStorage \\ tmp \\ ' + filename;
var release_path = app. getAppPath() + " \\ UpdateStorage \\ tmp \\ release.json ";
downloadFile( fileUri, path, function () {});

下载好了那么就要开始分析了。

这里我们在回调函数内分析,因为Node的异步,如果download函数下面一行就写分析的话,你是得不到结果的。

先把索引加载把。

因为require加载JSON可能会报错,所以必须使用try-catch块包围他们,并且我们需要将分析结果转储下来,这里我用upVer数组来转储,同样加载本地的版本文件,即version.json。

var release = null;
var upVer = null;
const old_v = require ( app . getAppPath () + ' \\ UpdateStorage \\ version.json ' );
try {
release = require( release_path);
} catch ( error) {
alert( " 更新出错! " + error);
}

首先要想用户展示有哪些更新可用,并且这个更新的说明是什么。

这个毫无技术难度。

var control = false;
for( var key in release. manifest){
    if( control){
        document. write( " Version: " + key + " &nbsp;&nbsp;可用,更新说明: " + release. manifest[ key][ ' detail '] + " <br> ");
    }
    if( key == old_v. version){
        control = true;
    }
}

注意,为什么我可以用foreach语句来遍历更新说明,请返回上面看一下我的release.json架构,我们必须保证,该json内的版本信息是有顺序的,此时才可以使foreach语句内的遍历无异常。

我们在foreach内,用control来判断foreach内的version是否超过当前的version,然后,我们在用version相同时,将control开关打开,OK,这样就可以遍历出来了。至于为什么control修改要放在后面,如果看不出来,请你仔细巩固基础再来看,虽然说是无难度掌握,但是基础都不行,可能是最高难度掌握了。

好的,那么接下来我们要开始更新文件了。

将control开关闭上,我们开始重新遍历的历程。

但是该怎么遍历呢?首先,我们要获取对应版本内所需更新的文件,假如现在软件版本1.0.0,但是服务器已经更新到了2.0.0,中间有版本1.0.1,和1.0.2,那么我们需要更新的文件就是对应版本1.0.1和1.0.0以及2.0.0版本所需更新的文件了。

同样还是和上面遍历一样的套路,因为保证了release.json文件的顺序性,那么我们可以用version比较以及开关控制。

这时又会产生一个问题了,我只知道要下载的文件是什么啊,可不知道地址是什么啊!

别担心,我们可以发现,所有存储在github内的文件,都是位于"https://raw.githubusercontent.com/1426652334/AutoUpdate/master/"下的。

那么也就是说我们的文件下载地址可以这样构造:

https://raw.githubusercontent.com/1426652334/AutoUpdate/master/$filedir_name_included

熟悉github的人知道其实不止是这个,因为这是拉取master branch下的文件,可能还有其他的branch,这里不作讨论了。

设置源,构造路径,完美。

const origin = ' https://raw.githubusercontent.com/1426652334/AutoUpdate/master/ ';
control = false;
for( var key in release. manifest){
    if( control){
        for( var file in release. manifest[ key][ ' fetch ']){
            var fileLink = origin + release. manifest[ key][ ' fetch '][ file];
            var storage = app. getAppPath() + " \\ " + release. manifest[ key][ ' fetch '][ file];
            downloadFile( fileLink, storage, function () {});
        }
        document. write( ' <p>更新至版本: ' + key + " ,请注意,此时可能尚未完成更新,请勿退出此应用。<br></p> ");
    }
    if( key == old_v. version){
        control = true;
       }
}

好了,如果有更新,此时应该会下载所有更新的所需文件了。

那么没有更新怎么办呢?

if( release. version == old_v. version){
    document. write( ' 看来今日无事可做,你的软件已是最新版本了。 ')
} else{
    document. write( ' 完成更新!请注意,软件可能仍在下载数据,但一般来说,由于更新所需要数据十分小,此时它应该已经完成了更新。<br>您可以放心的继续使用此软件而不受丝毫影响。 ')
}

OK,没有更新也处理完了。

但是别忘了还有最后一个结尾工作,

fs. writeFileSync( app. getAppPath() + " \\ UpdateStorage \\ version.json ", fs. readFileSync( release_path))
fs. unlink( release_path);

OK啦,这样子自动更新就做好啦。

是不是好简单?

对了,跟大家说一下,我之前的想法是:

release内的manifest中的fetch没有的,因为我是打算直接在release.json同级目录中存在若干个以版本号为文件名的json文件,里面存储着需要的文件索引。

之所以没有这么实现,是因为,这样子异步做起来会比较麻烦,不信大家可以试试啦,还有,为了保证客户端的流畅运行,所以下载是异步下载的啦,如果有需要自己想办法改成同步下载就好啦。


附该Project地址:

https://github.com/1426652334/AutoUpdate.git