diff --git a/lib/prepare.js b/lib/prepare.js
index 722fc6415..b549acdb0 100644
--- a/lib/prepare.js
+++ b/lib/prepare.js
@@ -363,58 +363,169 @@ function handleBuildSettings (platformConfig, locations, infoPlist) {
}
function mapIconResources (icons, iconsDir) {
- // See https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html
- // for launch images sizes reference.
+ // 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 = [
- { dest: 'icon-20.png', width: 20, height: 20 },
+ // iOS fallback icon sizes
{ dest: 'icon-20@2x.png', width: 40, height: 40 },
{ dest: 'icon-20@3x.png', width: 60, height: 60 },
- { dest: 'icon-40.png', width: 40, height: 40 },
- { dest: 'icon-40@2x.png', width: 80, height: 80 },
- { dest: 'icon-50.png', width: 50, height: 50 },
- { dest: 'icon-50@2x.png', width: 100, height: 100 },
+ { 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-72.png', width: 72, height: 72 },
- { dest: 'icon-72@2x.png', width: 144, height: 144 },
- { dest: 'icon-76.png', width: 76, height: 76 },
+ { 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 },
- { dest: 'icon-1024.png', width: 1024, height: 1024 },
- { dest: 'icon-29.png', width: 29, height: 29 },
- { dest: 'icon-29@2x.png', width: 58, height: 58 },
- { dest: 'icon-29@3x.png', width: 87, height: 87 },
- { dest: 'icon.png', width: 57, height: 57 },
- { dest: 'icon@2x.png', width: 114, height: 114 },
- { dest: 'icon-24@2x.png', width: 48, height: 48 },
- { dest: 'icon-27.5@2x.png', width: 55, height: 55 },
- { dest: 'icon-44@2x.png', width: 88, height: 88 },
- { dest: 'icon-86@2x.png', width: 172, height: 172 },
- { dest: 'icon-98@2x.png', width: 196, height: 196 }
+
+ // 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 = {};
+
+ 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 icon = icons.getBySize(item.width, item.height) || icons.getDefault();
+ 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) {
- const target = path.join(iconsDir, item.dest);
- pathMap[target] = icon.src;
+ if (icon.src) {
+ pathMap[dest] = icon.src;
+ }
+
+ // Only iOS has dark/tinted icon variants
+ if (!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;
}
-function getIconsDir (projectRoot, platformProjDir) {
- let iconsDir;
- const xcassetsExists = folderExists(path.join(projectRoot, platformProjDir, 'Assets.xcassets'));
+function generateAppIconContentsJson (resourceMap) {
+ const contentsJSON = {
+ images: [],
+ info: {
+ author: 'xcode',
+ version: 1
+ }
+ };
- if (xcassetsExists) {
- iconsDir = path.join(platformProjDir, 'Assets.xcassets', 'AppIcon.appiconset');
- } else {
- iconsDir = path.join(platformProjDir, 'Resources', 'icons');
- }
+ Object.keys(resourceMap).forEach(res => {
+ const [filename, platform, size, scale, variant] = path.basename(res).match(/([A-Za-z]+)(?:-([0-9.]+)(?:@([0-9.]x))?)?(?:-([a-z]+))?\.png/);
+
+ const entry = {
+ filename,
+ idiom: 'universal',
+ platform: (platform === 'icon') ? 'ios' : platform,
+ size: `${size ?? 1024}x${size ?? 1024}`
+ };
- return iconsDir;
+ if (scale) {
+ entry.scale = scale;
+ }
+
+ if (variant) {
+ entry.appearances = [
+ {
+ appearance: 'luminosity',
+ value: variant
+ }
+ ];
+ }
+
+ contentsJSON.images.push(entry);
+ });
+
+ return contentsJSON;
}
function updateIcons (cordovaProject, locations) {
@@ -426,18 +537,24 @@ function updateIcons (cordovaProject, locations) {
}
const platformProjDir = path.relative(cordovaProject.root, locations.xcodeCordovaProj);
- const iconsDir = getIconsDir(cordovaProject.root, platformProjDir);
+ const iconsDir = path.join(platformProjDir, 'Assets.xcassets', 'AppIcon.appiconset');
const resourceMap = mapIconResources(icons, iconsDir);
events.emit('verbose', `Updating icons at ${iconsDir}`);
FileUpdater.updatePaths(
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+
+ // Now we need to update the AppIcon.appiconset/Contents.json file
+ const contentsJSON = generateAppIconContentsJson(resourceMap);
+
+ events.emit('verbose', 'Updating App Icon image set contents.json');
+ fs.writeFileSync(path.join(cordovaProject.root, iconsDir, 'Contents.json'), JSON.stringify(contentsJSON, null, 2));
}
function cleanIcons (projectRoot, projectConfig, locations) {
const icons = projectConfig.getIcons('ios');
if (icons.length > 0) {
const platformProjDir = path.relative(projectRoot, locations.xcodeCordovaProj);
- const iconsDir = getIconsDir(projectRoot, platformProjDir);
+ const iconsDir = path.join(platformProjDir, 'Assets.xcassets', 'AppIcon.appiconset');
const resourceMap = mapIconResources(icons, iconsDir);
Object.keys(resourceMap).forEach(targetIconPath => {
resourceMap[targetIconPath] = null;
@@ -447,6 +564,16 @@ function cleanIcons (projectRoot, projectConfig, locations) {
// Source paths are removed from the map, so updatePaths() will delete the target files.
FileUpdater.updatePaths(
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+
+ const contentsJSON = generateAppIconContentsJson(resourceMap);
+
+ // delete filename from contents.json
+ contentsJSON.images.forEach(image => {
+ image.filename = undefined;
+ });
+
+ events.emit('verbose', 'Updating App Icon image set contents.json');
+ fs.writeFileSync(path.join(projectRoot, iconsDir, 'Contents.json'), JSON.stringify(contentsJSON, null, 2));
}
}
diff --git a/tests/spec/unit/fixtures/icon-support/configs/multi.xml b/tests/spec/unit/fixtures/icon-support/configs/multi.xml
new file mode 100644
index 000000000..504ca2976
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/configs/multi.xml
@@ -0,0 +1,42 @@
+
+
+ Hello Cordova
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/spec/unit/fixtures/icon-support/configs/none.xml b/tests/spec/unit/fixtures/icon-support/configs/none.xml
new file mode 100644
index 000000000..f1b8751cb
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/configs/none.xml
@@ -0,0 +1,24 @@
+
+
+ Hello Cordova
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/spec/unit/fixtures/icon-support/configs/single-only.xml b/tests/spec/unit/fixtures/icon-support/configs/single-only.xml
new file mode 100644
index 000000000..975364f71
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/configs/single-only.xml
@@ -0,0 +1,27 @@
+
+
+ Hello Cordova
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/spec/unit/fixtures/icon-support/configs/single-variants.xml b/tests/spec/unit/fixtures/icon-support/configs/single-variants.xml
new file mode 100644
index 000000000..52cd0d5d6
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/configs/single-variants.xml
@@ -0,0 +1,27 @@
+
+
+ Hello Cordova
+
+ A sample Apache Cordova application that responds to the deviceready event.
+
+
+ Apache Cordova Team
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/spec/unit/fixtures/icon-support/contents-json/multi.js b/tests/spec/unit/fixtures/icon-support/contents-json/multi.js
new file mode 100644
index 000000000..2b5a317a2
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/contents-json/multi.js
@@ -0,0 +1,145 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+module.exports = {
+ "images" : [
+ {
+ "filename": "icon-20@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename": "icon-20@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "20x20"
+ },
+ {
+ "filename": "icon-29@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename": "icon-29@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "filename": "icon-38@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "38x38"
+ },
+ {
+ "filename": "icon-38@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "38x38"
+ },
+ {
+ "filename": "icon-40@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename": "icon-40@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "filename": "icon-60@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "filename": "icon-60@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "filename": "icon-64@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "64x64"
+ },
+ {
+ "filename": "icon-64@3x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "3x",
+ "size" : "64x64"
+ },
+ {
+ "filename": "icon-68@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "68x68"
+ },
+ {
+ "filename": "icon-76@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "76x76"
+ },
+ {
+ "filename": "icon-83.5@2x.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "scale" : "2x",
+ "size" : "83.5x83.5"
+ },
+ {
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform": "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "filename" : "watchos.png",
+ "idiom" : "universal",
+ "platform": "watchos",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+};
+
diff --git a/tests/spec/unit/fixtures/icon-support/contents-json/none.js b/tests/spec/unit/fixtures/icon-support/contents-json/none.js
new file mode 100644
index 000000000..e08f8af56
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/contents-json/none.js
@@ -0,0 +1,39 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+module.exports = {
+ "images" : [
+ {
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform": "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform": "watchos",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+};
diff --git a/tests/spec/unit/fixtures/icon-support/contents-json/single-only.js b/tests/spec/unit/fixtures/icon-support/contents-json/single-only.js
new file mode 100644
index 000000000..600c3f122
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/contents-json/single-only.js
@@ -0,0 +1,39 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+module.exports = {
+ "images" : [
+ {
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform": "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "filename" : "watchos.png",
+ "idiom" : "universal",
+ "platform": "watchos",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+};
diff --git a/tests/spec/unit/fixtures/icon-support/contents-json/single-variants.js b/tests/spec/unit/fixtures/icon-support/contents-json/single-variants.js
new file mode 100644
index 000000000..1b3dc3396
--- /dev/null
+++ b/tests/spec/unit/fixtures/icon-support/contents-json/single-variants.js
@@ -0,0 +1,63 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+module.exports = {
+ "images" : [
+ {
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "icon-dark.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "tinted"
+ }
+ ],
+ "filename" : "icon-tinted.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ },
+ {
+ "filename" : "watchos.png",
+ "idiom" : "universal",
+ "platform" : "watchos",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+};
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-1024x1024@1x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-1024x1024@1x.png
new file mode 100644
index 000000000..8cfcb9741
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-1024x1024@1x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@2x.png
new file mode 100644
index 000000000..dac813888
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@3x.png
new file mode 100644
index 000000000..79e2e9273
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-20x20@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@2x.png
new file mode 100644
index 000000000..662beedcd
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@3x.png
new file mode 100644
index 000000000..9f8bfb093
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-29x29@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@2x.png
new file mode 100644
index 000000000..85a74483f
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@3x.png
new file mode 100644
index 000000000..0e0c498d8
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-38x38@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@2x.png
new file mode 100644
index 000000000..601336d4c
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@3x.png
new file mode 100644
index 000000000..c2e5c98d7
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-40x40@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@2x.png
new file mode 100644
index 000000000..aef9bf513
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@3x.png
new file mode 100644
index 000000000..d9f5559b5
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-60x60@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@2x.png
new file mode 100644
index 000000000..a436d0351
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@3x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@3x.png
new file mode 100644
index 000000000..56482a3be
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-64x64@3x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-68x68@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-68x68@2x.png
new file mode 100644
index 000000000..f756ba8c9
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-68x68@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-76x76@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-76x76@2x.png
new file mode 100644
index 000000000..303808070
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-76x76@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-83.5x83.5@2x.png b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-83.5x83.5@2x.png
new file mode 100644
index 000000000..efed7886a
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/AppIcon-83.5x83.5@2x.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/appicon-dark.png b/tests/spec/unit/fixtures/icon-support/res/ios/appicon-dark.png
new file mode 100644
index 000000000..884c42316
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/appicon-dark.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/appicon-tint.png b/tests/spec/unit/fixtures/icon-support/res/ios/appicon-tint.png
new file mode 100644
index 000000000..b37e81158
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/appicon-tint.png differ
diff --git a/tests/spec/unit/fixtures/icon-support/res/ios/appicon.png b/tests/spec/unit/fixtures/icon-support/res/ios/appicon.png
new file mode 100644
index 000000000..07afba0e4
Binary files /dev/null and b/tests/spec/unit/fixtures/icon-support/res/ios/appicon.png differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
index d19e65fdb..2c8c083ab 100644
--- a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
+++ b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,182 +1,20 @@
{
"images" : [
{
- "idiom" : "iphone",
- "size" : "29x29",
- "filename" : "icon-small.png",
- "scale" : "1x"
- },
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "filename" : "icon-small@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "filename" : "icon-small@3x.png",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "filename" : "icon-40@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "filename" : "icon-60@2x.png",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "57x57",
"filename" : "icon.png",
- "scale" : "1x"
- },
- {
- "idiom" : "iphone",
- "size" : "57x57",
- "filename" : "icon@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "60x60",
- "filename" : "icon-60@2x.png",
- "scale" : "2x"
+ "idiom" : "universal",
+ "platform": "ios",
+ "size" : "1024x1024"
},
{
- "idiom" : "iphone",
- "size" : "60x60",
- "filename" : "icon-60@3x.png",
- "scale" : "3x"
- },
- {
- "idiom" : "ipad",
- "size" : "29x29",
- "filename" : "icon-small.png",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "29x29",
- "filename" : "icon-small@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "40x40",
- "filename" : "icon-40.png",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "40x40",
- "filename" : "icon-40@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "50x50",
- "filename" : "icon-50.png",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "50x50",
- "filename" : "icon-50@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "72x72",
- "filename" : "icon-72.png",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "72x72",
- "filename" : "icon-72@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "76x76",
- "filename" : "icon-76.png",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "76x76",
- "filename" : "icon-76@2x.png",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "83.5x83.5",
- "filename" : "icon-83.5@2x.png",
- "scale" : "2x"
- },
- {
- "size" : "24x24",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "notificationCenter",
- "subtype" : "38mm"
- },
- {
- "size" : "27.5x27.5",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "notificationCenter",
- "subtype" : "42mm"
- },
- {
- "size" : "29x29",
- "idiom" : "watch",
- "role" : "companionSettings",
- "scale" : "2x"
- },
- {
- "size" : "29x29",
- "idiom" : "watch",
- "role" : "companionSettings",
- "scale" : "3x"
- },
- {
- "size" : "40x40",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "appLauncher",
- "subtype" : "38mm"
- },
- {
- "size" : "44x44",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "longLook",
- "subtype" : "42mm"
- },
- {
- "size" : "86x86",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "quickLook",
- "subtype" : "38mm"
- },
- {
- "size" : "98x98",
- "idiom" : "watch",
- "scale" : "2x",
- "role" : "quickLook",
- "subtype" : "42mm"
+ "filename" : "icon.png",
+ "idiom" : "universal",
+ "platform": "watchos",
+ "size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
-}
\ No newline at end of file
+}
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40.png
deleted file mode 100644
index e865adbc5..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png
deleted file mode 100644
index 6d07dce53..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50.png
deleted file mode 100644
index 98a9d96d5..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png
deleted file mode 100644
index bac693f7f..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-50@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png
deleted file mode 100644
index 955af362d..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png
deleted file mode 100644
index e1268916b..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72.png
deleted file mode 100644
index 8c6e5df34..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png
deleted file mode 100644
index dd819da61..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-72@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76.png
deleted file mode 100644
index 63afe7f17..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png
deleted file mode 100644
index 4cff29a2b..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png
deleted file mode 100644
index 3c1a01154..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small.png
deleted file mode 100644
index 0ea1c42f9..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png
deleted file mode 100644
index 2c72038ef..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@2x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png
deleted file mode 100644
index 5c37dfc2a..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon-small@3x.png and /dev/null differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon.png
index b2571a719..b9250b124 100644
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon.png and b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon.png differ
diff --git a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon@2x.png b/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon@2x.png
deleted file mode 100644
index d75098f5a..000000000
Binary files a/tests/spec/unit/fixtures/ios-config-xml/SampleApp/Assets.xcassets/AppIcon.appiconset/icon@2x.png and /dev/null differ
diff --git a/tests/spec/unit/prepare.spec.js b/tests/spec/unit/prepare.spec.js
index 769a3afac..836928d8b 100644
--- a/tests/spec/unit/prepare.spec.js
+++ b/tests/spec/unit/prepare.spec.js
@@ -400,6 +400,326 @@ describe('prepare', () => {
});
});
+ describe('App Icon handling', () => {
+ const mapIconResources = prepare.__get__('mapIconResources');
+
+ describe('#mapIconResources', () => {
+ it('should handle a default icon', () => {
+ const icons = [
+ { src: 'dummy.png' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon.png': 'dummy.png',
+ 'watchos.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle a default icon for a watchos target', () => {
+ const icons = [
+ { src: 'dummy.png' },
+ { src: 'dummy-watch.png', target: 'watchos' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon.png': 'dummy.png',
+ 'watchos.png': 'dummy-watch.png'
+ }));
+ });
+
+ it('should handle default icon variants', () => {
+ const icons = [
+ { src: 'dummy.png', monochrome: 'dummy-tint.png', foreground: 'dummy-dark.png' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon.png': 'dummy.png',
+ 'icon-dark.png': 'dummy-dark.png',
+ 'icon-tinted.png': 'dummy-tint.png',
+ 'watchos.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle a single sized icon', () => {
+ const icons = [
+ { src: 'dummy.png', height: 1024, width: 1024 }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon.png': 'dummy.png',
+ 'watchos.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle a single sized icon for watchos target', () => {
+ const icons = [
+ { src: 'dummy.png', height: 1024, width: 1024, target: 'watchos' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'watchos.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle a sized icon', () => {
+ const icons = [
+ { src: 'dummy.png', height: 120, width: 120 }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon-40@3x.png': 'dummy.png',
+ 'icon-60@2x.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle a sized spotlight icon', () => {
+ const icons = [
+ { src: 'dummy.png', height: 120, width: 120 },
+ { src: 'dummy-spot.png', height: 120, width: 120, target: 'spotlight' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon-40@3x.png': 'dummy-spot.png',
+ 'icon-60@2x.png': 'dummy.png'
+ }));
+ });
+
+ it('should handle sized icon variants', () => {
+ const icons = [
+ { src: 'dummy.png', height: 76, width: 76, monochrome: 'dummy-tint.png', foreground: 'dummy-dark.png' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'icon-38@2x.png': 'dummy.png',
+ 'icon-38@2x-dark.png': 'dummy-dark.png',
+ 'icon-38@2x-tinted.png': 'dummy-tint.png'
+ }));
+ });
+
+ it('should ignore sized watchos icons without a target', () => {
+ const icons = [
+ { src: 'dummy.png', height: 216, width: 216 }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual({});
+ });
+
+ it('should handle a sized macOS icon', () => {
+ const icons = [
+ { src: 'dummy.png', height: 256, width: 256, target: 'mac' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual(jasmine.objectContaining({
+ 'mac-128@2x.png': 'dummy.png',
+ 'mac-256.png': 'dummy.png'
+ }));
+ });
+
+ it('should ignore tinted icons for non-iOS targets', () => {
+ const icons = [
+ { monochrome: 'dummy-tint.png', height: 256, width: 256, target: 'mac' },
+ { foreground: 'dummy-dark.png', height: 216, width: 216, target: 'watchos' }
+ ];
+
+ const resMap = mapIconResources(icons, '');
+
+ expect(resMap).toEqual({});
+ });
+ });
+
+ describe('#updateIcons', () => {
+ const updateIcons = prepare.__get__('updateIcons');
+ const logFileOp = prepare.__get__('logFileOp');
+ let iconsDir = '';
+
+ beforeEach(() => {
+ const platformProjDir = path.relative(iosProject, p.locations.xcodeCordovaProj);
+ iconsDir = path.join(platformProjDir, 'Assets.xcassets', 'AppIcon.appiconset');
+ });
+
+ function updateIconsWithConfig (configFile) {
+ // create a suitable mock project for our method
+ const project = {
+ root: iosProject,
+ locations: p.locations,
+ projectConfig: new ConfigParser(path.join(FIXTURES, 'icon-support', 'configs', configFile))
+ };
+
+ // copy the icon fixtures to the iOS project
+ fs.cpSync(path.join(FIXTURES, 'icon-support', 'res'), path.join(iosProject, 'res'), { recursive: true });
+
+ // copy icons and update Contents.json
+ updateIcons(project, p.locations);
+ }
+
+ it('should not update paths if no icons are specified', () => {
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+
+ updateIconsWithConfig('none.xml');
+
+ expect(updatePaths).not.toHaveBeenCalled();
+
+ // verify that that Contents.json is as we expect
+ const result = JSON.parse(fs.readFileSync(path.join(iosProject, iconsDir, 'Contents.json')));
+ expect(result).toEqual(require('./fixtures/icon-support/contents-json/none'));
+ });
+
+ it('should update paths if a single icon is specified', () => {
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+
+ updateIconsWithConfig('single-only.xml');
+
+ expect(updatePaths).toHaveBeenCalledWith({
+ [path.join(iconsDir, 'icon.png')]: 'res/ios/appicon.png',
+ [path.join(iconsDir, 'watchos.png')]: 'res/ios/appicon.png'
+ }, { rootDir: iosProject }, logFileOp);
+
+ // verify that that Contents.json is as we expect
+ const result = JSON.parse(fs.readFileSync(path.join(iosProject, iconsDir, 'Contents.json')));
+ expect(result).toEqual(require('./fixtures/icon-support/contents-json/single-only'));
+ });
+
+ it('should update paths if a single icon with variants is specified', () => {
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+
+ updateIconsWithConfig('single-variants.xml');
+
+ expect(updatePaths).toHaveBeenCalledWith({
+ [path.join(iconsDir, 'icon.png')]: 'res/ios/appicon.png',
+ [path.join(iconsDir, 'icon-dark.png')]: 'res/ios/appicon-dark.png',
+ [path.join(iconsDir, 'icon-tinted.png')]: 'res/ios/appicon-tint.png',
+ [path.join(iconsDir, 'watchos.png')]: 'res/ios/appicon.png'
+ }, { rootDir: iosProject }, logFileOp);
+
+ // verify that that Contents.json is as we expect
+ const result = JSON.parse(fs.readFileSync(path.join(iosProject, iconsDir, 'Contents.json')));
+ expect(result).toEqual(require('./fixtures/icon-support/contents-json/single-variants'));
+ });
+
+ it('should update paths if multiple icon sizes are specified', () => {
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+
+ updateIconsWithConfig('multi.xml');
+
+ expect(updatePaths).toHaveBeenCalledWith({
+ [path.join(iconsDir, 'icon.png')]: 'res/ios/AppIcon-1024x1024@1x.png',
+ [path.join(iconsDir, 'watchos.png')]: 'res/ios/AppIcon-1024x1024@1x.png',
+ [path.join(iconsDir, 'icon-20@2x.png')]: 'res/ios/AppIcon-20x20@2x.png',
+ [path.join(iconsDir, 'icon-20@3x.png')]: 'res/ios/AppIcon-20x20@3x.png',
+ [path.join(iconsDir, 'icon-29@2x.png')]: 'res/ios/AppIcon-29x29@2x.png',
+ [path.join(iconsDir, 'icon-29@3x.png')]: 'res/ios/AppIcon-29x29@3x.png',
+ [path.join(iconsDir, 'icon-38@2x.png')]: 'res/ios/AppIcon-38x38@2x.png',
+ [path.join(iconsDir, 'icon-38@3x.png')]: 'res/ios/AppIcon-38x38@3x.png',
+ [path.join(iconsDir, 'icon-40@2x.png')]: 'res/ios/AppIcon-40x40@2x.png',
+ [path.join(iconsDir, 'icon-40@3x.png')]: 'res/ios/AppIcon-40x40@3x.png',
+ [path.join(iconsDir, 'icon-60@2x.png')]: 'res/ios/AppIcon-60x60@2x.png',
+ [path.join(iconsDir, 'icon-60@3x.png')]: 'res/ios/AppIcon-60x60@3x.png',
+ [path.join(iconsDir, 'icon-64@2x.png')]: 'res/ios/AppIcon-64x64@2x.png',
+ [path.join(iconsDir, 'icon-64@3x.png')]: 'res/ios/AppIcon-64x64@3x.png',
+ [path.join(iconsDir, 'icon-68@2x.png')]: 'res/ios/AppIcon-68x68@2x.png',
+ [path.join(iconsDir, 'icon-76@2x.png')]: 'res/ios/AppIcon-76x76@2x.png',
+ [path.join(iconsDir, 'icon-83.5@2x.png')]: 'res/ios/AppIcon-83.5x83.5@2x.png'
+ }, { rootDir: iosProject }, logFileOp);
+
+ // verify that that Contents.json is as we expect
+ const result = JSON.parse(fs.readFileSync(path.join(iosProject, iconsDir, 'Contents.json')));
+ expect(result).toEqual(require('./fixtures/icon-support/contents-json/multi'));
+ });
+ });
+
+ describe('#cleanIcons', () => {
+ const updateIcons = prepare.__get__('updateIcons');
+ const cleanIcons = prepare.__get__('cleanIcons');
+ const logFileOp = prepare.__get__('logFileOp');
+ let iconsDir = '';
+
+ beforeEach(() => {
+ const platformProjDir = path.relative(iosProject, p.locations.xcodeCordovaProj);
+ iconsDir = path.join(platformProjDir, 'Assets.xcassets', 'AppIcon.appiconset');
+ });
+
+ it('should remove icon images', () => {
+ // create a suitable mock project for our method
+ const project = {
+ root: iosProject,
+ locations: p.locations,
+ projectConfig: new ConfigParser(path.join(FIXTURES, 'icon-support', 'configs', 'multi.xml'))
+ };
+
+ // copy the icon fixtures to the iOS project
+ fs.cpSync(path.join(FIXTURES, 'icon-support', 'res'), path.join(iosProject, 'res'), { recursive: true });
+
+ // copy icons and update Contents.json
+ updateIcons(project, p.locations);
+
+ // now, clean the images
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+ cleanIcons(iosProject, project.projectConfig, p.locations);
+
+ expect(updatePaths).toHaveBeenCalledWith({
+ [path.join(iconsDir, 'icon.png')]: null,
+ [path.join(iconsDir, 'watchos.png')]: null,
+ [path.join(iconsDir, 'icon-20@2x.png')]: null,
+ [path.join(iconsDir, 'icon-20@3x.png')]: null,
+ [path.join(iconsDir, 'icon-29@2x.png')]: null,
+ [path.join(iconsDir, 'icon-29@3x.png')]: null,
+ [path.join(iconsDir, 'icon-38@2x.png')]: null,
+ [path.join(iconsDir, 'icon-38@3x.png')]: null,
+ [path.join(iconsDir, 'icon-40@2x.png')]: null,
+ [path.join(iconsDir, 'icon-40@3x.png')]: null,
+ [path.join(iconsDir, 'icon-60@2x.png')]: null,
+ [path.join(iconsDir, 'icon-60@3x.png')]: null,
+ [path.join(iconsDir, 'icon-64@2x.png')]: null,
+ [path.join(iconsDir, 'icon-64@3x.png')]: null,
+ [path.join(iconsDir, 'icon-68@2x.png')]: null,
+ [path.join(iconsDir, 'icon-76@2x.png')]: null,
+ [path.join(iconsDir, 'icon-83.5@2x.png')]: null
+ }, { rootDir: iosProject, all: true }, logFileOp);
+ });
+
+ it('should have no effect if no icons are specified', () => {
+ // create a suitable mock project for our method
+ const project = {
+ root: iosProject,
+ locations: p.locations,
+ projectConfig: new ConfigParser(path.join(FIXTURES, 'icon-support', 'configs', 'none.xml'))
+ };
+
+ // copy the icon fixtures to the iOS project
+ fs.cpSync(path.join(FIXTURES, 'icon-support', 'res'), path.join(iosProject, 'res'), { recursive: true });
+
+ // copy icons and update Contents.json
+ updateIcons(project, p.locations);
+
+ // now, clean the images
+ const updatePaths = spyOn(FileUpdater, 'updatePaths');
+ cleanIcons(iosProject, project.projectConfig, p.locations);
+
+ expect(updatePaths).not.toHaveBeenCalled();
+ });
+ });
+ });
+
describe('colorPreferenceToComponents', () => {
const colorPreferenceToComponents = prepare.__get__('colorPreferenceToComponents');