桌面应用electron+electron-builder+eletron-autoUpdater完整示例

本人亲测可用:
使用线上仓库: https://github.com/electron/electron-quick-start.git

什么也不说,先上完整代码,若是需要看分析,可看代码分析部分

package.json代码如下:

{
  "name": "Name must be english",
  "version": "2.6.1",
  "description": "A minimal Electron application",
  "main": "main.js", // 入口文件
  "scripts": {
    "start": "electron .",
    "builder": "electron-builder"
  },
  "build": { // 更多配置请看文档:https://www.electron.build/configuration/publish 内说得很清楚
    "appId": "yourappId",
    "productName": "productName",
    "artifactName":"${version}.${ext}",
    "directories": {
      "output": "builds"
    },
    "win": {
      "icon": "./favicon.ico",
      "publish": [
        {
          "provider": "generic",
          "channel":"latest", // 更新检测文件名
          "url": "https://******version"  // 远程更新包地址,无效拼接文件名,只需要目录路径,需要和main.js内的feedUrl一致,原因我没去了解
        }
      ]
    }
  },
  "repository": "https://github.com/electron/electron-quick-start",
  "keywords": [
    "Electron",
    "quick",
    "start",
    "tutorial",
    "demo"
  ],
  "author": "GitHub",
  "license": "CC0-1.0",
  "devDependencies": {
    "electron": "^5.0.8",
    "electron-builder": "^21.1.5"
  },
  "dependencies": {
    "electron-updater": "^4.1.2"
  }
}

main.js 【入口文件】代码如下:

// Modules to control application life and create native browser window
const {app, BrowserWindow,Menu,ipcMain} = require('electron')
const path = require('path')
// 一些自定义配置
const package = {
    version:"2.6.1",
    productEnv:"development",// development products
    feedUrl:"https://*****yversion"
};

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;


// ===============================================================更新区
// ===============================================================更新区
// ===============================================================更新区
const autoUpdater = require('electron-updater').autoUpdater;
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle() {
    // let message = {
    //     error: '检查更新出错',
    //     checking: '正在检查更新……',
    //     updateAva: '检测到新版本,正在下载……',
    //     updateNotAva: '现在使用的就是最新版本,不用更新',
    // };
    let message = {
        error: 'Check update is error.',
        checking: 'checking update now.',
        updateAva: 'has new packer is downing...',
        updateNotAva: 'is the lasted packer. do not to update   !',
    };
    const os = require('os');

    autoUpdater.setFeedURL(package.feedUrl);
    autoUpdater.on('error', function (error) {
        sendUpdateMessage({cmd:'error',message:error})
    });
    autoUpdater.on('checking-for-update', function (message) {
        // sendUpdateMessage({cmd:'checking-for-update',message:message})
    });
    autoUpdater.on('update-available', function (message) {
        sendUpdateMessage({cmd:'update-available',message:message})
    });
    autoUpdater.on('update-not-available', function (message) {
        sendUpdateMessage({cmd:'update-not-available',message:message})
    });

    // 更新下载进度事件
    autoUpdater.on('download-progress', function (progressObj) {
        sendUpdateMessage({cmd:'download-progress',message:progressObj})
    })
    autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl) {
        sendUpdateMessage({cmd:'update-downloaded',message:{
            releaseNotes, releaseName, releaseDate, updateUrl
        }})
    });

    ipcMain.on('isUpdateNow', (e, arg)=>{
        // sendUpdateMessage({cmd:'isUpdateNow',message:arg})
        //some code here to handle event
        autoUpdater.quitAndInstall();
    });

    ipcMain.on("checkForUpdate",(e, arg)=>{
        //执行自动更新检查
        // sendUpdateMessage({cmd:'checkForUpdate',message:arg})
        autoUpdater.checkForUpdates();
    })

}

// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage(data) {
    mainWindow.webContents.send('message', data)
}

