aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-04-05 00:33:31 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-04-05 14:08:58 +0000
commitf07fd407c2b618b4ed0dc05edaa8d38a6918f5c4 (patch)
tree625b829d8162bae986f3c5edec006a3fbcd31909 /src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
parentae8d6873a400393f14ab6ed7bd8d810ebfed5beb (diff)
Add 'apple_watch1_extension' and 'apple_watch_extension_binary' to support building watch OS 1 apps.
RELNOTES: Support apple_watch1_extension and apple_watch_extension_binary rules for creating watch OS 1 extensions. -- MOS_MIGRATED_REVID=119000703
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
new file mode 100644
index 0000000000..cc3492f997
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/WatchUtils.java
@@ -0,0 +1,172 @@
+// Copyright 2016 The Bazel Authors. All rights reserved.
+//
+// Licensed 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.
+
+package com.google.devtools.build.lib.rules.objc;
+
+import static com.google.devtools.build.lib.rules.objc.ObjcProvider.ROOT_MERGE_ZIP;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
+import com.google.devtools.build.lib.rules.apple.DottedVersion;
+import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.XcodeprojBuildSetting;
+
+/**
+ * Contains support methods for common processing and generating of watch extension and
+ * application bundles.
+ */
+final class WatchUtils {
+
+ /**
+ * Supported Apple watch OS versions.
+ */
+ enum WatchOSVersion {
+ OS1(XcodeProductType.WATCH_OS1_APPLICATION, XcodeProductType.WATCH_OS1_EXTENSION,
+ "WatchKitSupport");
+
+ private final XcodeProductType applicationXcodeProductType;
+ private final XcodeProductType extensionXcodeProductType;
+ private final String watchKitSupportDirName;
+
+ WatchOSVersion(XcodeProductType applicationXcodeProductType,
+ XcodeProductType extensionXcodeProductType,
+ String watchKitSupportDirName) {
+ this.applicationXcodeProductType = applicationXcodeProductType;
+ this.extensionXcodeProductType = extensionXcodeProductType;
+ this.watchKitSupportDirName = watchKitSupportDirName;
+ }
+
+ /**
+ * Returns the {@link XcodeProductType} to be used for the watch application's Xcode target.
+ */
+ XcodeProductType getApplicationXcodeProductType() {
+ return applicationXcodeProductType;
+ }
+
+ /**
+ * Returns the {@link XcodeProductType} to be used for the watch extension's Xcode target.
+ */
+ XcodeProductType getExtensionXcodeProductType() {
+ return extensionXcodeProductType;
+ }
+
+ /**
+ * Returns the name of the directory in the final iOS bundle which should contain the WatchKit
+ * support stub.
+ */
+ String getWatchKitSupportDirName() {
+ return watchKitSupportDirName;
+ }
+ }
+
+ @VisibleForTesting
+ static final String WATCH_KIT_STUB_PATH =
+ "${SDKROOT}/Library/Application\\ Support/WatchKit/WK";
+
+ // Apple only accepts watch extension and application starting at 8.2.
+ @VisibleForTesting
+ static final DottedVersion MINIMUM_OS_VERSION = DottedVersion.fromString("8.2");
+
+ /**
+ * Adds common xcode build settings required for watch bundles to the given xcode provider
+ * builder.
+ */
+ static void addXcodeSettings(RuleContext ruleContext,
+ XcodeProvider.Builder xcodeProviderBuilder) {
+ xcodeProviderBuilder.addMainTargetXcodeprojBuildSettings(xcodeSettings(ruleContext));
+ }
+
+ /**
+ * Watch Extension are not accepted by Apple below version 8.2. While applications built with a
+ * minimum iOS version of less than 8.2 may contain watch extension in their bundle, the
+ * extension itself needs to be built with 8.2 or higher. This logic overrides (if necessary)
+ * any flag-set minimum iOS version for extensions only so that this requirement is not
+ * violated.
+ */
+ static DottedVersion determineMinimumOsVersion(DottedVersion fromFlag) {
+ return Ordering.natural().max(fromFlag, MINIMUM_OS_VERSION);
+ }
+
+ static boolean isBuildingForWatchOS1Version(WatchOSVersion watchOSVersion) {
+ return watchOSVersion == WatchOSVersion.OS1;
+ }
+
+ /**
+ * Adds WatchKitSupport stub to the final ipa and exposes it to given @{link ObjcProvider.Builder}
+ * based on watch OS version.
+ *
+ * For example, for watch OS 1, the resulting ipa will have:
+ * Payload/TestApp.app
+ * WatchKitSupport
+ * WatchKitSupport/WK
+ */
+ static void registerActionsToAddWatchSupport(
+ RuleContext ruleContext, ObjcProvider.Builder objcProviderBuilder,
+ WatchOSVersion watchOSVersion) {
+ Artifact watchSupportZip = watchSupportZip(ruleContext);
+ String workingDirectory = watchSupportZip.getExecPathString()
+ .substring(0, watchSupportZip.getExecPathString().lastIndexOf('/'));
+ String watchKitSupportDirName = watchOSVersion.getWatchKitSupportDirName();
+ String watchKitSupportPath = workingDirectory + "/" + watchKitSupportDirName;
+
+ ImmutableList<String> command = ImmutableList.of(
+ // 1. Copy WK stub binary to watchKitSupportPath.
+ "mkdir -p " + watchKitSupportPath,
+ "&&",
+ String.format("cp %s %s", WATCH_KIT_STUB_PATH, watchKitSupportPath),
+ // 2. cd to working directory.
+ "&&",
+ "cd " + workingDirectory,
+ // 3. Zip watchSupport.
+ "&&",
+ String.format(
+ "/usr/bin/zip -q -r -0 %s %s",
+ watchSupportZip.getFilename(),
+ watchKitSupportDirName));
+
+ ruleContext.registerAction(ObjcRuleClasses.spawnAppleEnvActionBuilder(ruleContext,
+ ruleContext.getFragment(AppleConfiguration.class).getBundlingPlatform())
+ .setProgressMessage("Copying Watchkit support to app bundle")
+ .setShellCommand(ImmutableList.of("/bin/bash", "-c", Joiner.on(" ").join(command)))
+ .addOutput(watchSupportZip)
+ .build(ruleContext));
+
+ objcProviderBuilder.add(ROOT_MERGE_ZIP, watchSupportZip(ruleContext));
+ }
+
+ private static Artifact watchSupportZip(RuleContext ruleContext) {
+ return ruleContext.getRelatedArtifact(
+ ruleContext.getUniqueDirectory("_watch"), "/WatchKitSupport.zip");
+ }
+
+ private static Iterable<XcodeprojBuildSetting> xcodeSettings(RuleContext ruleContext) {
+ ImmutableList.Builder<XcodeprojBuildSetting> xcodeSettings = new ImmutableList.Builder<>();
+ xcodeSettings.add(
+ XcodeprojBuildSetting.newBuilder()
+ .setName("RESOURCES_TARGETED_DEVICE_FAMILY")
+ .setValue(TargetDeviceFamily.WATCH.getNameInRule())
+ .build());
+ xcodeSettings.add(
+ XcodeprojBuildSetting.newBuilder()
+ .setName("IPHONEOS_DEPLOYMENT_TARGET")
+ .setValue(determineMinimumOsVersion(
+ ObjcRuleClasses.objcConfiguration(ruleContext).getMinimumOs()).toString())
+ .build());
+ return xcodeSettings.build();
+ }
+}