Electron增量更新(三)

陌路凡歌發表於2021-12-20

寫Electron這個系列以來,還是有不少同學問了一些問題的,主要是針對於electron增量更新的,之前我寫過增量更新(二),但是其Windows方式需要管理員許可權包,不太優雅,且如果想要拖拽功能的話,由於許可權問題,提權後的軟體會禁止拖動(將外部檔案拖入軟體視窗會有一個禁止圖示),那麼這一期我會對增量更新進行一次比較詳細的說明以及提供臨時提權更新的方案供大家參考。

Mac更新

有些同學問了Mac平臺下的系統如何增量更新的,實際上Mac下的Electron的asar檔案是可以直接替換的,故下載替換後,開個定時器重啟就行了。

Windows

其實我們的桌面軟體大都不需要管理員許可權的(就是軟體上帶盾牌的),我們發現很多軟體都是在需要更新時會有一個彈窗出現,你點選後會對其進行臨時提權進行更新,本期的目標就是實現這種臨時提權的功能進行增量更新。

更新問題

其實我們增量更新有兩個難點,要想實現得攻克這兩個主要問題:

  1. 什麼時候需要uac提權?
  2. 怎麼處理Electron應用啟動後app.asar被佔用鎖定的問題?

更新說明

  1. Windows系統是有不同的使用者許可權級別的,比如我是普通使用者在修改c盤某些資料夾的檔案時,會有一個彈窗讓你使用管理員許可權建立或修改等等,當軟體被安裝在c盤時,我們就需要管理員許可權來替換app.asar檔案。exe
  2. 關於鎖定問題,在增量二中已經說明了一下,處理方式就是關閉我們的Electron應用,然後再進行app.asar檔案的替換。

更新步驟

  1. 編寫bat指令碼,在指令碼中執行Electron應用的關閉,app.asar檔案的替換,重啟Electron應用,然後將bat指令碼打包成exe檔案。
  2. 下載update.asar(更新版本的app.asar),判斷使用者軟體是否安裝在c盤,是:使用sudo-prompt這個包臨時提權執行上面的exe,不是:可以不用提權,直接使用node的exec執行上面的exe。

更新準備

模擬請求什麼的前兩期更新已經說了,點選這裡增量更新(二),看看步驟,這裡就不再多做說明。

構建exe

@echo off
taskkill /f /im %3
timeout /T 1 /NOBREAK
del /f /q /a %1\app.asar
move %2\update.asar %1
ren %1\update.asar app.asar
explorer.exe %4

簡單解釋一下吧,%1和%2為執行指令碼傳入的引數,比如update.bat aaa bbb,那麼%1為aaa,%2為bbb,上面我們執行exe時傳入的,
也就是%1為resourcesPath(也就是我們的app.asar所在目錄),%2為下載更新的update.asar所在目錄,%3為軟體的程式名稱(可在工作管理員中檢視),%4為軟體的啟動exe。
這裡的邏輯是Electron應用,暫停1秒鐘,然後刪除app.asar,將update.asar移動到app.asar目錄下,重新命名為app.asar,啟動Electron應用。
下載Bat To Exe Converter這個軟體,將update.bat轉換為update.exe,詳細操作請看前面兩期的詳細說明。

對比上一期的我們發現啟動時沒用start命令了,而是用的explorer.exe,它是Windows系統自帶的程式管理器,這裡的處理是打包的Electron應用不帶有管理員許可權,但是如果我們提權後執行此exe啟動Electron應用,我們會發現此時Electron應用也具有了管理員許可權,故需要使用explorer.exe降權啟動。

sudo-prompt

安裝sudo-prompt,npm i sudo-prompt,sudo-prompt這個包和node的exec命令差不多,執行時會有一個提權彈窗出現,使用者確認後會以管理員許可權執行命令,新建sudoPrompt.js:

var sudo = require('sudo-prompt')
var options = {
  name: 'Electron',
}

export default (shell) => {
  return new Promise((resolve, reject) => {
    sudo.exec(shell, options, function(error, stdout, stderr) {
      if (error) {
        reject(error)
        console.log('error:' + error)
        return
      }
      resolve(stdout)
      console.log('stdout: ' + stdout)
    })
  })
}
// npm i https://github.com/xuxingeren/sudo-prompt
"sudo-prompt": "git+https://github.com/xuxingeren/sudo-prompt.git",

注意:sudo-prompt這個包很久沒維護了,現在最新的還有一些問題,主要是帶有中文路徑會出錯,原作者已經關閉了提不了pr,我這邊處理了一下,使用的話可以fork我的分支來進行構建,地址

主程式更新處理

更新前的準備以及渲染程式處理這裡就略過了,請見前面兩期內容

import downloadFile from './downloadFile'
import sudoPrompt from './sudoPrompt'
import { app } from 'electron'
const fse = require('fs-extra')
const path = require('path')
const AdmZip = require('adm-zip')
import log from '../config/log.js'

export default async (data) => {
  const resourcesPath = process.resourcesPath
  // 下載我們上面打包好的更新exe,我這裡是放在app.getPath('userData')下的,其他位置也可
  if (!fse.pathExistsSync(path.join(app.getPath('userData'), './update.exe'))) {
    await downloadFile({
      url: data.upDateExe,
      targetPath: app.getPath('userData')
    }).catch((err) => {
      console.log(err)
      log.info(err)
    })
  }
  // 提權的方案,這裡簡寫了
  const downloads = app.getPath('downloads')
  // 下載update.asar,解壓(其實不用壓縮也可)在系統的下載目錄
  downloadFile({ url: data.upDateUrl, targetPath: downloads })
    .then(async (filePath) => {
      const zip = new AdmZip(filePath)
      zip.extractAllToAsync(downloads, true, (err) => {
        if (err) {
          console.error(err)
          return
        }
        fse.removeSync(filePath)
        // 這裡可以新增判斷,如果軟體是安裝在c盤使用sudoPrompt進行提權執行update.exe,不是的話可以直接執行update.exe
        // 臨時提權執行exe,exe中關閉主程式,替換安裝c盤中的asar(提權是為了處理c盤,如果安裝其他盤,可以直接用node.exec執行exe替換)
        // 由於提權後的exe開啟electron,導致其啟動後也會是管理員許可權,故需降權進行啟動,explorer.exe
        sudoPrompt(
          `"${path.join(
            app.getPath('userData'),
            './update.exe'
          )}" "${resourcesPath}" ${downloads} "${
            process.env.VUE_APP_PRODUCTNAME
          }.exe" "${app.getPath('exe')}"`
        )
      })
    })
    .catch((err) => {
      log.info(err)
      console.log(err)
    })
}

手動除錯的話你可以在cmd中執行update.exe xxx xxx xxx xxx傳入對應更新的地址看執行是否成功。

本系列更新只有利用週末和下班時間整理,比較多的內容的話更新會比較慢,希望能對你有所幫助,請多多star或點贊收藏支援一下

本文地址:連結
本文github地址:連結

相關文章