// ===============================================================窗口区
// ===============================================================窗口区
// ===============================================================窗口区

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    useContentSize: true,
    maximizable:false,
    resizable :false,
    title :"window title",
    icon :path.join(__dirname, 'favicon.ico'),
    webPreferences: {
        devTools:package.productEnv == "development",
        nodeIntegration: true
        // preload: path.join(__dirname, 'preload.js') // 预加载文件 本人无需用到
    }
  })

  // and load the index.html of the app.
  // mainWindow.loadFile('index.html') // 加载本地文件资源
  mainWindow.loadURL(`file://${__dirname}/index.html`); // 加载本地文件资源
  // mainWindow.loadURL('http://*****'); // 加载远程资源

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })


  if(package.productEnv == "development") mainWindow.webContents.openDevTools()  // 开启调试

    mainWindow.webContents.on('did-finish-load', () => { // 使用通信 版版本信息发送到渲染进程
        mainWindow.webContents.send('staticData', {"version":package.version});
    })

  updateHandle(); // 初始化更新相关监听
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', function(){
    createWindow();
    Menu.setApplicationMenu(null);// 屏蔽electron 默认菜单栏
})

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  // if (process.platform !== 'darwin') app.quit()
  app.quit()
})

app.on('activate', function () {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) createWindow()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
 

我的本地静态资源:



   
   
    title
   
   


   


   

       

           

           

               

                    最新版本:v1.0.0
               

               
               

                   
               

           

       

   

   

renderer.js 【相关的更新操作等,若不需要更新可注释引入就可以】代码:

// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.
const ipcRenderer = require('electron').ipcRenderer;
var Upd_app       = document.getElementById("update-app");
var _app              = document.getElementById("app");
var Upd_progress  = document.getElementById("update-progress");
var Upd_version   = document.getElementById("update-version");
var Upd_btn       = document.getElementById("update-btn");
var Upd_lock      = false;
var Upd_percent   = 0;

ipcRenderer.on("staticData",function(event,data){
    // 获取配置项数据
    console.log(data)
    if(data.version) {
        Upd_version.innerText = data.version;
        if(typeof window.updateVerson == 'function') _app.innerText = data.version;
    }
})

ipcRenderer.on('message',(event,data) => {
    
    // 初始化参数
    data = data || {};
    var message = data.message || {};
    console.log(data)

    // 需更新
    if(data.cmd == 'update-available'){
        Upd_app.style.display = "block";
        if(message.version) {
            layer.msg("正在更新到最新版本:v "+message.version);
            Upd_version.innerText = message.version;
        }
    }

    // 更新异常
    if(data.cmd == 'error'){
        Upd_lock = false;
        Upd_btn.innerText = "立即更新";

        if(message.errno == -4058){
            Upd_app.style.display = "none";
        }
    }

    // 下载中
    if(data.cmd == 'download-progress'){
        Upd_progress.value = Number(message.percent);
        Upd_percent = Number(message.percent);
    }
    
    // 下载完成
    if(data.cmd == 'update-downloaded'){
        // 下载完成 开始安装
        if(Upd_percent == 100){
            // 一般这里提示二次确认是否立即安装并重启,但是electron文档说了下载后不管这次是否更新,下次重启必定会更新 文档地址:https://electronjs.org/docs/api/auto-updater 最后一行注意事项
            Upd_btn.innerText = "安装重启中...";
            ipcRenderer.send('isUpdateNow');
        }
    }

});

setTimeout(function(){
    autoUpdate()
},500);

function autoUpdate(){
    //  这里提示是否检测有更新版本信息
    if(Upd_lock) return false;
    Upd_lock = true;
    Upd_btn.innerText = "版本更新中.";
    ipcRenderer.send('checkForUpdate');
}

备注:
记得最后安装 asar 把资源变成二进制文件
打包完成后复制下入两个文件到你的更新地址中

桌面应用electron+electron-builder+eletron-autoUpdater完整示例_第1张图片


以下是一些简单的代码分析:

1、本文采用electron-builder 打包,electron-autoupdate 更新
2、"nsis": {  // 是否存在该配置,存在则目录下打包结果多了个绿色版压缩包,如下图
        "oneClick": false,
        "perMachine": true,
        "allowElevation": true,
        "allowToChangeInstallationDirectory": true,
        "createDesktopShortcut": true,
        "runAfterFinish": true,
        "installerIcon": "favicon.ico",
        "uninstallerIcon": "favicon.ico"
    },
桌面应用electron+electron-builder+eletron-autoUpdater完整示例_第2张图片
3、main.js 的updateHandle函数是更新部分,对应入口文件内容的renderer.js。对于主进程和渲染进程不懂的可先了解一下socket,其通信一致,都是发送与监听,若不需要可以删除

4、如果打包后的资源不知道如何放,例如tp框架可以直接放在static/下,直接访问 http*****/static   这样就可以了

完整资源已上传,下载地址:https://download.csdn.net/download/m0_37118353/11437845

你可能感兴趣的:(备忘日志)