diff --git a/android/app/src/main/res-launcher/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res-launcher/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000..1ef13112f
--- /dev/null
+++ b/android/app/src/main/res-launcher/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res-launcher/drawable/ic_launcher_background.xml b/android/app/src/main/res-launcher/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000..ca3826a46
--- /dev/null
+++ b/android/app/src/main/res-launcher/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher.xml
similarity index 94%
rename from android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher.xml
index 6b78462d6..d378acd7a 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
-
+
+
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 94%
rename from android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher_round.xml
index 6b78462d6..d378acd7a 100644
--- a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/android/app/src/main/res-launcher/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
-
+
+
diff --git a/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..06c2ae637
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000..0cf22d879
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..3caf60918
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000..6295d899e
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..4b37dff4f
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..07249dac2
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..c1b77f576
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..926924d8a
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..9261b54e8
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000..1e239a77f
Binary files /dev/null and b/android/app/src/main/res-launcher/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 1f6bb2906..000000000
--- a/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/app/src/main/res/drawable/ic_launcher_background.xml b/android/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 0d025f9bf..000000000
--- a/android/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,170 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 898f3ed59..000000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
deleted file mode 100644
index dffca3601..000000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 64ba76f75..000000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
deleted file mode 100644
index dae5e0823..000000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index e5ed46597..000000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
deleted file mode 100644
index 14ed0af35..000000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index b0907cac3..000000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
deleted file mode 100644
index d8ae03154..000000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 2c18de9e6..000000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
deleted file mode 100644
index beed3cdd2..000000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ
diff --git a/ios/ReactTestApp.xcodeproj/project.pbxproj b/ios/ReactTestApp.xcodeproj/project.pbxproj
index 7a03b0a44..960ad86ca 100644
--- a/ios/ReactTestApp.xcodeproj/project.pbxproj
+++ b/ios/ReactTestApp.xcodeproj/project.pbxproj
@@ -67,7 +67,7 @@
19ECD0D5232ED425003D8557 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
19ECD0D7232ED425003D8557 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
19ECD0D9232ED425003D8557 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
- 19ECD0DB232ED427003D8557 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 19ECD0DB232ED427003D8557 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; };
19ECD0E1232ED427003D8557 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
19ECD0E3232ED427003D8557 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
19ECD0E8232ED427003D8557 /* ReactTestAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactTestAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
diff --git a/ios/test_app.rb b/ios/test_app.rb
index 8805103ae..076b9aeb3 100644
--- a/ios/test_app.rb
+++ b/ios/test_app.rb
@@ -74,6 +74,48 @@ def react_native_path(project_root, target_platform)
Pathname.new(resolve_module(react_native))
end
+def generate_assets_catalog!(project_root, target_platform, destination)
+ xcassets_src = project_path('ReactTestApp/Assets.xcassets', target_platform)
+ xcassets_dst = File.join(destination, File.basename(xcassets_src))
+ FileUtils.rm_rf(xcassets_dst)
+ FileUtils.cp_r(xcassets_src, destination)
+
+ icons = platform_config('icons', project_root, target_platform)
+ return if icons.nil? || icons['primaryIcon'].nil?
+
+ template = JSON.parse(File.read(File.join(xcassets_src, 'AppIcon.appiconset', 'Contents.json')))
+ app_manifest_dir = File.dirname(find_file('app.json', project_root))
+
+ app_icons = (icons['alternateIcons'] || {}).merge({ 'AppIcon' => icons['primaryIcon'] })
+ app_icons.each do |icon_set_name, app_icon|
+ app_icon_set = File.join(xcassets_dst, "#{icon_set_name}.appiconset")
+ FileUtils.mkdir_p(app_icon_set)
+
+ icon = File.join(app_manifest_dir, app_icon['filename'])
+ extname = File.extname(icon)
+ basename = File.basename(icon, extname)
+
+ images = []
+
+ template['images'].each do |image|
+ scale, size = image.values_at('scale', 'size')
+ width, height = size.split('x')
+ filename = "#{basename}-#{height}@#{scale}#{extname}"
+ images << { 'filename' => filename }.merge(image)
+ fork do
+ output = File.join(app_icon_set, filename)
+ scale = scale.split('x')[0].to_f
+ height = height.to_f * scale
+ width = width.to_f * scale
+ `sips --resampleHeightWidth #{height} #{width} --out "#{output}" "#{icon}"`
+ end
+ end
+
+ File.write(File.join(app_icon_set, 'Contents.json'),
+ JSON.pretty_generate({ 'images' => images, 'info' => template['info'] }))
+ end
+end
+
def react_native_pods(version)
v = version.release
if v == Gem::Version.new('0.0.0') || v >= Gem::Version.new('0.70')
@@ -184,6 +226,8 @@ def make_project!(xcodeproj, project_root, target_platform, options)
FileUtils.ln_sf(source, shared_path) unless File.exist?(shared_path)
end
+ generate_assets_catalog!(project_root, target_platform, destination)
+
# Copy localization files and replace instances of `ReactTestApp` with app display name
product_name = display_name || name
product_name = if product_name.is_a? String
diff --git a/macos/ReactTestApp.xcodeproj/project.pbxproj b/macos/ReactTestApp.xcodeproj/project.pbxproj
index 8a436b40f..f6f62e06a 100644
--- a/macos/ReactTestApp.xcodeproj/project.pbxproj
+++ b/macos/ReactTestApp.xcodeproj/project.pbxproj
@@ -43,7 +43,7 @@
193EF05F247A736200BE8C79 /* ReactTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ReactTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
193EF062247A736200BE8C79 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
193EF064247A736200BE8C79 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
- 193EF066247A736300BE8C79 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 193EF066247A736300BE8C79 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = SOURCE_ROOT; };
193EF069247A736300BE8C79 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
193EF06B247A736300BE8C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
193EF06C247A736300BE8C79 /* ReactTestApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ReactTestApp.entitlements; sourceTree = ""; };
diff --git a/macos/ReactTestApp/Info.plist b/macos/ReactTestApp/Info.plist
index 14025d2e0..812287729 100644
--- a/macos/ReactTestApp/Info.plist
+++ b/macos/ReactTestApp/Info.plist
@@ -8,8 +8,6 @@
$(PRODUCT_DISPLAY_NAME)
CFBundleExecutable
$(EXECUTABLE_NAME)
- CFBundleIconFile
-
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
diff --git a/schema.json b/schema.json
index d4ef3e552..9f1090a4f 100644
--- a/schema.json
+++ b/schema.json
@@ -1,5 +1,22 @@
{
"$defs": {
+ "appIconSet": {
+ "type": "object",
+ "properties": {
+ "filename": {
+ "description": "Path to the app icon file.",
+ "type": "string"
+ },
+ "prerendered": {
+ "description": "Whether the icon already incorporates a shine effect.",
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "filename",
+ "prerendered"
+ ]
+ },
"apple": {
"type": "object",
"properties": {
@@ -12,6 +29,38 @@
"markdownDescription": "Similar to [`version`](#version), but is not shown to users. This is a required\nkey for App Store.\n\nThe equivalent key in `Info.plist` is\n[`CFBundleVersion`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleversion).\n\nIntroduced in\n[1.4.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.4.0).",
"type": "string"
},
+ "icons": {
+ "description": "Information about all of the icons used by the app.",
+ "markdownDescription": "Information about all of the icons used by the app.\n\nIcons for all sizes and scales are generated for you so long as you provide PNGs\nmeasuring 1024x1024 pixels here.\n\nYou can read more about app icons in the\n[Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons).\n\nThe equivalent key in `Info.plist` is\n[`CFBundleIcons`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons).\n\nIntroduced in\n[1.6.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.6.0).",
+ "type": "object",
+ "properties": {
+ "primaryIcon": {
+ "description": "The primary icon for the Home screen and Settings app, among others.",
+ "markdownDescription": "The primary icon for the Home screen and Settings app, among others.\n\nThe equivalent key in `Info.plist` is\n[`CFBundlePrimaryIcon`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons/cfbundleprimaryicon).",
+ "allOf": [
+ {
+ "$ref": "#/$defs/appIconSet"
+ }
+ ]
+ },
+ "alternateIcons": {
+ "description": "The primary icon for the Home screen and Settings app, among others.",
+ "markdownDescription": "The primary icon for the Home screen and Settings app, among others.\n\nThe equivalent key in `Info.plist` is\n[`CFBundleAlternateIcons`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons/cfbundlealternateicons).",
+ "type": "object",
+ "additionalProperties": {
+ "allOf": [
+ {
+ "$ref": "#/$defs/appIconSet"
+ }
+ ],
+ "type": "object"
+ }
+ }
+ },
+ "required": [
+ "primaryIcon"
+ ]
+ },
"codeSignEntitlements": {
"description": "Specifies the path to a custom\n[Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements)\nfile. The path should be relative to `app.json`.",
"markdownDescription": "Specifies the path to a custom\n[Entitlements](https://developer.apple.com/documentation/bundleresources/entitlements)\nfile. The path should be relative to `app.json`.\n\nThis is the same as setting `CODE_SIGN_ENTITLEMENTS` in Xcode.\n\nIntroduced in\n[0.9.7](https://github.com/microsoft/react-native-test-app/releases/tag/0.9.7).",
@@ -27,8 +76,7 @@
"markdownDescription": "Sets the\ndevelopment\nteam that the app should be assigned to.\n\nThis is the same as setting `DEVELOPMENT_TEAM` in Xcode.\n\nIntroduced in\n[0.9.7](https://github.com/microsoft/react-native-test-app/releases/tag/0.9.7).",
"type": "string"
}
- },
- "exclude-from-codegen": true
+ }
},
"component": {
"type": "object",
@@ -122,8 +170,7 @@
},
"required": [
"storeFile"
- ],
- "exclude-from-codegen": true
+ ]
}
},
"allOf": [
@@ -192,6 +239,11 @@
"markdownDescription": "A positive integer used as an internal version number. Google uses this number\nto determine whether one version is more recent than another. See\n[Version your app](https://developer.android.com/studio/publish/versioning#appversioning)\nfor more on how it is used and how it differs from [`version`](#version).\n\nIntroduced in\n[1.4.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.4.0).",
"type": "string"
},
+ "icons": {
+ "description": "Path to resources folder containing launcher icons for the app.",
+ "markdownDescription": "Path to resources folder containing launcher icons for the app.\n\nIf you're configuring icons for the first time, set this property to the path\nwhere you want to store your icons, then use\n[Image Asset Studio](https://developer.android.com/studio/write/image-asset-studio#access)\nto generate the assets.\n\nYou can read more about Android adaptive icons in the\n[Android documentation](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive).\n\nIntroduced in\n[1.6.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.6.0).",
+ "type": "string"
+ },
"signingConfigs": {
"description": "Use this to set the\nsigning\nconfigurations for the app.",
"markdownDescription": "Use this to set the\nsigning\nconfigurations for the app.\n\nThe JSON schema follows the Gradle DSL very closely. Below is what one would add\nfor the debug and release flavors:\n\n```javascript\n{\n \"android\": {\n \"signingConfigs\": {\n \"debug\": { // optional\n \"keyAlias\": \"androiddebugkey\", // defaults to \"androiddebugkey\"\n \"keyPassword\": \"android\", // defaults to \"android\n \"storeFile\": \"debug.keystore\", // required\n \"storePassword\": \"android\" // defaults to \"android\n },\n \"release\": { // optional\n \"keyAlias\": \"androiddebugkey\", // defaults to \"androiddebugkey\"\n \"keyPassword\": \"android\", // defaults to \"android\n \"storeFile\": \"release.keystore\", // required\n \"storePassword\": \"android\" // defaults to \"android\n }\n }\n }\n}\n```\n\nIntroduced in\n[0.11.0](https://github.com/microsoft/react-native-test-app/releases/tag/0.11.0).",
diff --git a/scripts/docs/android.icons.md b/scripts/docs/android.icons.md
new file mode 100644
index 000000000..40c4058d3
--- /dev/null
+++ b/scripts/docs/android.icons.md
@@ -0,0 +1,12 @@
+Path to resources folder containing launcher icons for the app.
+
+If you're configuring icons for the first time, set this property to the path
+where you want to store your icons, then use
+[Image Asset Studio](https://developer.android.com/studio/write/image-asset-studio#access)
+to generate the assets.
+
+You can read more about Android adaptive icons in the
+[Android documentation](https://developer.android.com/guide/practices/ui_guidelines/icon_design_adaptive).
+
+Introduced in
+[1.6.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.6.0).
diff --git a/scripts/docs/ios.icons.alternateIcons.md b/scripts/docs/ios.icons.alternateIcons.md
new file mode 100644
index 000000000..474d34c05
--- /dev/null
+++ b/scripts/docs/ios.icons.alternateIcons.md
@@ -0,0 +1,4 @@
+The primary icon for the Home screen and Settings app, among others.
+
+The equivalent key in `Info.plist` is
+[`CFBundleAlternateIcons`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons/cfbundlealternateicons).
diff --git a/scripts/docs/ios.icons.md b/scripts/docs/ios.icons.md
new file mode 100644
index 000000000..a6ecaaf0b
--- /dev/null
+++ b/scripts/docs/ios.icons.md
@@ -0,0 +1,13 @@
+Information about all of the icons used by the app.
+
+Icons for all sizes and scales are generated for you so long as you provide PNGs
+measuring 1024x1024 pixels here.
+
+You can read more about app icons in the
+[Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons).
+
+The equivalent key in `Info.plist` is
+[`CFBundleIcons`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons).
+
+Introduced in
+[1.6.0](https://github.com/microsoft/react-native-test-app/releases/tag/1.6.0).
diff --git a/scripts/docs/ios.icons.primaryIcon.md b/scripts/docs/ios.icons.primaryIcon.md
new file mode 100644
index 000000000..58a142f44
--- /dev/null
+++ b/scripts/docs/ios.icons.primaryIcon.md
@@ -0,0 +1,4 @@
+The primary icon for the Home screen and Settings app, among others.
+
+The equivalent key in `Info.plist` is
+[`CFBundlePrimaryIcon`](https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleicons/cfbundleprimaryicon).
diff --git a/scripts/generate-schema.mjs b/scripts/generate-schema.mjs
index a1a76bf28..d090e945b 100755
--- a/scripts/generate-schema.mjs
+++ b/scripts/generate-schema.mjs
@@ -48,12 +48,16 @@ export async function generateSchema() {
resources: dummy,
singleApp: dummy,
version: dummy,
+ "android.icons": dummy,
"android.signingConfigs": dummy,
"android.versionCode": dummy,
"ios.buildNumber": dummy,
"ios.codeSignEntitlements": dummy,
"ios.codeSignIdentity": dummy,
"ios.developmentTeam": dummy,
+ "ios.icons": dummy,
+ "ios.icons.primaryIcon": dummy,
+ "ios.icons.alternateIcons": dummy,
"windows.appxManifest": dummy,
"windows.certificateKeyFile": dummy,
"windows.certificatePassword": dummy,
@@ -65,6 +69,22 @@ export async function generateSchema() {
return {
$defs: {
+ appIconSet: {
+ type: "object",
+ properties: {
+ filename: {
+ description: "Path to the app icon file.",
+ type: "string",
+ },
+ prerendered: {
+ description:
+ "Whether the icon already incorporates a shine effect.",
+ type: "boolean",
+ },
+ },
+ required: ["filename", "prerendered"],
+ "exclude-from-codegen": true,
+ },
apple: {
type: "object",
properties: {
@@ -78,6 +98,30 @@ export async function generateSchema() {
markdownDescription: await docs["ios.buildNumber"],
type: "string",
},
+ icons: {
+ description: extractBrief(await docs["ios.icons"]),
+ markdownDescription: await docs["ios.icons"],
+ type: "object",
+ properties: {
+ primaryIcon: {
+ description: extractBrief(await docs["ios.icons.primaryIcon"]),
+ markdownDescription: await docs["ios.icons.primaryIcon"],
+ allOf: [{ $ref: "#/$defs/appIconSet" }],
+ },
+ alternateIcons: {
+ description: extractBrief(
+ await docs["ios.icons.alternateIcons"]
+ ),
+ markdownDescription: await docs["ios.icons.alternateIcons"],
+ type: "object",
+ additionalProperties: {
+ allOf: [{ $ref: "#/$defs/appIconSet" }],
+ type: "object",
+ },
+ },
+ },
+ required: ["primaryIcon"],
+ },
codeSignEntitlements: {
description: extractBrief(await docs["ios.codeSignEntitlements"]),
markdownDescription: await docs["ios.codeSignEntitlements"],
@@ -239,6 +283,11 @@ export async function generateSchema() {
markdownDescription: await docs["android.versionCode"],
type: "string",
},
+ icons: {
+ description: extractBrief(await docs["android.icons"]),
+ markdownDescription: await docs["android.icons"],
+ type: "string",
+ },
signingConfigs: {
description: extractBrief(await docs["android.signingConfigs"]),
markdownDescription: await docs["android.signingConfigs"],
@@ -321,6 +370,9 @@ export async function generateSchema() {
if (process.argv[1] === thisScript) {
generateSchema()
.then((schema) => {
+ for (const def of Object.values(schema.$defs)) {
+ delete def["exclude-from-codegen"];
+ }
return trimCarriageReturn(JSON.stringify(schema, undefined, 2)) + "\n";
})
.then((schema) => fs.writeFile("schema.json", schema))
diff --git a/scripts/validate-manifest.js b/scripts/validate-manifest.js
index ac3587f37..89e7701da 100755
--- a/scripts/validate-manifest.js
+++ b/scripts/validate-manifest.js
@@ -38,18 +38,8 @@ function findFile(file, startDir = process.cwd()) {
}
function makeValidator() {
- const { default: Ajv, _ } = require("ajv");
+ const { default: Ajv } = require("ajv");
const ajv = new Ajv({ allErrors: true });
- ajv.addKeyword({
- keyword: "exclude-from-codegen",
- type: "object",
- schemaType: "boolean",
- code: (cxt) => {
- const { data, schema } = cxt;
- const op = schema ? _`!==` : _`===`;
- cxt.fail(_`${data} %2 ${op} 0`);
- },
- });
ajv.addKeyword({ keyword: "markdownDescription" });
return ajv.compile(require(`${__dirname}/../schema.json`));
}
diff --git a/test-app.gradle b/test-app.gradle
index cef28d4ce..2d9e95b09 100644
--- a/test-app.gradle
+++ b/test-app.gradle
@@ -137,6 +137,11 @@ ext.applyTestAppModule = { Project project ->
main {
assets.srcDirs += generatedAssetsDir
res.srcDirs += generatedResDir
+ if (manifest.containsKey("android") && manifest["android"].containsKey("icons")) {
+ res.srcDirs += "${projectRoot}/${manifest["android"]["icons"]}"
+ } else {
+ res.srcDirs += "${testAppDir}/android/app/src/main/res-launcher"
+ }
}
}
}