Skip to content

Conversation

@iamEvanYT
Copy link

@iamEvanYT iamEvanYT commented Sep 17, 2025

closes #9254
closes #9278


This PR updates the "icon" property to the electron-builder configuration which adds support for icons made with Icon Composer (.icon format).

On building, it will create an Assets.car with the icon which will be bundled inside the app's Resources folder.

@changeset-bot
Copy link

changeset-bot bot commented Sep 17, 2025

🦋 Changeset detected

Latest commit: 0ef3fde

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
app-builder-lib Major
dmg-builder Major
electron-builder-squirrel-windows Major
electron-builder Major
electron-forge-maker-appimage Major
electron-forge-maker-nsis-web Major
electron-forge-maker-nsis Major
electron-forge-maker-snap Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Kilian
Copy link
Contributor

Kilian commented Sep 19, 2025

would this support shipping both a .icon for Tahoe+ and an .icns for older mac versions?

@mmaietta
Copy link
Collaborator

would this support shipping both a .icon for Tahoe+ and an .icns for older mac versions?

@Kilian Do you know if those are separate "fields" perceived by mac? e.g., if we package both an icns and an icon, only Taho can read the new value?
Basically, do we know if Mac will render an icon file on older versions of macOS or is it only macOS 26+ "visible"?

I haven't gotten around to updating my mac to Tahoe yet as I'm afraid it'll brick my current dev environment while I'm mid-project. This is indeed on the todo list though

@iamEvanYT
Copy link
Author

iamEvanYT commented Sep 19, 2025

@mmaietta @Kilian I have tested on macOS Sequoia and with both the .icon and .icns file bundled, it will choose the .icon file and display a static version on it. I assume its the same for other macOS versions, but haven't tested.


Update 1:

Screenshot 2025-09-20 at 2 26 22 PM

The plist property seems to be available since macOS 10.13+, which should mean that the Liquid Glass icon will be visible since that macOS version.


Update 2:

Tested with macOS Monterey and confirmed that it does show there.

Screenshot 2025-09-20 at 17 09 14

@mmaietta
Copy link
Collaborator

mmaietta commented Sep 22, 2025

Thank you @iamEvanYT !

In this case then, I'd like to refactor this PR to instead leverage the icon, but I still need to check dmg-builder to see if/how the .icon would be rendered. Will try to get back to this asap

Is there a minimum xcode or macos version required for supporting this CLI tool? Wondering if we need to throw a more descriptive error if the tool command doesn't exist

@iamEvanYT
Copy link
Author

@mmaietta I did a few commits a few days ago to change to the icon property which should work. As for the minimum Xcode version, it should be Xcode 26. There is a check for macOS Tahoe in the icon-composer.ts file, which should cover errors in CI.

@mmaietta
Copy link
Collaborator

This is looking solid! Any chance we can add a .icon test fixture to integrate this into one of the mac unit tests?

@iamEvanYT
Copy link
Author

iamEvanYT commented Sep 26, 2025

@mmaietta There, the tests passed on my computer, so it should theoretically pass on the CI. However, it may not pass as it still uses the old Xcode SDK and not Xcode 26. In that case, we might have to change the CI runner from macos-latest to macos-26, but it may not be ideal.


Edit:

Huh, it seems like the macIconTest file isn't being ran in CI. I wonder if that's intentional?

I've added a commit that runs the macIconTests on macos-26 in the CI, but let me know if you want me to revert that.

@mmaietta
Copy link
Collaborator

mmaietta commented Sep 27, 2025

I took a look at dmg-builder and it does seem to indeed rely on an icns file., but it's in its own config param dmg.icon and does not inherit from mac.icon, so we should be good there!

Thank you for your great work on this PR and I appreciate your flexibility in working through these iterations

@mmaietta
Copy link
Collaborator

FYI, this LGTM, but I need to fix the core test-updater test suite before I can merge this. Working on this currently and hope to resolve asap

@erikolofsson
Copy link

I tried this out and fixed the following problems:

  • Didn't work with universal build because Assets.car was different between x64 and arm64
  • Didn't populate Icon.icns in Resources and setup in plist for compatibility with older OSes
  • It didn't detect the versions properly on macOS 15 (acToolVersionOutput was empty after spawn), so I just removed the version checks. It still worked fine with Xcode 26 installed on macOS 15.

Feel free to cherry-pick from c4ccbb5

Other problems I ran into and worked around:

  • If you set mac.icon to a .icon file Linux AppImage build fails
  • I had to work around the dmg problem by generating the compatibility .icns and setting dmg.icon. It would be more convenient if it used the Icon.icns generated automatically by actool.

@iamEvanYT
Copy link
Author

@erikolofsson, thanks for helping test out this PR!

Didn't work with universal build because Assets.car was different between x64 and arm64

Good catch, thank you!

Didn't populate Icon.icns in Resources and setup in plist for compatibility with older OSes

This isn't needed as the Liquid Glass icon will show on macOS versions 10.13+ and the latest chromium versions won't support macOS with such old versions.

