From c6fc4271adb154ff46568600e42948c1c9079b62 Mon Sep 17 00:00:00 2001 From: Nicholas Levin Date: Wed, 1 Nov 2023 09:46:10 -0700 Subject: [PATCH] Add support for alternate app icons in UIKit via actool in Xcode 14+ (first introduced in 13). PiperOrigin-RevId: 578548155 --- apple/internal/ios_rules.bzl | 2 + apple/internal/partials/resources.bzl | 6 ++ .../partials/support/resources_support.bzl | 3 +- apple/internal/resource_actions/BUILD | 1 + apple/internal/resource_actions/actool.bzl | 64 ++++++++++++++++-- apple/internal/rule_attrs.bzl | 20 +++++- apple/internal/tvos_rules.bzl | 5 +- apple/internal/visionos_rules.bzl | 2 + doc/rules-ios.md | 5 +- doc/rules-tvos.md | 5 +- doc/rules-visionos.md | 5 +- .../ios_application_resources_test.bzl | 41 +++++++++++ test/starlark_tests/resources/BUILD | 5 ++ .../app_icon-bazel.appiconset/Bazel_logo.png | Bin 0 -> 10263 bytes .../app_icon-bazel.appiconset/Contents.json | 14 ++++ .../app_icon.appiconset/Contents.json | 15 ++++ .../app_icon.appiconset/app_icon.png | Bin 0 -> 23064 bytes .../targets_under_test/ios/BUILD | 39 +++++++++++ 18 files changed, 216 insertions(+), 16 deletions(-) create mode 100644 test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon-bazel.appiconset/Bazel_logo.png create mode 100644 test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon-bazel.appiconset/Contents.json create mode 100644 test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon.appiconset/Contents.json create mode 100644 test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon.appiconset/app_icon.png diff --git a/apple/internal/ios_rules.bzl b/apple/internal/ios_rules.bzl index 7e1740c3f6..86202e552a 100644 --- a/apple/internal/ios_rules.bzl +++ b/apple/internal/ios_rules.bzl @@ -374,6 +374,7 @@ def _ios_application_impl(ctx): launch_storyboard = ctx.file.launch_storyboard, locales_to_include = ctx.attr.locales_to_include, platform_prerequisites = platform_prerequisites, + primary_icon_name = ctx.attr.primary_app_icon, resource_deps = resource_deps, rule_descriptor = rule_descriptor, rule_label = label, @@ -2520,6 +2521,7 @@ ios_application = rule_factory.create_apple_rule( rule_attrs.app_icon_attrs( icon_extension = ".appiconset", icon_parent_extension = ".xcassets", + supports_alternate_icons = True, ), rule_attrs.app_intents_attrs( deps_cfg = transition_support.apple_platform_split_transition, diff --git a/apple/internal/partials/resources.bzl b/apple/internal/partials/resources.bzl index ab0293f3fa..2793132829 100644 --- a/apple/internal/partials/resources.bzl +++ b/apple/internal/partials/resources.bzl @@ -190,6 +190,7 @@ def _resources_partial_impl( locales_to_include, output_discriminator, platform_prerequisites, + primary_icon_name, resource_deps, rule_descriptor, rule_label, @@ -296,6 +297,7 @@ def _resources_partial_impl( "output_discriminator": output_discriminator, "parent_dir": parent_dir, "platform_prerequisites": platform_prerequisites, + "primary_icon_name": primary_icon_name, "product_type": rule_descriptor.product_type, "rule_label": rule_label, } @@ -398,6 +400,7 @@ def resources_partial( locales_to_include = [], output_discriminator = None, platform_prerequisites, + primary_icon_name = None, resource_deps, rule_descriptor, rule_label, @@ -438,6 +441,8 @@ def resources_partial( output_discriminator: A string to differentiate between different target intermediate files or `None`. platform_prerequisites: Struct containing information on the platform being targeted. + primary_icon_name: An optional String to identify the name of the primary app icon when + alternate app icons have been provided for the app. resource_deps: A list of dependencies that the resource aspect has been applied to. rule_descriptor: A rule descriptor for platform and product types from the rule context. rule_label: The label of the target being analyzed. @@ -471,6 +476,7 @@ def resources_partial( locales_to_include = locales_to_include, output_discriminator = output_discriminator, platform_prerequisites = platform_prerequisites, + primary_icon_name = primary_icon_name, resource_deps = resource_deps, rule_descriptor = rule_descriptor, rule_label = rule_label, diff --git a/apple/internal/partials/support/resources_support.bzl b/apple/internal/partials/support/resources_support.bzl index 4253d20490..236f6aa0e1 100644 --- a/apple/internal/partials/support/resources_support.bzl +++ b/apple/internal/partials/support/resources_support.bzl @@ -149,6 +149,7 @@ def _asset_catalogs( output_discriminator, parent_dir, platform_prerequisites, + primary_icon_name, product_type, rule_label, **_kwargs): @@ -159,7 +160,6 @@ def _asset_catalogs( assets_plist = None infoplists = [] if not parent_dir: - # TODO(kaipi): Merge this into the top level Info.plist. assets_plist_path = paths.join(parent_dir or "", "xcassets-info.plist") assets_plist = intermediates.file( actions = actions, @@ -211,6 +211,7 @@ def _asset_catalogs( output_dir = assets_dir, output_plist = assets_plist, platform_prerequisites = platform_prerequisites, + primary_icon_name = primary_icon_name, product_type = product_type, rule_label = rule_label, xctoolrunner = apple_mac_toolchain_info.xctoolrunner, diff --git a/apple/internal/resource_actions/BUILD b/apple/internal/resource_actions/BUILD index 96aa640982..bbf9c81672 100644 --- a/apple/internal/resource_actions/BUILD +++ b/apple/internal/resource_actions/BUILD @@ -19,6 +19,7 @@ bzl_library( "//apple/internal/utils:xctoolrunner", "@bazel_skylib//lib:collections", "@bazel_skylib//lib:paths", + "@bazel_skylib//lib:sets", "@build_bazel_apple_support//lib:apple_support", ], ) diff --git a/apple/internal/resource_actions/actool.bzl b/apple/internal/resource_actions/actool.bzl index 8fc2114550..137e4c8a25 100644 --- a/apple/internal/resource_actions/actool.bzl +++ b/apple/internal/resource_actions/actool.bzl @@ -22,6 +22,10 @@ load( "@bazel_skylib//lib:paths.bzl", "paths", ) +load( + "@bazel_skylib//lib:sets.bzl", + "sets", +) load( "@build_bazel_apple_support//lib:apple_support.bzl", "apple_support", @@ -50,6 +54,7 @@ def _actool_args_for_special_file_types( asset_files, bundle_id, platform_prerequisites, + primary_icon_name, product_type): """Returns command line arguments needed to compile special assets. @@ -63,6 +68,8 @@ def _actool_args_for_special_file_types( asset_files: The asset catalog files. bundle_id: The bundle ID to configure for this target. platform_prerequisites: Struct containing information on the platform being targeted. + primary_icon_name: An optional String to identify the name of the primary app icon when + alternate app icons have been provided for the app. product_type: The product type identifier used to describe the current bundle type. Returns: @@ -124,14 +131,55 @@ def _actool_args_for_special_file_types( [appicon_extension], attr = "app_icons", ).keys() - if len(icon_dirs) != 1: + if len(icon_dirs) != 1 and not primary_icon_name: formatted_dirs = "[\n %s\n]" % ",\n ".join(icon_dirs) - fail("The asset catalogs should contain exactly one directory named " + - "*.%s among its asset catalogs, " % appicon_extension + - "but found the following: " + formatted_dirs, "app_icons") - app_icon_name = paths.split_extension(paths.basename(icon_dirs[0]))[0] - args += ["--app-icon", app_icon_name] + # Alternate icons are only supported for UIKit applications on iOS, tvOS, visionOS and + # iOS-on-macOS (Catalyst) + if (platform_prerequisites.platform_type == apple_common.platform_type.watchos or + platform_prerequisites.platform_type == apple_common.platform_type.macos or + product_type != apple_product_type.application): + fail("The asset catalogs should contain exactly one directory named " + + "*.%s among its asset catalogs, " % appicon_extension + + "but found the following: " + formatted_dirs, "app_icons") + else: + fail(""" +Found multiple app icons among the asset catalogs with no primary_app_icon assigned. + +If you intend to assign multiple app icons to this target, please declare which of these is intended +to be the primary app icon with the primary_app_icon attribute on the rule itself. + +app_icons was assigned the following: {formatted_dirs} +""".format(formatted_dirs = formatted_dirs)) + elif primary_icon_name: + # Check that primary_icon_name matches one of the icon sets, then add actool arguments + # for `--alternate-app-icon` and `--app_icon` as appropriate. These do NOT overlap. + app_icon_names = sets.make() + for icon_dir in icon_dirs: + app_icon_names = sets.insert( + app_icon_names, + paths.split_extension(paths.basename(icon_dir))[0], + ) + app_icon_name_list = sets.to_list(app_icon_names) + found_primary = False + for app_icon_name in app_icon_name_list: + if app_icon_name == primary_icon_name: + found_primary = True + args += ["--app-icon", primary_icon_name] + else: + args += ["--alternate-app-icon", app_icon_name] + if not found_primary: + fail(""" +Could not find the primary icon named "{primary_icon_name}" in the list of app_icons provided. + +Found the following icon names from those provided: {app_icon_names}. +""".format( + primary_icon_name = primary_icon_name, + app_icon_names = ", ".join(app_icon_name_list), + )) + else: + app_icon_name = paths.split_extension(paths.basename(icon_dirs[0]))[0] + args += ["--app-icon", app_icon_name] # Add arguments for watch extension complication, if there is one. complication_files = [f for f in asset_files if ".complicationset/" in f.path] @@ -193,6 +241,7 @@ def compile_asset_catalog( output_dir, output_plist, platform_prerequisites, + primary_icon_name, product_type, rule_label, xctoolrunner): @@ -217,6 +266,8 @@ def compile_asset_catalog( output_plist: The file reference for the output plist that should be merged into Info.plist. May be None if the output plist is not desired. platform_prerequisites: Struct containing information on the platform being targeted. + primary_icon_name: An optional String to identify the name of the primary app icon when + alternate app icons have been provided for the app. product_type: The product type identifier used to describe the current bundle type. rule_label: The label of the target being analyzed. xctoolrunner: A files_to_run for the wrapper around the "xcrun" tool. @@ -239,6 +290,7 @@ def compile_asset_catalog( asset_files = asset_files, bundle_id = bundle_id, platform_prerequisites = platform_prerequisites, + primary_icon_name = primary_icon_name, product_type = product_type, )) args.extend(collections.before_each( diff --git a/apple/internal/rule_attrs.bzl b/apple/internal/rule_attrs.bzl index e57161b482..f88ba0e53e 100644 --- a/apple/internal/rule_attrs.bzl +++ b/apple/internal/rule_attrs.bzl @@ -651,7 +651,11 @@ hermetic given these inputs to ensure that the result can be safely cached. ), } -def _app_icon_attrs(*, icon_extension = ".appiconset", icon_parent_extension = ".xcassets"): +def _app_icon_attrs( + *, + icon_extension = ".appiconset", + icon_parent_extension = ".xcassets", + supports_alternate_icons = False): """Returns the attribute required to define app icons for the given target. Args: @@ -659,8 +663,10 @@ def _app_icon_attrs(*, icon_extension = ".appiconset", icon_parent_extension = " app icon assets. Optional. Defaults to `.appiconset`. icon_parent_extension: A String representing the extension required of the parent directory of the directory containing the app icon assets. Optional. Defaults to `.xcassets`. + supports_alternate_icons: Bool representing if the rule supports alternate icons. False by + default. """ - return { + app_icon_attrs = { "app_icons": attr.label_list( allow_files = True, doc = """ @@ -672,6 +678,16 @@ named `*.{app_icon_parent_extension}/*.{app_icon_extension}` and there may be on ), ), } + if supports_alternate_icons: + app_icon_attrs = dicts.add(app_icon_attrs, { + "primary_app_icon": attr.string( + doc = """ +An optional String to identify the name of the primary app icon when alternate app icons have been +provided for the app. +""", + ), + }) + return app_icon_attrs def _launch_images_attrs(): """Returns the attribute required to support launch images for a given target.""" diff --git a/apple/internal/tvos_rules.bzl b/apple/internal/tvos_rules.bzl index 3a7245b3ea..b24f958bdb 100644 --- a/apple/internal/tvos_rules.bzl +++ b/apple/internal/tvos_rules.bzl @@ -340,6 +340,7 @@ def _tvos_application_impl(ctx): launch_storyboard = ctx.file.launch_storyboard, locales_to_include = ctx.attr.locales_to_include, platform_prerequisites = platform_prerequisites, + primary_icon_name = ctx.attr.primary_app_icon, resource_deps = resource_deps, rule_descriptor = rule_descriptor, rule_label = label, @@ -1451,7 +1452,9 @@ tvos_application = rule_factory.create_apple_rule( is_executable = True, predeclared_outputs = {"archive": "%{name}.ipa"}, attrs = [ - rule_attrs.app_icon_attrs(), + rule_attrs.app_icon_attrs( + supports_alternate_icons = True, + ), rule_attrs.app_intents_attrs( deps_cfg = transition_support.apple_platform_split_transition, ), diff --git a/apple/internal/visionos_rules.bzl b/apple/internal/visionos_rules.bzl index db29d1a497..f003f7acf8 100644 --- a/apple/internal/visionos_rules.bzl +++ b/apple/internal/visionos_rules.bzl @@ -344,6 +344,7 @@ Resolved Xcode is version {xcode_version}. launch_storyboard = None, locales_to_include = ctx.attr.locales_to_include, platform_prerequisites = platform_prerequisites, + primary_icon_name = ctx.attr.primary_app_icon, resource_deps = resource_deps, rule_descriptor = rule_descriptor, rule_label = label, @@ -1447,6 +1448,7 @@ visionos_application = rule_factory.create_apple_rule( rule_attrs.app_icon_attrs( icon_extension = ".solidimagestack", icon_parent_extension = ".xcassets", + supports_alternate_icons = True, ), rule_attrs.app_intents_attrs( deps_cfg = transition_support.apple_platform_split_transition, diff --git a/doc/rules-ios.md b/doc/rules-ios.md index b9fd0ff770..4c3230b53c 100644 --- a/doc/rules-ios.md +++ b/doc/rules-ios.md @@ -64,8 +64,8 @@ ios_application(name, exported_symbols_lists, extensions, families, frameworks, include_symbols_in_bundle, infoplists, ipa_post_processor, launch_images, launch_storyboard, linkopts, locales_to_include, minimum_deployment_os_version, minimum_os_version, platform_type, - provisioning_profile, sdk_frameworks, settings_bundle, shared_capabilities, stamp, - strings, version, watch_application) + primary_app_icon, provisioning_profile, sdk_frameworks, settings_bundle, + shared_capabilities, stamp, strings, version, watch_application) Builds and bundles an iOS Application. @@ -105,6 +105,7 @@ Builds and bundles an iOS Application. | minimum_deployment_os_version | A required string indicating the minimum deployment OS version supported by the target, represented as a dotted version number (for example, "9.0"). This is different from `minimum_os_version`, which is effective at compile time. Ensure version specific APIs are guarded with `available` clauses. | String | optional | `""` | | minimum_os_version | A required string indicating the minimum OS version supported by the target, represented as a dotted version number (for example, "9.0"). | String | required | | | platform_type | - | String | optional | `"ios"` | +| primary_app_icon | An optional String to identify the name of the primary app icon when alternate app icons have been provided for the app. | String | optional | `""` | | provisioning_profile | The provisioning profile (`.mobileprovision` file) to use when creating the bundle. This value is optional for simulator builds as the simulator doesn't fully enforce entitlements, but is required for device builds. | Label | optional | `None` | | sdk_frameworks | Names of SDK frameworks to link with (e.g., `AddressBook`, `QuartzCore`). `UIKit` and `Foundation` are always included, even if this attribute is provided and does not list them.

This attribute is discouraged; in general, targets should list system framework dependencies in the library targets where that framework is used, not in the top-level bundle. | List of strings | optional | `[]` | | settings_bundle | A resource bundle (e.g. `apple_bundle_import`) target that contains the files that make up the application's settings bundle. These files will be copied into the root of the final application bundle in a directory named `Settings.bundle`. | Label | optional | `None` | diff --git a/doc/rules-tvos.md b/doc/rules-tvos.md index c347b3495c..d0b59d5e09 100644 --- a/doc/rules-tvos.md +++ b/doc/rules-tvos.md @@ -12,8 +12,8 @@ tvos_application(name, entitlements_validation, executable_name, exported_symbols_lists, extensions, families, frameworks, infoplists, ipa_post_processor, launch_images, launch_storyboard, linkopts, locales_to_include, minimum_deployment_os_version, - minimum_os_version, platform_type, provisioning_profile, settings_bundle, - shared_capabilities, stamp, strings, version) + minimum_os_version, platform_type, primary_app_icon, provisioning_profile, + settings_bundle, shared_capabilities, stamp, strings, version) Builds and bundles a tvOS Application. @@ -50,6 +50,7 @@ Builds and bundles a tvOS Application. | minimum_deployment_os_version | A required string indicating the minimum deployment OS version supported by the target, represented as a dotted version number (for example, "9.0"). This is different from `minimum_os_version`, which is effective at compile time. Ensure version specific APIs are guarded with `available` clauses. | String | optional | `""` | | minimum_os_version | A required string indicating the minimum OS version supported by the target, represented as a dotted version number (for example, "9.0"). | String | required | | | platform_type | - | String | optional | `"tvos"` | +| primary_app_icon | An optional String to identify the name of the primary app icon when alternate app icons have been provided for the app. | String | optional | `""` | | provisioning_profile | The provisioning profile (`.mobileprovision` file) to use when creating the bundle. This value is optional for simulator builds as the simulator doesn't fully enforce entitlements, but is required for device builds. | Label | optional | `None` | | settings_bundle | A resource bundle (e.g. `apple_bundle_import`) target that contains the files that make up the application's settings bundle. These files will be copied into the root of the final application bundle in a directory named `Settings.bundle`. | Label | optional | `None` | | shared_capabilities | A list of shared `apple_capability_set` rules to represent the capabilities that a code sign aware Apple bundle rule output should have. These can define the formal prefix for the target's `bundle_id` and can further be merged with information provided by `entitlements`, if defined by any capabilities found within the `apple_capability_set`. | List of labels | optional | `[]` | diff --git a/doc/rules-visionos.md b/doc/rules-visionos.md index 6000403a61..6c29310e3c 100755 --- a/doc/rules-visionos.md +++ b/doc/rules-visionos.md @@ -12,8 +12,8 @@ visionos_application(name, entitlements, entitlements_validation, executable_name, exported_symbols_lists, extensions, families, frameworks, infoplists, ipa_post_processor, launch_storyboard, linkopts, locales_to_include, minimum_deployment_os_version, - minimum_os_version, platform_type, provisioning_profile, shared_capabilities, - stamp, strings, version) + minimum_os_version, platform_type, primary_app_icon, provisioning_profile, + shared_capabilities, stamp, strings, version) Builds and bundles a visionOS Application. @@ -49,6 +49,7 @@ Builds and bundles a visionOS Application. | minimum_deployment_os_version | A required string indicating the minimum deployment OS version supported by the target, represented as a dotted version number (for example, "9.0"). This is different from `minimum_os_version`, which is effective at compile time. Ensure version specific APIs are guarded with `available` clauses. | String | optional | `""` | | minimum_os_version | A required string indicating the minimum OS version supported by the target, represented as a dotted version number (for example, "9.0"). | String | required | | | platform_type | - | String | optional | `"visionos"` | +| primary_app_icon | An optional String to identify the name of the primary app icon when alternate app icons have been provided for the app. | String | optional | `""` | | provisioning_profile | The provisioning profile (`.mobileprovision` file) to use when creating the bundle. This value is optional for simulator builds as the simulator doesn't fully enforce entitlements, but is required for device builds. | Label | optional | `None` | | shared_capabilities | A list of shared `apple_capability_set` rules to represent the capabilities that a code sign aware Apple bundle rule output should have. These can define the formal prefix for the target's `bundle_id` and can further be merged with information provided by `entitlements`, if defined by any capabilities found within the `apple_capability_set`. | List of labels | optional | `[]` | | stamp | Enable link stamping. Whether to encode build information into the binary. Possible values:

* `stamp = 1`: Stamp the build information into the binary. Stamped binaries are only rebuilt when their dependencies change. Use this if there are tests that depend on the build information. * `stamp = 0`: Always replace build information by constant values. This gives good build result caching. * `stamp = -1`: Embedding of build information is controlled by the `--[no]stamp` flag. | Integer | optional | `-1` | diff --git a/test/starlark_tests/ios_application_resources_test.bzl b/test/starlark_tests/ios_application_resources_test.bzl index aa1aafd4e5..1e8eef0cf9 100644 --- a/test/starlark_tests/ios_application_resources_test.bzl +++ b/test/starlark_tests/ios_application_resources_test.bzl @@ -175,6 +175,47 @@ def ios_application_resources_test_suite(name): tags = [name], ) + # Test that when alternate app icons are declared alongside the primary app icon, that they are + # bundled in expected locations with the app, that they are embedded within the plist + # referencing their file names, and that they are also bundled within the asset catalog for the + # application. + archive_contents_test( + name = "{}_alt_app_icons_test".format(name), + build_type = "device", + target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_alternate_app_icons", + contains = [ + "$BUNDLE_ROOT/app_icon60x60@2x.png", + "$BUNDLE_ROOT/app_icon76x76@2x~ipad.png", + "$BUNDLE_ROOT/app_icon-bazel60x60@2x.png", + "$BUNDLE_ROOT/app_icon-bazel76x76@2x~ipad.png", + ], + plist_test_file = "$CONTENT_ROOT/Info.plist", + plist_test_values = { + "CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles:0": "app_icon", + "CFBundleIcons:CFBundleAlternateIcons:CFBundleIconFiles:0": "app_icon-bazel", + }, + text_test_file = "$BUNDLE_ROOT/Assets.car", + text_test_values = ["app_icon", "app_icon-bazel"], + tags = [name], + ) + + analysis_failure_message_test( + name = "{}_alt_app_icons_missing_primary_icon_name_test".format(name), + target_under_test = "//test/starlark_tests/targets_under_test/ios:app_with_alternate_app_icons_without_primary", + expected_error = """ +Found multiple app icons among the asset catalogs with no primary_app_icon assigned. + +If you intend to assign multiple app icons to this target, please declare which of these is intended +to be the primary app icon with the primary_app_icon attribute on the rule itself. + +app_icons was assigned the following: [ + test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon-bazel.appiconset, + test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon.appiconset +] +""", + tags = [name], + ) + # Tests that apple_bundle_import files are bundled correctly with the application. archive_contents_test( name = "{}_apple_bundle_test".format(name), diff --git a/test/starlark_tests/resources/BUILD b/test/starlark_tests/resources/BUILD index be9ed22edb..7fc61cda01 100644 --- a/test/starlark_tests/resources/BUILD +++ b/test/starlark_tests/resources/BUILD @@ -485,6 +485,11 @@ filegroup( srcs = glob(["alticons/**"]), ) +filegroup( + name = "app_icons_with_alts_ios", + srcs = glob(["app_icons_with_alts_ios.xcassets/**"]), +) + filegroup( name = "launch_images_ios", srcs = glob(["launch_images_ios.xcassets/**"]), diff --git a/test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon-bazel.appiconset/Bazel_logo.png b/test/starlark_tests/resources/app_icons_with_alts_ios.xcassets/app_icon-bazel.appiconset/Bazel_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2dde57feb15fab7bc1c2f56e7bea45044f74818d GIT binary patch literal 10263 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 BSgHU3 literal 0 HcmV?d00001 diff --git a/test/starlark_tests/targets_under_test/ios/BUILD b/test/starlark_tests/targets_under_test/ios/BUILD index 0a18fdb46b..9fcbc8a05b 100644 --- a/test/starlark_tests/targets_under_test/ios/BUILD +++ b/test/starlark_tests/targets_under_test/ios/BUILD @@ -424,6 +424,45 @@ ios_application( ], ) +ios_application( + name = "app_with_alternate_app_icons", + app_icons = ["//test/starlark_tests/resources:app_icons_with_alts_ios"], + bundle_id = "com.google.example", + families = [ + "iphone", + "ipad", + ], + infoplists = [ + "//test/starlark_tests/resources:Info.plist", + ], + minimum_os_version = common.min_os_ios.baseline, + primary_app_icon = "app_icon", + provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision", + tags = common.fixture_tags, + deps = [ + "//test/starlark_tests/resources:objc_main_lib", + ], +) + +ios_application( + name = "app_with_alternate_app_icons_without_primary", + app_icons = ["//test/starlark_tests/resources:app_icons_with_alts_ios"], + bundle_id = "com.google.example", + families = [ + "iphone", + "ipad", + ], + infoplists = [ + "//test/starlark_tests/resources:Info.plist", + ], + minimum_os_version = common.min_os_ios.baseline, + provisioning_profile = "//test/testdata/provisioning:integration_testing_ios.mobileprovision", + tags = common.fixture_tags, + deps = [ + "//test/starlark_tests/resources:objc_main_lib", + ], +) + # --------------------------------------------------------------------------------------- ios_application(