apache / cordova-ios

Apache Cordova iOS
https://cordova.apache.org/
Apache License 2.0
2.16k stars 986 forks source link

feat(icons)!: Support a single 1024⨉1024 icon, but also more complex customizations #1465

Closed dpogue closed 3 months ago

dpogue commented 3 months ago

Platforms affected

iOS (watchOS, and macOS Catalyst technically)

Motivation and Context

Xcode now supports generating all the app icons sizes automatically from a single 1024⨉1024 PNG image. Supporting this drastically simplifies the requirements for app developers.

That said, there are cases where an app developer might want to provide specific icons for specific situations (such as watchOS notifications, or a macOS Catalyst app) and historically Cordova has been pretty bad at supporting those customizations due to relying solely on image sizes to handle mappings.

iOS 18 is also introducing dark mode and tinted app icon variants, and we need a way to support those.

Description

Simple case

For the simplest case, an app developer can provide a single 1024⨉1024 icon image and list it in their config.xml file with no attributes:

<platform name="ios">
    <icon src="appicon.png" />
</platform>

With iOS 18 variants

We make use of the foreground and monochrome attributes, already supported in Cordova Android, to handle the dark mode and tint-able icon variants.

The dark mode icon should have a transparent background (hence, the foreground attribute). The tint-able icon should be a greyscale mask that gets multiplied by the system tint colour (hence, the monochrome attribute).

Example images: sampleicon sampleicon-dark sampleicon-tint

Example config:

<platform name="ios">
    <icon src="appicon.png" foreground="appicon-dark.png" monochrome="appicon-tint.png" />
</platform>

You can provide variants for all iOS icons (but variants are not supported on watchOS or macOS Catalyst).

Platform-specific icons

Apple watchOS supports the same automatic generation of icons from a single 1024⨉1024 icon. By default this will use the app icon, but it can be overridden by providing another icon with a target attribute.

<platform name="ios">
    <icon src="appicon.png" />
    <icon src="watchicon.png" target="watchos" />
</platform>

Supported targets are watchos and mac. There's a special case target spotlight for iOS to disambiguate some icons that otherwise have identical sizes (only applicable if you are providing all your own icon sizes).

The macOS icons do not support a single 1024⨉1024 image, so if you want to customize those then you will need to provide all the required icon sizes yourself.

Providing all the icon sizes

If you prefer to provide all the icons yourself, you can still do so. Note that if you provide any sized icons, you are required to provide all the sized icons for that platform.

<platform name="ios">
    <icon src="appicon-40.png" width="40" height="40" />
    <icon src="appicon-58.png" width="58" height="58" />
    <icon src="appicon-60.png" width="60" height="60" />
    <icon src="appicon-72.png" width="72" height="72" />
    <icon src="appicon-80.png" width="80" height="80" target="spotlight" />
    <icon src="appicon-87.png" width="87" height="87" />
    <icon src="appicon-120.png" width="120" height="120" />
    <icon src="appicon-120.png" width="120" height="120" target="spotlight" />
    <icon src="appicon-128.png" width="128" height="128" />
    <icon src="appicon-136.png" width="136" height="136" />
    <icon src="appicon-144.png" width="144" height="144" />
    <icon src="appicon-152.png" width="152" height="152" />
    <icon src="appicon-167.png" width="167" height="167" />
    <icon src="appicon-180.png" width="180" height="180" />
    <icon src="appicon-196.png" width="196" height="196" />
    <icon src="appicon-1024.png" width="1024" height="1024" />
</platform>

You can also provide all the icons for the watchos and mac targets, with all their respective sizes.

Testing

Closed issues

Closes #592. Closes #623. Closes #657. Closes #658. Closes #1019. Closes #1233. Closes #1387. Closes #1462.

Checklist

codecov-commenter commented 3 months ago

Codecov Report

Attention: Patch coverage is 90.90909% with 7 lines in your changes missing coverage. Please review.

Project coverage is 80.22%. Comparing base (3a426fd) to head (d63d690).

Files Patch % Lines
lib/prepare.js 90.90% 7 Missing :warning:
Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #1465 +/- ## ========================================== + Coverage 78.31% 80.22% +1.91% ========================================== Files 16 16 Lines 1826 1871 +45 ========================================== + Hits 1430 1501 +71 + Misses 396 370 -26 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

dpogue commented 3 months ago

We've got one issue to sort out here, and it's related to the new iOS 18 icon variants and Xcode support.

Icon variants are only supported/understood by Xcode 16. If you set up icon variants, and then open the project in Xcode 15 (or lower) it will see 3 icons trying to fill the same slot and pick one at random (and almost always one of the variants instead of the default icon). I already tried reordering the icons in Contents.json and that did not produce consistent behaviour 😞

One option (and the easiest) is to document this behaviour and say that specifying icon variants only works with Xcode 16 and up. Documentation gives us something to point to when people open issues about it, but I have low confidence in its ability to prevent issues from being opened.

The second option (and what I tried to do here) is to detect the Xcode version at prepare-time and only add the icon variants if it's 16 or higher. This works great on macOS. However, we support adding and preparing the iOS platform on other OSes where Xcode is not present, and that prepare-time check is failing. So the question here is what to do about those other platforms, do we make them pretend to be Xcode 15 (and skip the variants) or Xcode 16 (and potentially include broken variants)?

Would be good to get some feedback or other proposals for how best to handle this @jcesarmobile @breautek @erisu

erisu commented 3 months ago

I would go with the second option.

As for anyone who runs the cordova prepare command on a non-macOS (Darwin) platform, I would suggest it skips the variants setup and behave as if it was Xcode 15.

As of right now, building an app with Xcode 16 is not a hard requirement of the App Store and I believe it wont be until April 2025. Once it becomes a hard requirement, then we can remove the version check and default the variants setup for all systems.