feat: add native macOS dynamic app icon (#1402)
* feat: add native macOS dynamic app icon Adds Icon Composer source and compiled Assets.car for macOS Packages the dynamic icon asset into the Electron app Adds a script to regenerate macOS icon assets * fix: harden macOS icon asset scripts
This commit is contained in:
committed by
GitHub
parent
0c8301d579
commit
3f3b835ee9
@@ -0,0 +1,17 @@
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
module.exports = (context) => {
|
||||
if (context.electronPlatformName !== 'darwin') return;
|
||||
|
||||
const appName = context.packager.appInfo.productFilename;
|
||||
const appBundlePath = path.join(context.appOutDir, `${appName}.app`);
|
||||
const resourcesPath = path.join(appBundlePath, 'Contents', 'Resources');
|
||||
const sourceAssetsPath = path.join(__dirname, '..', 'resources', 'icons', 'Assets.car');
|
||||
|
||||
if (!fs.existsSync(sourceAssetsPath)) {
|
||||
throw new Error(`Missing compiled app icon asset catalog at ${sourceAssetsPath}`);
|
||||
}
|
||||
|
||||
fs.copyFileSync(sourceAssetsPath, path.join(resourcesPath, 'Assets.car'));
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
const { execFileSync } = require('node:child_process');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
|
||||
const iconName = 'AppIcon';
|
||||
const iconsDir = path.join(__dirname, '..', 'resources', 'icons');
|
||||
const sourceIconPath = path.join(iconsDir, `${iconName}.icon`);
|
||||
const outputAssetsPath = path.join(iconsDir, 'Assets.car');
|
||||
|
||||
const resolveActool = () => {
|
||||
try {
|
||||
return execFileSync('xcrun', ['--find', 'actool'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
||||
} catch {
|
||||
const xcodeActool = '/Applications/Xcode.app/Contents/Developer/usr/bin/actool';
|
||||
if (fs.existsSync(xcodeActool)) return xcodeActool;
|
||||
throw new Error('Unable to find actool. Install Xcode or set DEVELOPER_DIR to a full Xcode installation.');
|
||||
}
|
||||
};
|
||||
|
||||
if (!fs.existsSync(sourceIconPath)) {
|
||||
throw new Error(`Missing Icon Composer source at ${sourceIconPath}`);
|
||||
}
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-app-icon-'));
|
||||
try {
|
||||
execFileSync(resolveActool(), [
|
||||
sourceIconPath,
|
||||
'--compile', tmpDir,
|
||||
'--app-icon', iconName,
|
||||
'--platform', 'macosx',
|
||||
'--target-device', 'mac',
|
||||
'--minimum-deployment-target', '13.0',
|
||||
'--output-partial-info-plist', path.join(tmpDir, 'partial.plist'),
|
||||
], { stdio: 'inherit' });
|
||||
|
||||
const generatedAssetsPath = path.join(tmpDir, 'Assets.car');
|
||||
if (!fs.existsSync(generatedAssetsPath)) {
|
||||
throw new Error(`actool did not generate Assets.car at ${generatedAssetsPath}`);
|
||||
}
|
||||
|
||||
fs.copyFileSync(generatedAssetsPath, outputAssetsPath);
|
||||
console.log(`Generated ${outputAssetsPath}`);
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
Reference in New Issue
Block a user