Skip to content

Commit

Permalink
App Extension rules validation flags
Browse files Browse the repository at this point in the history
  • Loading branch information
maustinstar committed May 1, 2023
1 parent 22d8f3a commit bf0f818
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 19 deletions.
6 changes: 6 additions & 0 deletions apple/internal/ios_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -954,8 +954,12 @@ def _ios_extension_impl(ctx):
if ctx.attr.extensionkit_extension:
bundle_location = processor.location.extension
product_type = apple_product_type.extensionkit_extension
extensionkit_keys_required = True
nsextension_keys_required = False
else:
bundle_location = processor.location.plugin
extensionkit_keys_required = False
nsextension_keys_required = True

entitlements = entitlements_support.process_entitlements(
actions = actions,
Expand Down Expand Up @@ -1091,7 +1095,9 @@ def _ios_extension_impl(ctx):
bundle_name = bundle_name,
environment_plist = ctx.file._environment_plist,
executable_name = executable_name,
extensionkit_keys_required = extensionkit_keys_required,
launch_storyboard = None,
nsextension_keys_required = nsextension_keys_required,
platform_prerequisites = platform_prerequisites,
resource_deps = resource_deps,
rule_descriptor = rule_descriptor,
Expand Down
6 changes: 6 additions & 0 deletions apple/internal/macos_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,12 @@ def _macos_extension_impl(ctx):
if ctx.attr.extensionkit_extension:
bundle_location = processor.location.extension
product_type = apple_product_type.extensionkit_extension
extensionkit_keys_required = True
nsextension_keys_required = False
else:
bundle_location = processor.location.plugin
extensionkit_keys_required = False
nsextension_keys_required = True

entitlements = entitlements_support.process_entitlements(
actions = actions,
Expand Down Expand Up @@ -675,7 +679,9 @@ def _macos_extension_impl(ctx):
bundle_name = bundle_name,
environment_plist = ctx.file._environment_plist,
executable_name = executable_name,
extensionkit_keys_required = extensionkit_keys_required,
launch_storyboard = None,
nsextension_keys_required = nsextension_keys_required,
platform_prerequisites = platform_prerequisites,
resource_deps = resource_deps,
rule_descriptor = rule_descriptor,
Expand Down
12 changes: 12 additions & 0 deletions apple/internal/partials/resources.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ def _resources_partial_impl(
executable_name,
bundle_verification_targets,
environment_plist,
extensionkit_keys_required,
launch_storyboard,
nsextension_keys_required,
output_discriminator,
platform_prerequisites,
resource_deps,
Expand Down Expand Up @@ -317,8 +319,10 @@ def _resources_partial_impl(
child_plists = bundle_verification_infoplists,
child_required_values = bundle_verification_required_values,
environment_plist = environment_plist,
extensionkit_keys_required = extensionkit_keys_required,
input_plists = infoplists,
launch_storyboard = launch_storyboard,
nsextension_keys_required = nsextension_keys_required,
out_infoplist = out_infoplist,
output_discriminator = output_discriminator,
platform_prerequisites = platform_prerequisites,
Expand Down Expand Up @@ -346,7 +350,9 @@ def resources_partial(
executable_name,
bundle_verification_targets = [],
environment_plist,
extensionkit_keys_required = False,
launch_storyboard,
nsextension_keys_required = False,
output_discriminator = None,
platform_prerequisites,
resource_deps,
Expand Down Expand Up @@ -378,7 +384,11 @@ def resources_partial(
plist entry that must contain this target's bundle ID.
environment_plist: File referencing a plist with the required variables about the versions
the target is being built for and with.
extensionkit_keys_required: Whether to validate that the Info.plist ExtensionKit keys are correctly
configured.
launch_storyboard: A file to be used as a launch screen for the application.
nsextension_keys_required: Whether to validate that the Info.plist ExtensionKit keys are correctly
configured.
output_discriminator: A string to differentiate between different target intermediate files
or `None`.
platform_prerequisites: Struct containing information on the platform being targeted.
Expand Down Expand Up @@ -406,9 +416,11 @@ def resources_partial(
bundle_id = bundle_id,
bundle_name = bundle_name,
executable_name = executable_name,
extensionkit_keys_required = extensionkit_keys_required,
bundle_verification_targets = bundle_verification_targets,
environment_plist = environment_plist,
launch_storyboard = launch_storyboard,
nsextension_keys_required = nsextension_keys_required,
output_discriminator = output_discriminator,
platform_prerequisites = platform_prerequisites,
resource_deps = resource_deps,
Expand Down
14 changes: 14 additions & 0 deletions apple/internal/resource_actions/plist.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,11 @@ def merge_root_infoplists(
child_plists = [],
child_required_values = [],
environment_plist,
extensionkit_keys_required = False,
include_executable_name = True,
input_plists,
launch_storyboard,
nsextension_keys_required = False,
output_discriminator,
output_plist,
output_pkginfo,
Expand Down Expand Up @@ -223,11 +225,17 @@ def merge_root_infoplists(
pair, see plisttool's `child_plist_required_values`, as this is passed
straight through to it.
environment_plist: An executable file referencing the environment_plist tool.
extensionkit_keys_required: If True, the merged Info.plist file must include
an EXAppExtensionAttributes dictionary containing EXExtensionPointIdentifier.
The presence of an NSExtension entry will raise an error.
include_executable_name: If True, the executable name will be added to
the plist in the `CFBundleExecutable` key. This is mainly intended for
plists embedded in a command line tool which don't need this value.
input_plists: The root plist files to merge.
launch_storyboard: A file to be used as a launch screen for the application.
nsextension_keys_required: If True, the merged Info.plist file must include
an NSExtension dictionary containing NSExtensionPointIdentifier.
The presence of an EXAppExtensionAttributes entry will raise an error.
output_discriminator: A string to differentiate between different target intermediate files
or `None`.
output_pkginfo: The file reference for the PkgInfo file. Can be None if not
Expand Down Expand Up @@ -298,6 +306,12 @@ def merge_root_infoplists(
**{str(p.owner): v for (p, v) in child_required_values}
)

if extensionkit_keys_required:
info_plist_options["extensionkit_keys_required"] = True

if nsextension_keys_required:
info_plist_options["nsextension_keys_required"] = True

if (version != None and AppleBundleVersionInfo in version):
version_info = version[AppleBundleVersionInfo]
input_files.append(version_info.version_file)
Expand Down
6 changes: 6 additions & 0 deletions apple/internal/tvos_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -904,8 +904,12 @@ def _tvos_extension_impl(ctx):
if ctx.attr.extensionkit_extension:
bundle_location = processor.location.extension
product_type = apple_product_type.extensionkit_extension
extensionkit_keys_required = True
nsextension_keys_required = False
else:
bundle_location = processor.location.plugin
extensionkit_keys_required = False
nsextension_keys_required = True

entitlements = entitlements_support.process_entitlements(
actions = actions,
Expand Down Expand Up @@ -1026,7 +1030,9 @@ def _tvos_extension_impl(ctx):
bundle_name = bundle_name,
environment_plist = ctx.file._environment_plist,
executable_name = executable_name,
extensionkit_keys_required = extensionkit_keys_required,
launch_storyboard = None,
nsextension_keys_required = nsextension_keys_required,
platform_prerequisites = platform_prerequisites,
resource_deps = resource_deps,
rule_descriptor = rule_descriptor,
Expand Down
6 changes: 6 additions & 0 deletions apple/internal/watchos_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -861,8 +861,12 @@ def _watchos_extension_impl(ctx):
if ctx.attr.extensionkit_extension:
bundle_location = processor.location.extension
product_type = apple_product_type.extensionkit_extension
extensionkit_keys_required = True
nsextension_keys_required = False
else:
bundle_location = processor.location.plugin
extensionkit_keys_required = False
nsextension_keys_required = True

# Xcode 11 requires this flag to be passed to the linker, but it is not accepted by earlier
# versions.
Expand Down Expand Up @@ -1035,7 +1039,9 @@ def _watchos_extension_impl(ctx):
bundle_name = bundle_name,
environment_plist = ctx.file._environment_plist,
executable_name = executable_name,
extensionkit_keys_required = extensionkit_keys_required,
launch_storyboard = None,
nsextension_keys_required = nsextension_keys_required,
platform_prerequisites = platform_prerequisites,
resource_deps = resource_deps,
rule_descriptor = rule_descriptor,
Expand Down
2 changes: 1 addition & 1 deletion examples/macos/HelloToday/Ext-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<string>2.0</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widget-extension</string>
<string>com.apple.widgetkit-extension</string>
<key>NSExtensionPrincipalClass</key>
<string>TodayViewController</string>
<key>com.apple.notificationcenter.widget.description</key>
Expand Down
63 changes: 56 additions & 7 deletions test/ios_extension_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ EOF
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down Expand Up @@ -240,7 +240,7 @@ function test_missing_version_fails() {
CFBundleShortVersionString = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand All @@ -265,7 +265,7 @@ function test_missing_short_version_fails() {
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down Expand Up @@ -337,7 +337,7 @@ EOF
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down Expand Up @@ -407,7 +407,7 @@ EOF
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down Expand Up @@ -477,7 +477,7 @@ EOF
CFBundleVersion = "1.1";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand All @@ -486,6 +486,55 @@ EOF
expect_log "While processing target \"//app:app\"; the CFBundleVersion of the child target \"//app:ext\" should be the same as its parent's version string \"1.0\", but found \"1.1\"."
}

# Test that a known ExtensionKit extension point provides a warning.
function test_known_extensionkit_warning() {
create_common_files
create_minimal_ios_application_with_extension

# Replace the file, but without CFBundleVersion.
cat > app/Info-Ext.plist <<EOF
{
CFBundleIdentifier = "\${PRODUCT_BUNDLE_IDENTIFIER}";
CFBundleName = "\${PRODUCT_NAME}";
CFBundlePackageType = "XPC!";
CFBundleShortVersionString = "1.0";
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPointIdentifier = "com.apple.appintents-extension";
};
}
EOF

do_build ios //app:app || fail "Should build"

expect_log 'Target //app:ext with extension point com.apple.appintents-extension is known to be an ExtensionKit App Extension. The target rule may be misconfigured. ExtensionKit App Extension targets expect the attribute `extensionkit_extension = True`.'
}

# Test the presence of EXAppExtensionAttributes fails the build.
function test_exappextensionattributes_fails() {
create_common_files
create_minimal_ios_application_with_extension

# Replace the file, but without CFBundleVersion.
cat > app/Info-Ext.plist <<EOF
{
CFBundleIdentifier = "\${PRODUCT_BUNDLE_IDENTIFIER}";
CFBundleName = "\${PRODUCT_NAME}";
CFBundlePackageType = "XPC!";
CFBundleShortVersionString = "1.0";
CFBundleVersion = "1.0";
EXAppExtensionAttributes = {
EXExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF

! do_build ios //app:app \
|| fail "Should fail build"

expect_log 'Target //app:ext has an unexpected key, EXAppExtensionAttributes, for product type com.apple.product-type.app-extension. Plugin extensions expect key NSExtension. To build an app extension with ExtensionKit, set `extensionkit_extension = True`.'
}

# Tests that a prebuilt static framework (i.e., apple_static_framework_import)
# is not bundled with the application or extension.
function test_prebuilt_static_apple_framework_import_dependency() {
Expand Down Expand Up @@ -599,7 +648,7 @@ EOF
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down
49 changes: 49 additions & 0 deletions test/ios_extensionkit_extension_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,55 @@ EOF
expect_log "While processing target \"//app:app\"; the CFBundleVersion of the child target \"//app:ext\" should be the same as its parent's version string \"1.0\", but found \"1.1\"."
}

# Test that a known NSExtension extension point provides a warning.
function test_known_nsextension_warning() {
create_common_files
create_minimal_ios_application_with_extension

# Replace the file, but without CFBundleVersion.
cat > app/Info-Ext.plist <<EOF
{
CFBundleIdentifier = "\${PRODUCT_BUNDLE_IDENTIFIER}";
CFBundleName = "\${PRODUCT_NAME}";
CFBundlePackageType = "XPC!";
CFBundleShortVersionString = "1.0";
CFBundleVersion = "1.0";
EXAppExtensionAttributes = {
EXExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF

do_build ios //app:app || fail "Should build"

expect_log 'Target //app:ext with extension point com.apple.widgetkit-extension is known to be an NSExtension. The target rule may be misconfigured. NSExtension targets expect the attribute `extensionkit_extension = False`.'
}

# Test the presence of NSExtension fails the build.
function test_nsextension_fails() {
create_common_files
create_minimal_ios_application_with_extension

# Replace the file, but without CFBundleVersion.
cat > app/Info-Ext.plist <<EOF
{
CFBundleIdentifier = "\${PRODUCT_BUNDLE_IDENTIFIER}";
CFBundleName = "\${PRODUCT_NAME}";
CFBundlePackageType = "XPC!";
CFBundleShortVersionString = "1.0";
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPointIdentifier = "com.apple.appintents-extension";
};
}
EOF

! do_build ios //app:app \
|| fail "Should fail build"

expect_log 'Target //app:ext has an unexpected key, NSExtension, for product type com.apple.product-type.extensionkit-extension. ExtensionKit extensions expect key EXAppExtensionAttributes. To build an app extension without ExtensionKit, set `extensionkit_extension = False`.'
}

# Tests that a prebuilt static framework (i.e., apple_static_framework_import)
# is not bundled with the application or extension.
function test_prebuilt_static_apple_framework_import_dependency() {
Expand Down
2 changes: 1 addition & 1 deletion test/ios_imessage_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ EOF
CFBundleVersion = "1.0";
NSExtension = {
NSExtensionPrincipalClass = "DummyValue";
NSExtensionPointIdentifier = "com.apple.widget-extension";
NSExtensionPointIdentifier = "com.apple.widgetkit-extension";
};
}
EOF
Expand Down
Loading

0 comments on commit bf0f818

Please sign in to comment.