Skip to content
索引

electron实现github自动升级

实现 GitHub 自动升级需要编写一些自动化脚本,以下是一个简单的方案:

  1. 在 Electron 应用的主进程中,使用 electron-updater 模块实现自动更新功能。这个模块提供了一些 API,可以方便地检查和下载最新的应用版本。
  2. 将应用的安装包发布到 GitHub Release 中。每次发布新版本时,需要将安装包上传到对应的 Release 中,并将版本号和更新说明填写好。
  3. 编写一个自动化脚本,定期检查 GitHub Release 中是否有新版本的安装包发布。可以使用 GitHub API 获取最新的 Release 信息,并比较版本号判断是否需要更新。
  4. 如果检测到有新版本发布,则使用 electron-updater 模块下载最新的安装包,并启动安装程序完成升级操作。

需要注意的是,为了保证应用的安全性,下载的安装包应该来自可信的来源,比如使用 HTTPS 协议获取 GitHub Release 中的安装包,并验证其数字签名。同时,在自动升级过程中,需要确保用户的数据不会丢失或被覆盖,建议在升级前进行数据备份。

检查 GitHub Release 中是否有新版本的安装包发布

js
const https = require('https');
const { exec } = require('child_process');

const OWNER = 'your_github_username';
const REPO = 'your_github_repo';

const getCurrentVersion = () => {
  // 获取当前应用的版本号,可以根据实际情况进行修改
  const { version } = require('./package.json');
  return version;
};

const getLatestRelease = async () => {
  // 使用 GitHub API 获取最新的 Release 信息
  const url = `https://api.github.com/repos/${OWNER}/${REPO}/releases/latest`;
  const options = {
    headers: { 'User-Agent': 'Mozilla/5.0' }
  };
  return new Promise((resolve, reject) => {
    https.get(url, options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        try {
          const release = JSON.parse(data);
          resolve(release);
        } catch (err) {
          reject(err);
        }
      });
    }).on('error', (err) => {
      reject(err);
    });
  });
};

const compareVersions = (v1, v2) => {
  // 比较版本号大小,返回 true 表示 v1 > v2,需要升级
  const v1Parts = v1.split('.');
  const v2Parts = v2.split('.');
  for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
    const v1Part = Number(v1Parts[i] || 0);
    const v2Part = Number(v2Parts[i] || 0);
    if (v1Part > v2Part) {
      return true;
    } else if (v1Part < v2Part) {
      return false;
    }
  }
  return false;
};

const checkForUpdates = async () => {
  const currentVersion = getCurrentVersion();
  const latestRelease = await getLatestRelease();
  const latestVersion = latestRelease.tag_name.replace(/^v/, '');
  if (compareVersions(latestVersion, currentVersion)) {
    console.log(`New version ${latestVersion} is available. Run "npm run update" to install.`);
  } else {
    console.log(`You have the latest version ${currentVersion}.`);
  }
};

checkForUpdates();
const https = require('https');
const { exec } = require('child_process');

const OWNER = 'your_github_username';
const REPO = 'your_github_repo';

const getCurrentVersion = () => {
  // 获取当前应用的版本号,可以根据实际情况进行修改
  const { version } = require('./package.json');
  return version;
};

const getLatestRelease = async () => {
  // 使用 GitHub API 获取最新的 Release 信息
  const url = `https://api.github.com/repos/${OWNER}/${REPO}/releases/latest`;
  const options = {
    headers: { 'User-Agent': 'Mozilla/5.0' }
  };
  return new Promise((resolve, reject) => {
    https.get(url, options, (res) => {
      let data = '';
      res.on('data', (chunk) => {
        data += chunk;
      });
      res.on('end', () => {
        try {
          const release = JSON.parse(data);
          resolve(release);
        } catch (err) {
          reject(err);
        }
      });
    }).on('error', (err) => {
      reject(err);
    });
  });
};

const compareVersions = (v1, v2) => {
  // 比较版本号大小,返回 true 表示 v1 > v2,需要升级
  const v1Parts = v1.split('.');
  const v2Parts = v2.split('.');
  for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
    const v1Part = Number(v1Parts[i] || 0);
    const v2Part = Number(v2Parts[i] || 0);
    if (v1Part > v2Part) {
      return true;
    } else if (v1Part < v2Part) {
      return false;
    }
  }
  return false;
};

const checkForUpdates = async () => {
  const currentVersion = getCurrentVersion();
  const latestRelease = await getLatestRelease();
  const latestVersion = latestRelease.tag_name.replace(/^v/, '');
  if (compareVersions(latestVersion, currentVersion)) {
    console.log(`New version ${latestVersion} is available. Run "npm run update" to install.`);
  } else {
    console.log(`You have the latest version ${currentVersion}.`);
  }
};

checkForUpdates();

Skip checkForUpdates because application is not packed and dev update config is not forced

如果你在开发过程中遇到了"Skip checkForUpdates because application is not packed and dev update config is not forced"这个错误,通常是因为在开发环境下直接运行Electron应用程序,而不是打包后运行。在这种情况下,Electron-updater会默认跳过自动更新检查,以避免在开发环境下不必要的网络请求和处理。

如果你想在开发环境下测试自动更新,可以通过以下两种方式解决这个问题:

  1. setFeedURL方法中设置updateConfigPath选项,将其指向一个本地的JSON文件,用于模拟自动更新的配置信息。例如:

    js
    codeautoUpdater.setFeedURL({
      provider: 'generic',
      url: 'http://localhost:3000/updates/',
      channel: 'latest',
      updateConfigPath: path.join(__dirname, 'dev-app-update.yml')
    });
    
    codeautoUpdater.setFeedURL({
      provider: 'generic',
      url: 'http://localhost:3000/updates/',
      channel: 'latest',
      updateConfigPath: path.join(__dirname, 'dev-app-update.yml')
    });
    

    dev-app-update.yml文件中,可以指定自动更新的配置信息,例如:

    yml
    codeversion: '1.0.0'
    releaseDate: '2022-03-23T00:00:00Z'
    url: 'http://localhost:3000/updates/app-1.0.0.dmg'
    sha512: '1234567890abcdef'
    
    codeversion: '1.0.0'
    releaseDate: '2022-03-23T00:00:00Z'
    url: 'http://localhost:3000/updates/app-1.0.0.dmg'
    sha512: '1234567890abcdef'
    

    这样,在开发环境下,Electron-updater就会读取本地的JSON文件,模拟自动更新的配置信息,从而可以测试自动更新功能。

  2. 在Electron应用程序的启动脚本中,设置环境变量ELECTRON_FORCE_WINDOW_UPDATEtrue,强制启用自动更新检查。例如:

    js
    codeprocess.env.ELECTRON_FORCE_WINDOW_UPDATE = 'true';
    
    app.on('ready', () => {
      autoUpdater.checkForUpdatesAndNotify();
      // ...
    });
    
    codeprocess.env.ELECTRON_FORCE_WINDOW_UPDATE = 'true';
    
    app.on('ready', () => {
      autoUpdater.checkForUpdatesAndNotify();
      // ...
    });
    

    这样,在开发环境下,Electron-updater就会强制启用自动更新检查,从而可以测试自动更新功能。注意,这种方式可能会产生不必要的网络请求和处理,建议仅在开发环境下使用。

Released under the MIT License.