深入浅出Electron:原理、工程与实践
上QQ阅读APP看书,第一时间看更新

3.4 辅助工具app-builder

在上一节介绍的代码中,getBinFromUrl方法拼接好下载的url,并把这个url传递给了getBin方法。getBin方法把这个url转换成命令行参数,传递给了一个应用程序app-builder.exe,由它负责下载对应的文件,代码逻辑如下:

export function download(url: string, output: string, checksum?: string | null): Promise<void> {
  const args = ["download", "--url", url, "--output", output]
  if (checksum != null) {
    args.push("--sha512", checksum)
  }
  return executeAppBuilder(args) as Promise<any> // 此方法最终调用了app-builder.exe
}

executeAppBuilder方法使用Node.js子进程控制的API启动了app-builder.exe,并把命令行参数传递给了app-builder.exe。后面会介绍Node.js子进程控制的使用方式。

这里不单是Electron的二进制包,包括签名工具、资源修改工具、打包工具,都是由app-builder.exe负责下载并缓存的。大部分这些工具的使用也是由它来完成调用的,可以说它就是electron-builder的辅助工具之母。

app-builder(https://github.com/develar/app-builder)是由electron-builder的主要作者develar使用Go语言开发的,在这个工具中也使用了ELECTRON_BUILDER_CACHE环境变量来缓存文件,如下是它获取缓存目录的逻辑:

func GetCacheDirectory(appName string, envName string, isAvoidSystemOnWindowsbool) (string, error) {
  env := os.Getenv(envName)
  if len(env) != 0 {
    return env, nil
  }
  currentOs := util.GetCurrentOs()
  if currentOs == util.MAC {
    userHomeDir, err := homedir.Dir()
    if err != nil {
      return "", errors.WithStack(err)
    }
    return filepath.Join(userHomeDir, "Library", "Caches", appName), nil
  }
  if currentOs == util.WINDOWS {
    localAppData := os.Getenv("LOCALAPPDATA")
    if len(localAppData) != 0 {
      if isAvoidSystemOnWindows && strings.Contains(strings.ToLower(localAppData), "\\ windows\\ system32\\ ") || strings.ToLower(os.Getenv("USERNAME")) == "system" {
        return filepath.Join(os.TempDir(), appName+"-cache"), nil
      }
      return filepath.Join(localAppData, appName, "Cache"), nil
    }
  }
  xdgCache := os.Getenv("XDG_CACHE_HOME")
  if xdgCache != "" {
    return filepath.Join(xdgCache, appName), nil
  }
  userHomeDir, err := homedir.Dir()
  if err != nil {
    return "", errors.WithStack(err)
  }
  return filepath.Join(userHomeDir, ".cache", appName), nil
}

如果下载的是签名工具或打包工具,那么这个envName的值就是ELECTRON_BUILDER_CACHE。也就是说,如果设置了ELECTRON_BUILDER_CACHE环境变量,则使用这个环境变量的值;如果没有设置,则计算一个默认值。一般情况下这个计算出来的值所指向的路径为:

C:\Users\yourUserName\AppData\Local\electron-builder\Cache

如果下载的是Electron的二进制包,那么这个envName的值就是electron_config_cache环境变量对应的值。如果开发者没有配置这个环境变量,它的默认值应为:

C:\Users\[yourUserName]\AppData\Local\electron\Cache

下载的过程并无太多出奇的地方,且与普通开发者关系不大,值得一提的是,作者非常细心,不但提供了下载失败后的重连能力、代理能力、下载过程和记录日志,甚至会验证下载文件的哈希值是否合法。

启动外部工具也与Node.js的子进程控制方式非常相似:准备目标程序路径,生成命令行指令,对接标准输入、输出流等;由于是Go语言完成的逻辑,这里不再多做介绍。