美化nwjs生成的桌面程序安装包

Posted 蔚蓝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了美化nwjs生成的桌面程序安装包相关的知识,希望对你有一定的参考价值。

上期讲到用nw.js打包vuecli3创建的项目为桌面程序:传送门:使用nw.js将vue项目打包为可在xp系统运行的桌面程序。打包完成之后却发现打包出来的是一个文件夹,里面有可执行程序exe和一堆环境或资源文件,这么一个文件夹丢给客户安装显然太不优雅。
这期就讲下如何将这一堆东西美化成一个.exe安装包。本文先粗浅研究美化程序在vuecli3项目上的实现,主要参考不爱吃西红柿的文章:用 vue2 和 webpack 快速建构 NW.js 项目(3),并将其修改为在vuecli3项目上的实现。

美化nwjs安装包

上个文章已经完成了vuecli3项目打包成.exe,现在接着处理美化程序。

先安装相关依赖

npm install iconv-lite innosetup-compiler --save-dev

创建config/setup.iss文件

复制即可,后面理解了可以自行修改;另外如果安装包出现乱码,可将setup.iss文件修改后缀为txt然后以ansi格式保存后再改回setup.iss
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
; This CWD is the directory where the `setup.iss`, pay attention to join the relative directory!
; 该执行目录为 `setup.iss` 所在的目录,请注意拼接相对目录

#define MyAppName "_name_"
#define MyAppAliasName "_appName_"
#define MyAppVersion "_version_"
#define MyAppPublisher "_appPublisher_"
#define MyAppURL "_appURL_"
#define MyAppExeName "_name_.exe"
#define OutputPath "_outputPath_"
#define OutputFileName "_outputFileName_"
#define SourceMain "_filesPath_\\_name_.exe"
#define SourceFolder "_filesPath_\\*"
#define LicenseFilePath "_resourcesPath_\\license.txt"
#define SetupIconFilePath "_resourcesPath_\\logo.ico"
#define MyAppId "_appId_"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={#MyAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppAliasName}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\\{#MyAppName}
LicenseFile={#LicenseFilePath}
OutputDir={#OutputPath}
OutputBaseFilename={#OutputFileName}
SetupIconFile={#SetupIconFilePath}
Compression=lzma
SolidCompression=yes
PrivilegesRequired=admin
Uninstallable=yes
UninstallDisplayName={#MyAppAliasName}
DefaultGroupName={#MyAppAliasName}

[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce

[Files]
Source: {#SourceMain}; DestDir: "{app}"; Flags: ignoreversion
Source: {#SourceFolder}; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Messages]
SetupAppTitle={#MyAppAliasName} setup wizard
SetupWindowTitle={#MyAppAliasName} setup wizard

[Icons]
Name: "{commondesktop}\\{#MyAppAliasName}"; Filename: "{app}\\{#MyAppExeName}"; Tasks: desktopicon
Name: "{group}\\{#MyAppAliasName}"; Filename: "{app}\\{#MyAppExeName}"
Name: "{group}\\uninstall {#MyAppAliasName}"; Filename: "{uninstallexe}"

[Run]
Filename: "{app}\\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, \'&\', \'&&\')}}"; Flags: nowait postinstall skipifsilent

新增build/setup.js

var innosetupCompiler = require(\'innosetup-compiler\')
var path = require(\'path\')
var fs = require(\'fs\')
var iconv = require(\'iconv-lite\')
function resolve() {
  return path.resolve.apply(path, [__dirname, \'..\'].concat(...arguments))
}
var rootPath = path.resolve(__dirname, \'../\')

// `./package.json`
var tmpJson = require(path.resolve(rootPath, \'./package.json\'))
var curReleasesPath = resolve(\'./releases\');
// 约定性配置
var setupOptions = {
  issPath: resolve(\'./config/setup.iss\'),
  // only one version path
  files: curReleasesPath,
  resourcesPath: resolve(\'./build/setup_resources\'),
  appPublisher: \'nw-vue-demo, Inc.\',
  appURL: \'your url\',
  appId: \'{{your id}}\',
  // data: { name, version, platform }
};

fs.readdir(setupOptions.files, function (err, files) {
  if (err) throw err
  files.forEach(function (fileName) {
    if (!~fileName.indexOf(\'win\')) return

    const curPath = path.resolve(setupOptions.files, fileName)
    fs.stat(curPath, function (err, stats) {
      if (err || stats.isFile()) return
      if (stats.isDirectory()) {
        makeExeSetup(Object.assign({}, setupOptions, { files: curPath, platform: fileName }))
      }
    })
  })
})

function makeExeSetup(opt) {
  const { issPath, files, resourcesPath, appPublisher, appURL, appId, platform } = opt
  const { name, version } = tmpJson
  const tmpIssPath = path.resolve(path.parse(issPath).dir, \'_tmp.iss\')

  return new Promise(function (resolve, reject) {
    // rewrite name, version to iss
    fs.readFile(issPath, null, function (err, text) {
      if (err) return reject(err)
      // 这里是iss文件里的变量配置的地方
      let str = iconv.decode(text, \'gbk\')
        .replace(/_name_/g, name) // 名字
        .replace(/_appName_/g, name) // app名字,这里用name代替
        .replace(/_version_/g, version) // 版本
        .replace(/_outputPath_/g, \'app\') // 美化程序输出的路径,这里写死config/app,则美化程序打包后将在config/app/下生成
        .replace(/_outputFileName_/g, name + version) // 输出的文件名
        .replace(/_filesPath_/g, files) // 要打包的文件路径
        .replace(/_resourcesPath_/g, resourcesPath) // 资源路径,主要是图标、安装协议等,复制build下的setup_resources目录即可
        .replace(/_appPublisher_/g, appPublisher) // 软件出版商,自己写
        .replace(/_appURL_/g, appURL) // app线上路径
        .replace(/_appId_/g, appId) // appid


      fs.writeFile(tmpIssPath, iconv.encode(str, \'gbk\'), null, function (err) {
        if (err) return reject(err)

        // inno setup start
        innosetupCompiler(tmpIssPath, { gui: false, verbose: true }, function (err) {
          fs.unlinkSync(tmpIssPath)
          if (err) return reject(err)
          resolve(opt)
        })
      })
    })
  })
}

主要的调整修改就是在setup.js文件

修改完成,先打包nw文件,再打包美化文件

yarn build:nw
yarn setup

项目地址:

Github

以上是关于美化nwjs生成的桌面程序安装包的主要内容,如果未能解决你的问题,请参考以下文章

使用nwjs开发桌面应用之Hello,World!

cxfreeze打包python程序的方法说明(生成安装包,实现桌面快捷方式删除快捷方式)

nwjs-打包

学会这 9 个 Android 手机美化技巧,就像换台新手机

Debian 9 美化界面

nwjs-简介