Screenshot from Latest Chromium Version's Info.plist:
Screenshot 2025-10-09 at 12 06 09 AM

It didn't detect the versions properly on macOS 15 (acToolVersionOutput was empty after spawn), so I just removed the version checks. It still worked fine with Xcode 26 installed on macOS 15.

I agree that the macOS version check could be removed, but the actool version check shouldn't, as removing it could lead to unexpected errors.

If you set mac.icon to a .icon file Linux AppImage build fails

What was the problem? How did you work around it?

I had to work around the dmg problem by generating the compatibility .icns and setting dmg.icon. It would be more convenient if it used the Icon.icns generated automatically by actool.

I didn't know that it generats a .icns file! I'll check it out.


Screenshot 2025-10-09 at 12 12 22 AM

What difference does this change make? Does icons not show on older versions with this set to 26.0?

@erikolofsson
Copy link

This isn't needed as the Liquid Glass icon will show on macOS versions 10.13+ and the latest chromium versions won't support macOS with such old versions.

Ok, granted that it works. You can however look at the partial plist that actool generates, where it seems Apple thinks you should set the CFBundleIconFile and include the icns file in Resources.

Also if you don't set it you end up with this, which seems unecessary:

    <key>CFBundleIconFile</key>
    <string>electron.icns</string>

Could you also use older Electron versions with electron-builder where older OSes are supported?

When you try to run it on an older OS version you still see the icon with a stop sign overlayed, so that would also be a scenario. The oldest VM I have is 10.13, so I can't check what happens on older OSes.

I agree that the macOS version check could be removed, but the actool version check shouldn't, as removing it could lead to unexpected errors.

If you have macOS 15 to try on you can try to debug it, but it could also have been the environment I was running in, maybe you can run the check after actool has failed instead and do it as an extra explanation? Because now it could be an unnecessary source of errors if actool would have worked.

If you set mac.icon to a .icon file Linux AppImage build fails

What was the problem? How did you work around it?

It tried to extract an icon from the file in mac.icon it seems. Got the same error when trying to generate a DMG without setting dmg.icon. I had it set as:

icon: "icon.png"
mac.icon: "icon.icon"

My workaround was to create separate config file when I built for Linux which set mac.icon to icon.png.

What difference does this change make? Does icons not show on older versions with this set to 26.0?

I tried it out now and it seems that it generates the .icns file anyway when set to 26.0. You should probably set it to the version supported by Electron bundled in the build.

@iamEvanYT
Copy link
Author

Ok, granted that it works. You can however look at the partial plist that actool generates, where it seems Apple thinks you should set the CFBundleIconFile and include the icns file in Resources.

I manually ran the actool command and there is nothing inside the generated plist, so I don't know where you're getting the icns file from.

Screenshot 2025-10-09 at 6 20 07 PM

@erikolofsson
Copy link

I manually ran the actool command and there is nothing inside the generated plist, so I don't know where you're getting the icns file from.

--app-icon has to have the same name as the .icon file.

Example:

	xcrun actool \
		--compile "$ACTOOL_TMP" \
		--platform macosx \
		--minimum-deployment-target 12.0 \
		--output-partial-info-plist "$ACTOOL_PLIST" \
		--warnings \
		--notices \
		--compress-pngs \
		--app-icon "$1" \
		"$PWD/build/$1.icon"

@mmaietta
Copy link
Collaborator

Quite a conversation happening here. @iamEvanYT, is this ready for review?

@iamEvanYT
Copy link
Author

@mmaietta not yet, i'll try to get the improvements ready as soon as possible.

@iamEvanYT
Copy link
Author

iamEvanYT commented Oct 12, 2025

@erikolofsson I should have fixed most of the problems that you mentioned now. Thank you for flagging them!

  • Removed macOS version check
  • Cloned .icns file too as fallback
  • DMGs should use the icon
  • Fixed linux builds (Filtered out the .icon file from available icons)

@erikolofsson Would you mind testing the linux builds for me? I don't have a linux machine so I couldn't.


@mmaietta The PR ready for review now.

@iamEvanYT iamEvanYT requested a review from mmaietta October 12, 2025 00:17
@erikolofsson
Copy link

We end up with this:

    <key>CFBundleIconFile</key>
    <string>icon.icns</string>
    <key>CFBundleIconName</key>
    <string>Icon</string>

It doesn't match up with convention and what is output from the partial plist where .icns is omitted from the file name, and the capitalized Icon is used. It's probably ok, but it would be safer to use standard naming to mimic what Xcode does. Another example:

defaults read /Applications/Numbers.app/Contents/Info.plist | grep Icon
    CFBundleIconFile = AppIcon;
    CFBundleIconName = AppIcon;

Also the version parsing is still failing on my macOS 15 build server:

 • spawning        command=actool --version
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.actool.version</key>
    <dict>
        <key>bundle-version</key>
        <string>24128</string>
        <key>short-bundle-version</key>
        <string>26.0.1</string>
    </dict>
</dict>
</plist>
  • exited          command=actool code=0 pid=8366
