@bacons/apple-targets 4.0.1 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,6 @@
1
1
  # Apple Targets
2
2
 
3
- > [!WARNING]
4
- > This is an experimental Config Plugin not part of any official Expo workflow. Automated testing of targets is seemingly impossible meaning unexpected regressions can occur between versions.
5
-
6
- An experimental Expo Config Plugin that generates native Apple Targets like Widgets or App Clips, and links them outside the `/ios` directory. You can open Xcode and develop the targets inside the virtual `expo:targets` folder and the changes will be saved outside of the `ios` directory. This pattern enables building things that fall outside of the scope of React Native while still obtaining all the benefits of [Continuous Native Generation](https://docs.expo.dev/workflow/continuous-native-generation/).
3
+ An Expo Config Plugin that generates native Apple Targets like Widgets or App Clips, and links them outside the `/ios` directory. You can open Xcode and develop the targets inside the virtual `expo:targets` folder and the changes will be saved outside of the `ios` directory. This pattern enables building things that fall outside of the scope of React Native while still obtaining all the benefits of [Continuous Native Generation](https://docs.expo.dev/workflow/continuous-native-generation/).
7
4
 
8
5
  <img width="1728" height="963" alt="targets" src="https://github.com/user-attachments/assets/aedaafa0-1ef0-403c-a797-9f4c82cdb9f1" />
9
6
 
package/build/target.js CHANGED
@@ -621,6 +621,13 @@ function getTargetInfoPlistForType(type) {
621
621
  NSExtensionPrincipalClass: "$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension",
622
622
  },
623
623
  };
624
+ case "device-activity-monitor":
625
+ return {
626
+ NSExtension: {
627
+ NSExtensionPointIdentifier,
628
+ NSExtensionPrincipalClass: "$(PRODUCT_MODULE_NAME).DeviceActivityMonitorExtension",
629
+ },
630
+ };
624
631
  case "print-service":
625
632
  return {
626
633
  NSExtension: {
@@ -19,9 +19,8 @@ const util_1 = require("./util");
19
19
  const DEFAULT_DEPLOYMENT_TARGET = "18.0";
20
20
  const DEFAULT_WATCHOS_DEPLOYMENT_TARGET = "11.0";
21
21
  const withWidget = (config, props) => {
22
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
23
- util_1.LOG_QUEUE.add(() => (0, util_1.warnOnce)((0, chalk_1.default) `\nUsing experimental Config Plugin {bold @bacons/apple-targets} that is subject to breaking changes.`));
24
22
  // TODO: Magically based on the top-level folders in the `ios-widgets/` folder
23
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
25
24
  if (props.icon && !/https?:\/\//.test(props.icon)) {
26
25
  props.icon = path_1.default.join(props.directory, props.icon);
27
26
  }
@@ -13,6 +13,16 @@ const with_bacons_xcode_1 = require("./with-bacons-xcode");
13
13
  const assert_1 = __importDefault(require("assert"));
14
14
  const configuration_list_1 = require("./configuration-list");
15
15
  const util_1 = require("./util");
16
+ /**
17
+ * Checks if a target is a watchOS extension by inspecting its build settings.
18
+ * This is more agnostic than checking props.type directly, as it derives
19
+ * the behavior from Xcode project attributes.
20
+ */
21
+ function isWatchOSExtensionTarget(target) {
22
+ const buildSettings = target.getDefaultConfiguration().props.buildSettings;
23
+ return (buildSettings.SDKROOT === "watchos" ||
24
+ "WATCHOS_DEPLOYMENT_TARGET" in buildSettings);
25
+ }
16
26
  const withXcodeChanges = (config, props) => {
17
27
  return (0, with_bacons_xcode_1.withXcodeProjectBeta)(config, async (config) => {
18
28
  await applyXcodeChanges(config, config.modResults, props);
@@ -33,8 +43,8 @@ exports.withXcodeChanges = withXcodeChanges;
33
43
  // return version;
34
44
  // }
35
45
  async function applyXcodeChanges(config, project, props) {
36
- var _a, _b;
37
- var _c;
46
+ var _a, _b, _c;
47
+ var _d;
38
48
  const mainAppTarget = (0, target_1.getMainAppTarget)(project);
39
49
  // Special setting for share extensions.
40
50
  if ((0, target_1.needsEmbeddedSwift)(props.type)) {
@@ -218,9 +228,39 @@ async function applyXcodeChanges(config, project, props) {
218
228
  productReference: appExtensionBuildFile.props.fileRef /* alphaExtension.appex */,
219
229
  productType: productType,
220
230
  });
221
- const copyPhase = mainAppTarget.getCopyBuildPhaseForTarget(targetToUpdate);
222
- if (!copyPhase.getBuildFile(appExtensionBuildFile.props.fileRef)) {
223
- copyPhase.props.files.push(appExtensionBuildFile);
231
+ // For watchOS extensions, embed in the watchOS app target instead of
232
+ // the main iOS app target. getCopyBuildPhaseForTarget() throws when
233
+ // called on non-main targets, so we manually create the
234
+ // "Embed Foundation Extensions" copy phase on the watch target.
235
+ if (isWatchOSExtensionTarget(targetToUpdate)) {
236
+ const watchTarget = project.rootObject.props.targets.find((t) => xcode_1.PBXNativeTarget.is(t) && t.isWatchOSTarget());
237
+ if (watchTarget) {
238
+ const { PBXCopyFilesBuildPhase, } = require("@bacons/xcode/build/api/PBXSourcesBuildPhase");
239
+ const existingPhase = watchTarget.props.buildPhases.find((phase) => PBXCopyFilesBuildPhase.is(phase) &&
240
+ phase.props.name === "Embed Foundation Extensions");
241
+ const embedPhase = existingPhase !== null && existingPhase !== void 0 ? existingPhase : watchTarget.createBuildPhase(PBXCopyFilesBuildPhase, {
242
+ name: "Embed Foundation Extensions",
243
+ dstSubfolderSpec: 13,
244
+ dstPath: "",
245
+ files: [],
246
+ });
247
+ if (!embedPhase.getBuildFile(appExtensionBuildFile.props.fileRef)) {
248
+ embedPhase.props.files.push(appExtensionBuildFile);
249
+ }
250
+ }
251
+ else {
252
+ console.warn("[apple-targets] watchOS extension: could not find watchOS app target, falling back to main app");
253
+ const copyPhase = mainAppTarget.getCopyBuildPhaseForTarget(targetToUpdate);
254
+ if (!copyPhase.getBuildFile(appExtensionBuildFile.props.fileRef)) {
255
+ copyPhase.props.files.push(appExtensionBuildFile);
256
+ }
257
+ }
258
+ }
259
+ else {
260
+ const copyPhase = mainAppTarget.getCopyBuildPhaseForTarget(targetToUpdate);
261
+ if (!copyPhase.getBuildFile(appExtensionBuildFile.props.fileRef)) {
262
+ copyPhase.props.files.push(appExtensionBuildFile);
263
+ }
224
264
  }
225
265
  }
226
266
  configureTargetWithKnownSettings(targetToUpdate);
@@ -230,7 +270,12 @@ async function applyXcodeChanges(config, project, props) {
230
270
  targetToUpdate.getSourcesBuildPhase();
231
271
  targetToUpdate.getResourcesBuildPhase();
232
272
  configureJsExport(targetToUpdate);
233
- mainAppTarget.addDependency(targetToUpdate);
273
+ // For watchOS extensions, the dependency belongs on the watchOS
274
+ // app target so Xcode builds the extension before the watch app.
275
+ const dependencyParent = isWatchOSExtensionTarget(targetToUpdate)
276
+ ? (_b = project.rootObject.props.targets.find((t) => xcode_1.PBXNativeTarget.is(t) && t.isWatchOSTarget())) !== null && _b !== void 0 ? _b : mainAppTarget
277
+ : mainAppTarget;
278
+ dependencyParent.addDependency(targetToUpdate);
234
279
  const assetsDir = path_1.default.join(magicCwd, "assets");
235
280
  // TODO: Maybe just limit this to Safari extensions?
236
281
  const explicitFolders = !fs_1.default.existsSync(assetsDir)
@@ -282,7 +327,7 @@ async function applyXcodeChanges(config, project, props) {
282
327
  }
283
328
  // If there's a `_shared` folder, create a PBXFileSystemSynchronizedBuildFileExceptionSet and set the `target` to the main app target. Then add exceptions to the new target's PBXFileSystemSynchronizedRootGroup's exceptions. Finally, ensure the relative paths for each file in the _shared folder are added to the `membershipExceptions` array.
284
329
  (0, assert_1.default)(syncRootGroup instanceof xcode_1.PBXFileSystemSynchronizedRootGroup);
285
- (_b = (_c = syncRootGroup.props).exceptions) !== null && _b !== void 0 ? _b : (_c.exceptions = []);
330
+ (_c = (_d = syncRootGroup.props).exceptions) !== null && _c !== void 0 ? _c : (_d.exceptions = []);
286
331
  const existingExceptionSet = syncRootGroup.props.exceptions.find((exception) => exception instanceof xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet &&
287
332
  exception.props.target === mainAppTarget);
288
333
  if (sharedAssets.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacons/apple-targets",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "Generate Apple Targets with Expo Prebuild",
5
5
  "main": "build/ExtensionStorage.js",
6
6
  "types": "build/ExtensionStorage.d.ts",
@@ -20,7 +20,7 @@
20
20
  "test": "jest --watch",
21
21
  "test:e2e": "jest --no-watch --config e2e/jest.config.js",
22
22
  "prepare": "expo-module prepare",
23
- "prepublishOnly": "expo-module prepublishOnly",
23
+ "prepublishOnly": "proofread",
24
24
  "expo-module": "expo-module"
25
25
  },
26
26
  "repository": {
@@ -45,17 +45,18 @@
45
45
  "debug": "^4.3.4"
46
46
  },
47
47
  "devDependencies": {
48
- "expo-module-scripts": "^4.1.7",
49
- "@types/debug": "^4.1.7",
50
- "@types/glob": "^8.1.0",
51
48
  "@expo/babel-preset-cli": "^0.3.1",
52
49
  "@expo/config": "^12.0.13",
53
50
  "@expo/config-plugins": "^54.0.4",
54
51
  "@expo/image-utils": "^0.8.8",
52
+ "@expo/npm-proofread": "^1.0.1",
55
53
  "@expo/plist": "^0.4.8",
56
54
  "@expo/prebuild-config": "^54.0.8",
55
+ "@types/debug": "^4.1.7",
56
+ "@types/glob": "^8.1.0",
57
57
  "chalk": "^4.0.0",
58
58
  "expo": "^54.0.32",
59
+ "expo-module-scripts": "^4.1.7",
59
60
  "jest-environment-node": "^26"
60
61
  },
61
62
  "peerDependencies": {