On the TV the update stopped at "Bible App cannot be closed", and uninstalling from Windows Settings showed "Installer integrity check has failed". The cause is the uninstaller, not anything running. An update runs the PREVIOUS version's uninstaller first. Versions 1.4.35-1.4.37 were built on macOS, where electron-builder can't run NSIS to write the uninstaller and rebuilds it in JavaScript (UninstallerReader) from the installer's stub — without NSIS's icon patch. makensis computes the uninstaller's CRC over the stub WITH the uninstaller icon in it, so whenever the two icons differ the result fails NSIS's integrity check. With no app icon configured, NSIS uses its two different default icons, so every Mac-built uninstaller was damaged. Verified with a reimplementation of NSIS's loadHeaders() check: the shipped installers pass; the captured uninstaller failed (0x4235c8f5 vs stored 0x90f7de2c) and passes with this fix (0xb37e533c). - build/installerIcon.ico: NSIS's own default install icon, so electron-builder uses ONE icon for installer and uninstaller (nothing looks different; the app's icon is unchanged). tools/build-win.cjs refuses to build without it. - build/installer.nsh: for installs of 1.4.35-1.4.37 only, clear the old UninstallString so the damaged uninstaller is not run; the new files are copied over the old ones and a fresh, valid uninstaller is written. Every other version keeps the normal uninstall-then-install path. - BUILD-AND-DEPLOY.md: why the icon file must stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
2.4 KiB
JavaScript
49 lines
2.4 KiB
JavaScript
/*
|
|
* build-win.cjs — build the Windows x64 installer. Works on Windows AND on macOS: electron-builder
|
|
* fetches its own mac build of wine for the few Windows-only steps, so the laptop can produce the
|
|
* exact installer the stage PC installs.
|
|
*
|
|
* npm run build:win
|
|
*
|
|
* Two things this wrapper exists to guarantee:
|
|
*
|
|
* - --x64. electron-builder otherwise targets the HOST architecture, so on an Apple Silicon Mac a
|
|
* plain `electron-builder --win` quietly produces an arm64 build that the stage PC cannot run.
|
|
* - a clean signing environment. There is no code-signing certificate. electron-builder aborts on
|
|
* an EMPTY WIN_CSC_LINK ("Env WIN_CSC_LINK is not correct"), so those variables are removed
|
|
* rather than blanked, and identity auto-discovery is turned off.
|
|
* - a working uninstaller. On macOS electron-builder rebuilds the NSIS uninstaller in JavaScript and
|
|
* skips NSIS's icon patch, so unless the installer and uninstaller use the SAME icon the uninstaller
|
|
* fails NSIS's integrity check — and then that version can never be updated or uninstalled
|
|
* (1.4.35-1.4.37 shipped like that). build/installerIcon.ico makes electron-builder use one icon for
|
|
* both, so this refuses to build without it.
|
|
*/
|
|
const { spawnSync } = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const env = { ...process.env, CSC_IDENTITY_AUTO_DISCOVERY: 'false' };
|
|
for (const key of ['CSC_LINK', 'WIN_CSC_LINK', 'CSC_KEY_PASSWORD', 'WIN_CSC_KEY_PASSWORD', 'CSC_KEYCHAIN']) {
|
|
delete env[key];
|
|
}
|
|
|
|
const ICON = path.join(__dirname, '..', 'build', 'installerIcon.ico');
|
|
if (!fs.existsSync(ICON)) {
|
|
console.error('build/installerIcon.ico is missing. Without it the uninstaller built on macOS is damaged');
|
|
console.error('("Installer integrity check has failed") and the version could never be updated. See tools/build-win.cjs.');
|
|
process.exit(1);
|
|
}
|
|
|
|
const extra = process.argv.slice(2);
|
|
const args = ['electron-builder', '--win', '--x64', ...extra];
|
|
|
|
console.log(`Building the Windows x64 installer on ${process.platform}…`);
|
|
const r = spawnSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', args, {
|
|
cwd: path.join(__dirname, '..'),
|
|
env,
|
|
stdio: 'inherit',
|
|
shell: process.platform === 'win32'
|
|
});
|
|
if (r.error) { console.error('Build failed to start:', r.error.message); process.exit(1); }
|
|
process.exit(r.status === null ? 1 : r.status);
|