[xmldom error]    invalid doc source 
@#[line:0,col:undefined]
  ⨯ Cannot read properties of undefined (reading 'documentElement')  failedTask=build stackTrace=TypeError: Cannot read properties of undefined (reading 'documentElement')
    at Object.parse (.../node_modules/plist/lib/parse.js:68:9)
    at generateAssetCatalogForIcon (.../node_modules/app-builder-lib/src/util/macosIconComposer.ts:12:29)
    at processTicksAndRejections (node:internal/process/task_queues:105:5)
    at MacPackager.applyCommonInfo (.../node_modules/app-builder-lib/src/macPackager.ts:558:44)
    at createMacApp (.../node_modules/app-builder-lib/src/electron/electronMac.ts:118:3)
    at beforeCopyExtraFiles (.../node_modules/app-builder-lib/src/electron/ElectronFramework.ts:85:5)
    at MacPackager.doPack (.../node_modules/app-builder-lib/src/platformPackager.ts:321:7)
    at MacPackager.doPack (.../node_modules/app-builder-lib/src/macPackager.ts:156:9)
    at MacPackager.pack (.../node_modules/app-builder-lib/src/macPackager.ts:254:9)
    at Packager.doBuild (.../node_modules/app-builder-lib/src/packager.ts:507:11)

@erikolofsson
Copy link

This fixes the macOS 15 version parsing:
947ff62

Also universal builds are broken again. Guessing because of this:

        // @ts-expect-error - this is an override for compatibility
        this.platformSpecificBuildOptions.icon = tempIcnsFile

The problem is that the arm64 build now builds without the .icon file so Info.plist is different between the builds.

@iamEvanYT
Copy link
Author

iamEvanYT commented Oct 14, 2025

It doesn't match up with convention and what is output from the partial plist where .icns is omitted from the file name, and the capitalized Icon is used.

@erikolofsson For the icon.icns naming, I just took the naming from the implementation of icns files for consistency and to avoid breaking changes. @mmaietta What do you think?


For the other issues, are they fixed now?

@erikolofsson
Copy link

For the other issues, are they fixed now?

macOS builds correctly now. Still have the Linux failure:

  • building        target=AppImage arch=x64 file=<app>-1.0.189.AppImage
  • no event listeners found  event=artifactBuildStarted
  • spawning        command=<RootPath>/node_modules/app-builder-bin/mac/app-builder_arm64 icon --format set --root <RootPath>/build --root <RootPath> --out <RootPath>/dist/.icon-set --input icon_test.icon --fallback-input <RootPath>/node_modules/app-builder-lib/templates/icons/electron-linux
  • path resolved   path=<RootPath>/build/icon_test.icon outputFormat=set
  ⨯ icon directory <RootPath>/build/icon_test.icon doesn't contain icons
github.com/develar/app-builder/pkg/icons.CollectIcons
    /Users/runner/work/app-builder/app-builder/pkg/icons/collect-icons.go:73
github.com/develar/app-builder/pkg/icons.doConvertIcon
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:199
github.com/develar/app-builder/pkg/icons.ConvertIcon
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56
github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33
github.com/alecthomas/kingpin.(*actionMixin).applyActions
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/actions.go:28
github.com/alecthomas/kingpin.(*Application).applyActions
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:557
github.com/alecthomas/kingpin.(*Application).execute
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:390
github.com/alecthomas/kingpin.(*Application).Parse
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:222
main.main
    /Users/runner/work/app-builder/app-builder/main.go:90
runtime.main
    /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267
runtime.goexit
    /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_arm64.s:1197
github.com/develar/app-builder/pkg/icons.doConvertIcon
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:201
github.com/develar/app-builder/pkg/icons.ConvertIcon
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56
github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1
    /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33
github.com/alecthomas/kingpin.(*actionMixin).applyActions
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/actions.go:28
github.com/alecthomas/kingpin.(*Application).applyActions
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:557
github.com/alecthomas/kingpin.(*Application).execute
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:390
github.com/alecthomas/kingpin.(*Application).Parse
    /Users/runner/go/pkg/mod/github.com/alecthomas/[email protected]+incompatible/app.go:222
main.main
    /Users/runner/work/app-builder/app-builder/main.go:90
runtime.main
    /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267
runtime.goexit
    /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_arm64.s:1197
  • exited          command=app-builder_arm64 code=1 pid=77581

I'm building the Linux build from a macOS host

		"linux": {
			"category": "Office",
			"target": [
				{
					"target": "AppImage",
					"arch": [
						"x64"
					]
				}
			]
		},
		
electron-builder -l --x64

@iamEvanYT
Copy link
Author

Still have the Linux failure

@erikolofsson Does it work now?

@erikolofsson
Copy link

@erikolofsson Does it work now?

Yes, everything works now.

@iamEvanYT
Copy link
Author

@mmaietta Any idea what's causing the tests to fail? I don't think I have changed anything relating to those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Support Liquid Glass Icons for macOS 26 MacOS 26 .icon compatibility

4 participants