function mapIconResources()

in lib/prepare.js [359:488]


function mapIconResources (icons, iconsDir, xcodeversion) {
    // Ref: https://developer.apple.com/design/human-interface-guidelines/app-icons
    // These are ordered according to how Xcode puts them in the Contents.json file
    const platformIcons = [
        // iOS fallback icon sizes
        { dest: 'icon-20@2x.png', width: 40, height: 40 },
        { dest: 'icon-20@3x.png', width: 60, height: 60 },
        { dest: 'icon-29@2x.png', width: 58, height: 58 },
        { dest: 'icon-29@3x.png', width: 87, height: 87 },
        { dest: 'icon-38@2x.png', width: 76, height: 76 },
        { dest: 'icon-38@3x.png', width: 114, height: 114 },
        { dest: 'icon-40@2x.png', width: 80, height: 80, target: 'spotlight' },
        { dest: 'icon-40@3x.png', width: 120, height: 120, target: 'spotlight' },
        { dest: 'icon-60@2x.png', width: 120, height: 120 },
        { dest: 'icon-60@3x.png', width: 180, height: 180 },
        { dest: 'icon-64@2x.png', width: 128, height: 128 },
        { dest: 'icon-64@3x.png', width: 192, height: 192 },
        { dest: 'icon-68@2x.png', width: 136, height: 136 },
        { dest: 'icon-76@2x.png', width: 152, height: 152 },
        { dest: 'icon-83.5@2x.png', width: 167, height: 167 },

        // Default iOS icon
        { dest: 'icon.png', width: 1024, height: 1024, useDefault: true },

        // macOS icon sizes
        { dest: 'mac-16.png', width: 16, height: 16, target: 'mac' },
        { dest: 'mac-16@2x.png', width: 32, height: 32, target: 'mac' },
        { dest: 'mac-32.png', width: 32, height: 32, target: 'mac' },
        { dest: 'mac-32@2x.png', width: 64, height: 64, target: 'mac' },
        { dest: 'mac-128.png', width: 128, height: 128, target: 'mac' },
        { dest: 'mac-128@2x.png', width: 256, height: 256, target: 'mac' },
        { dest: 'mac-256.png', width: 256, height: 256, target: 'mac' },
        { dest: 'mac-256@2x.png', width: 512, height: 512, target: 'mac' },
        { dest: 'mac-512.png', width: 512, height: 512, target: 'mac' },
        { dest: 'mac-512@2x.png', width: 1024, height: 1024, target: 'mac' },

        // WatchOS fallback icon sizes
        { dest: 'watchos-22@2x.png', width: 44, height: 44, target: 'watchos' },
        { dest: 'watchos-24@2x.png', width: 48, height: 48, target: 'watchos' },
        { dest: 'watchos-27.5@2x.png', width: 55, height: 55, target: 'watchos' },
        { dest: 'watchos-29@2x.png', width: 58, height: 58, target: 'watchos' },
        { dest: 'watchos-30@2x.png', width: 60, height: 60, target: 'watchos' },
        { dest: 'watchos-32@2x.png', width: 64, height: 64, target: 'watchos' },
        { dest: 'watchos-33@2x.png', width: 66, height: 66, target: 'watchos' },
        { dest: 'watchos-40@2x.png', width: 80, height: 80, target: 'watchos' },
        { dest: 'watchos-43.5@2x.png', width: 87, height: 87, target: 'watchos' },
        { dest: 'watchos-44@2x.png', width: 88, height: 88, target: 'watchos' },
        { dest: 'watchos-46@2x.png', width: 92, height: 92, target: 'watchos' },
        { dest: 'watchos-50@2x.png', width: 100, height: 100, target: 'watchos' },
        { dest: 'watchos-51@2x.png', width: 102, height: 102, target: 'watchos' },
        { dest: 'watchos-54@2x.png', width: 108, height: 108, target: 'watchos' },
        { dest: 'watchos-86@2x.png', width: 172, height: 172, target: 'watchos' },
        { dest: 'watchos-98@2x.png', width: 196, height: 196, target: 'watchos' },
        { dest: 'watchos-108@2x.png', width: 216, height: 216, target: 'watchos' },
        { dest: 'watchos-117@2x.png', width: 234, height: 234, target: 'watchos' },
        { dest: 'watchos-129@2x.png', width: 258, height: 258, target: 'watchos' },

        // Allow customizing the watchOS icon with target="watchos"
        // This falls back to using the iOS app icon by default
        { dest: 'watchos.png', width: 1024, height: 1024, target: 'watchos', useDefault: true }
    ];

    const pathMap = {};

    // We can only support dark mode and tinted icons with Xcode 16
    const isAtLeastXcode16 = versions.compareVersions(xcodeversion, '16.0.0') >= 0;

    function getDefaultIconForTarget (target) {
        const def = icons.filter(res => !res.width && !res.height && !res.target).pop();

        if (target) {
            return icons
                .filter(res => res.target === target)
                .filter(res => !res.width && !res.height)
                .pop() || def;
        }

        return def;
    }

    function getIconBySizeAndTarget (width, height, target) {
        return icons
            .filter(res => res.target === target)
            .find(res =>
                (res.width || res.height) &&
                (!res.width || (width === res.width)) &&
                (!res.height || (height === res.height))
            ) || null;
    }

    platformIcons.forEach(item => {
        const dest = path.join(iconsDir, item.dest);
        let icon = getIconBySizeAndTarget(item.width, item.height, item.target);

        if (!icon && item.target === 'spotlight') {
            // Fall back to a non-targeted icon
            icon = getIconBySizeAndTarget(item.width, item.height);
        }

        if (!icon && item.useDefault) {
            if (item.target) {
                icon = getIconBySizeAndTarget(item.width, item.height);
            }

            const defaultIcon = getDefaultIconForTarget(item.target);
            if (!icon && defaultIcon) {
                icon = defaultIcon;
            }
        }

        if (icon) {
            if (icon.src) {
                pathMap[dest] = icon.src;
            }

            // Only iOS has dark/tinted icon variants
            if (isAtLeastXcode16 && (!item.target || item.target === 'spotlight')) {
                if (icon.foreground) {
                    pathMap[dest.replace('.png', '-dark.png')] = icon.foreground;
                }

                if (icon.monochrome) {
                    pathMap[dest.replace('.png', '-tinted.png')] = icon.monochrome;
                }
            }
        }
    });

    return pathMap;
}