@bacons/apple-targets 0.0.9 → 0.1.0

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
@@ -9,11 +9,13 @@ An experimental Expo Config Plugin that generates native Apple Targets like Widg
9
9
 
10
10
  ## 🚀 How to use
11
11
 
12
+ > This plugin requires at least CocoaPods 1.16.2 and Xcode 16.
13
+
12
14
  - Add targets to `targets/` directory with an `expo-target.config.json` file.
13
15
  - Currently, if you don't have an `Info.plist`, it'll be generated on `npx expo prebuild`. This may be changed in the future so if you have an `Info.plist` it'll be used, otherwise, it'll be generated.
14
16
  - Any files in a top-level `target/*/assets` directory will be linked as resources of the target. This was added to support Safari Extensions.
15
17
  - A single top-level `*.entitlements` file will be linked as the entitlements of the target. This is not currently used in EAS Capability signing, but may be in the future.
16
- - All top-level swift files will be linked as build sources of the target. There is currently no support for storyboard or `.xib` files because I can't be bothered.
18
+ - All Swift files will be linked as build sources of the target. There is currently no support for storyboard or `.xib` files because I can't be bothered.
17
19
  - All top-level `*.xcassets` will be linked as resources, and accessible in the targets. If you add files outside of Xcode, you'll need to re-run `npx expo prebuild` to link them.
18
20
  - In Expo SDK +52, set the `ios.appleTeamId`, for SDK 51 and below, set the `appleTeamId` prop in the Config Plugin in `app.config.js`:
19
21
 
@@ -97,14 +99,32 @@ There are certain values that are shared across targets. We use a predefined con
97
99
 
98
100
  Adding a file `pods.rb` in the root of the repo will enable you to modify the target settings for the project.
99
101
 
100
- The ruby module evaluates with global access to the property `podfile_properties` and the method `use_native_modules`.
102
+ The ruby module evaluates with global access to the property `podfile_properties`.
101
103
 
102
104
  For example, the following is useful for enabling React Native in an App Clip target:
103
105
 
104
106
  ```rb
107
+ require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods")
108
+
105
109
  exclude = []
106
110
  use_expo_modules!(exclude: exclude)
107
- config = use_native_modules!
111
+
112
+ if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
113
+ config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
114
+ else
115
+ config_command = [
116
+ 'node',
117
+ '--no-warnings',
118
+ '--eval',
119
+ 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
120
+ 'react-native-config',
121
+ '--json',
122
+ '--platform',
123
+ 'ios'
124
+ ]
125
+ end
126
+
127
+ config = use_native_modules!(config_command)
108
128
 
109
129
  use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
110
130
  use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
package/build/index.d.ts CHANGED
@@ -4,5 +4,5 @@ export declare const withTargetsDir: ConfigPlugin<{
4
4
  appleTeamId?: string;
5
5
  match?: string;
6
6
  root?: string;
7
- }>;
7
+ } | void>;
8
8
  export { Config };
package/build/index.js CHANGED
@@ -9,11 +9,12 @@ const path_1 = __importDefault(require("path"));
9
9
  const withPodTargetExtension_1 = require("./withPodTargetExtension");
10
10
  const withWidget_1 = __importDefault(require("./withWidget"));
11
11
  const withXcparse_1 = require("./withXcparse");
12
- const withTargetsDir = (config, _a) => {
13
- var _b;
14
- var {
15
- // @ts-expect-error: not on type yet
16
- appleTeamId = (_b = config.ios) === null || _b === void 0 ? void 0 : _b.appleTeamId, root = "./targets", match = "*", } = _a;
12
+ const withTargetsDir = (config, _props) => {
13
+ var _a;
14
+ const { appleTeamId = (_a = config === null || config === void 0 ? void 0 : config.ios) === null || _a === void 0 ? void 0 : _a.appleTeamId, root = "./targets", match = "*", } = _props || {};
15
+ if (!appleTeamId) {
16
+ throw new Error(`You must specify an \`appleTeamId\` in your app config to use the \`withTargetsDir\` plugin.`);
17
+ }
17
18
  const projectRoot = config._internal.projectRoot;
18
19
  const targets = (0, glob_1.sync)(`${root}/${match}/expo-target.config.@(json|js)`, {
19
20
  // const targets = globSync(`./targets/action/expo-target.config.@(json|js)`, {
@@ -25,6 +26,7 @@ const withTargetsDir = (config, _a) => {
25
26
  appleTeamId,
26
27
  ...require(configPath),
27
28
  directory: path_1.default.relative(projectRoot, path_1.default.dirname(configPath)),
29
+ configPath,
28
30
  });
29
31
  });
30
32
  (0, withPodTargetExtension_1.withPodTargetExtension)(config);
@@ -12,7 +12,9 @@ function safeSet(obj, key, value) {
12
12
  }
13
13
  obj = obj[segment];
14
14
  });
15
- obj[last] = value;
15
+ if (!obj[last]) {
16
+ obj[last] = value;
17
+ }
16
18
  return obj;
17
19
  }
18
20
  const withEASTargets = (config, { bundleIdentifier, targetName, entitlements }) => {
@@ -10,7 +10,6 @@ Dir.glob(File.join(__dir__, '..', 'targets', '**', 'pods.rb')).each do |target_f
10
10
  # Create a new binding with access to necessary methods and variables
11
11
  target_binding = binding
12
12
  target_binding.local_variable_set(:podfile_properties, podfile_properties)
13
- target_binding.local_variable_set(:config, use_native_modules!)
14
13
 
15
14
  # Evaluate the target file content in the new binding
16
15
  eval(File.read(target_file), target_binding, target_file)
@@ -2,6 +2,7 @@ import { ConfigPlugin } from "@expo/config-plugins";
2
2
  import { Config } from "./config";
3
3
  type Props = Config & {
4
4
  directory: string;
5
+ configPath: string;
5
6
  };
6
7
  declare const withWidget: ConfigPlugin<Props>;
7
8
  export default withWidget;
@@ -113,6 +113,7 @@ const withWidget = (config, props) => {
113
113
  const targetName = (_c = props.name) !== null && _c !== void 0 ? _c : widget;
114
114
  const bundleId = config.ios.bundleIdentifier + "." + widget;
115
115
  (0, withXcodeChanges_1.withXcodeChanges)(config, {
116
+ configPath: props.configPath,
116
117
  name: targetName,
117
118
  cwd: "../" +
118
119
  path_1.default.relative(config._internal.projectRoot, path_1.default.resolve(props.directory)),
@@ -14,5 +14,7 @@ export type XcodeSettings = {
14
14
  teamId?: string;
15
15
  icon?: string;
16
16
  exportJs?: boolean;
17
+ /** File path to the extension config file. */
18
+ configPath: string;
17
19
  };
18
20
  export declare const withXcodeChanges: ConfigPlugin<XcodeSettings>;
@@ -39,14 +39,19 @@ function createNotificationContentConfigurationList(project, { name, cwd, bundle
39
39
  INFOPLIST_KEY_CFBundleDisplayName: name,
40
40
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
41
41
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
42
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
42
+ LD_RUNPATH_SEARCH_PATHS: [
43
+ "$(inherited)",
44
+ "@executable_path/Frameworks",
45
+ "@executable_path/../../Frameworks",
46
+ ],
43
47
  MARKETING_VERSION: "1.0",
44
48
  MTL_FAST_MATH: "YES",
45
49
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
46
50
  PRODUCT_NAME: "$(TARGET_NAME)",
47
51
  SKIP_INSTALL: "YES",
48
52
  SWIFT_EMIT_LOC_STRINGS: "YES",
49
- SWIFT_OPTIMIZATION_LEVEL: "-Owholemodule",
53
+ SWIFT_COMPILATION_MODE: "wholemodule",
54
+ SWIFT_OPTIMIZATION_LEVEL: "-O",
50
55
  SWIFT_VERSION: "5.0",
51
56
  TARGETED_DEVICE_FAMILY: "1,2",
52
57
  };
@@ -126,7 +131,7 @@ function createShareConfigurationList(project, { name, cwd, bundleId, deployment
126
131
  CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: "YES",
127
132
  CLANG_WARN_UNGUARDED_AVAILABILITY: "YES_AGGRESSIVE",
128
133
  CODE_SIGN_STYLE: "Automatic",
129
- DEBUG_INFORMATION_FORMAT: "dwarf",
134
+ DEBUG_INFORMATION_FORMAT: "dwarf", // NOTE
130
135
  GCC_C_LANGUAGE_STANDARD: "gnu11",
131
136
  GENERATE_INFOPLIST_FILE: "YES",
132
137
  CURRENT_PROJECT_VERSION: currentProjectVersion,
@@ -134,7 +139,11 @@ function createShareConfigurationList(project, { name, cwd, bundleId, deployment
134
139
  INFOPLIST_KEY_CFBundleDisplayName: name,
135
140
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
136
141
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
137
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
142
+ LD_RUNPATH_SEARCH_PATHS: [
143
+ "$(inherited)",
144
+ "@executable_path/Frameworks",
145
+ "@executable_path/../../Frameworks",
146
+ ],
138
147
  MARKETING_VERSION: "1.0",
139
148
  MTL_FAST_MATH: "YES",
140
149
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
@@ -193,7 +202,7 @@ function createIMessageConfigurationList(project, { name, cwd, bundleId, deploym
193
202
  CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER: "YES",
194
203
  CLANG_WARN_UNGUARDED_AVAILABILITY: "YES_AGGRESSIVE",
195
204
  CODE_SIGN_STYLE: "Automatic",
196
- DEBUG_INFORMATION_FORMAT: "dwarf",
205
+ DEBUG_INFORMATION_FORMAT: "dwarf", // NOTE
197
206
  GCC_C_LANGUAGE_STANDARD: "gnu11",
198
207
  GENERATE_INFOPLIST_FILE: "YES",
199
208
  CURRENT_PROJECT_VERSION: currentProjectVersion,
@@ -201,7 +210,11 @@ function createIMessageConfigurationList(project, { name, cwd, bundleId, deploym
201
210
  INFOPLIST_KEY_CFBundleDisplayName: name,
202
211
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
203
212
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
204
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
213
+ LD_RUNPATH_SEARCH_PATHS: [
214
+ "$(inherited)",
215
+ "@executable_path/Frameworks",
216
+ "@executable_path/../../Frameworks",
217
+ ],
205
218
  MARKETING_VERSION: "1.0",
206
219
  MTL_FAST_MATH: "YES",
207
220
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
@@ -259,7 +272,7 @@ function createWatchAppConfigurationList(project, { name, cwd, bundleId, deploym
259
272
  INFOPLIST_KEY_WKCompanionAppBundleIdentifier: mainAppTarget.props.buildSettings.PRODUCT_BUNDLE_IDENTIFIER,
260
273
  // INFOPLIST_KEY_WKCompanionAppBundleIdentifier: "$(BUNDLE_IDENTIFIER)",
261
274
  // INFOPLIST_KEY_WKCompanionAppBundleIdentifier: rootBundleId,
262
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks",
275
+ LD_RUNPATH_SEARCH_PATHS: ["$(inherited)", "@executable_path/Frameworks"],
263
276
  MARKETING_VERSION: "1.0",
264
277
  MTL_FAST_MATH: "YES",
265
278
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
@@ -291,7 +304,8 @@ function createWatchAppConfigurationList(project, { name, cwd, bundleId, deploym
291
304
  buildSettings: {
292
305
  ...common,
293
306
  // Diff
294
- SWIFT_OPTIMIZATION_LEVEL: "-Owholemodule",
307
+ SWIFT_COMPILATION_MODE: "wholemodule",
308
+ SWIFT_OPTIMIZATION_LEVEL: "-O",
295
309
  COPY_PHASE_STRIP: "NO",
296
310
  DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym",
297
311
  },
@@ -320,7 +334,11 @@ function createSafariConfigurationList(project, { name, cwd, bundleId, deploymen
320
334
  INFOPLIST_KEY_CFBundleDisplayName: name,
321
335
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
322
336
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
323
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
337
+ LD_RUNPATH_SEARCH_PATHS: [
338
+ "$(inherited)",
339
+ "@executable_path/Frameworks",
340
+ "@executable_path/../../Frameworks",
341
+ ],
324
342
  MARKETING_VERSION: "1.0",
325
343
  MTL_FAST_MATH: "YES",
326
344
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
@@ -347,7 +365,8 @@ function createSafariConfigurationList(project, { name, cwd, bundleId, deploymen
347
365
  buildSettings: {
348
366
  ...common,
349
367
  // Diff
350
- SWIFT_OPTIMIZATION_LEVEL: "-Owholemodule",
368
+ SWIFT_COMPILATION_MODE: "wholemodule",
369
+ SWIFT_OPTIMIZATION_LEVEL: "-O",
351
370
  COPY_PHASE_STRIP: "NO",
352
371
  DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym",
353
372
  },
@@ -403,7 +422,7 @@ function createAppClipConfigurationList(project, { name, cwd, bundleId, deployme
403
422
  ...infoPlist,
404
423
  ...superCommon,
405
424
  ASSETCATALOG_COMPILER_APPICON_NAME: "AppIcon",
406
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks",
425
+ LD_RUNPATH_SEARCH_PATHS: ["$(inherited)", "@executable_path/Frameworks"],
407
426
  MTL_FAST_MATH: "YES",
408
427
  ENABLE_PREVIEWS: "YES",
409
428
  };
@@ -423,7 +442,8 @@ function createAppClipConfigurationList(project, { name, cwd, bundleId, deployme
423
442
  buildSettings: {
424
443
  ...common,
425
444
  // Diff
426
- SWIFT_OPTIMIZATION_LEVEL: "-Owholemodule",
445
+ SWIFT_COMPILATION_MODE: "wholemodule",
446
+ SWIFT_OPTIMIZATION_LEVEL: "-O",
427
447
  COPY_PHASE_STRIP: "NO",
428
448
  DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym",
429
449
  },
@@ -457,7 +477,11 @@ function createConfigurationList(project, { name, cwd, bundleId, deploymentTarge
457
477
  INFOPLIST_KEY_CFBundleDisplayName: name,
458
478
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
459
479
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
460
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
480
+ LD_RUNPATH_SEARCH_PATHS: [
481
+ "$(inherited)",
482
+ "@executable_path/Frameworks",
483
+ "@executable_path/../../Frameworks",
484
+ ],
461
485
  MARKETING_VERSION: "1.0",
462
486
  MTL_ENABLE_DEBUG_INFO: "INCLUDE_SOURCE",
463
487
  MTL_FAST_MATH: "YES",
@@ -493,14 +517,19 @@ function createConfigurationList(project, { name, cwd, bundleId, deploymentTarge
493
517
  INFOPLIST_KEY_CFBundleDisplayName: name,
494
518
  INFOPLIST_KEY_NSHumanReadableCopyright: "",
495
519
  IPHONEOS_DEPLOYMENT_TARGET: deploymentTarget,
496
- LD_RUNPATH_SEARCH_PATHS: "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks",
520
+ LD_RUNPATH_SEARCH_PATHS: [
521
+ "$(inherited)",
522
+ "@executable_path/Frameworks",
523
+ "@executable_path/../../Frameworks",
524
+ ],
497
525
  MARKETING_VERSION: "1.0",
498
526
  MTL_FAST_MATH: "YES",
499
527
  PRODUCT_BUNDLE_IDENTIFIER: bundleId,
500
528
  PRODUCT_NAME: "$(TARGET_NAME)",
501
529
  SKIP_INSTALL: "YES",
502
530
  SWIFT_EMIT_LOC_STRINGS: "YES",
503
- SWIFT_OPTIMIZATION_LEVEL: "-Owholemodule",
531
+ SWIFT_COMPILATION_MODE: "wholemodule",
532
+ SWIFT_OPTIMIZATION_LEVEL: "-O",
504
533
  SWIFT_VERSION: "5",
505
534
  TARGETED_DEVICE_FAMILY: "1,2",
506
535
  },
@@ -539,37 +568,6 @@ function createConfigurationListForType(project, props) {
539
568
  return createNotificationContentConfigurationList(project, props);
540
569
  }
541
570
  }
542
- /** It's common for all frameworks to exist in the top-level "Frameworks" folder that shows in Xcode. */
543
- function addFrameworksToDisplayFolder(project, frameworks) {
544
- var _a;
545
- const mainFrameworksGroup = (_a = project.rootObject.props.mainGroup
546
- .getChildGroups()
547
- .find((group) => group.getDisplayName() === "Frameworks")) !== null && _a !== void 0 ? _a :
548
- // If this happens, there's a big problem. But just in case...
549
- project.rootObject.props.mainGroup.createGroup({
550
- name: "Frameworks",
551
- sourceTree: "<group>",
552
- });
553
- frameworks.forEach((file) => {
554
- if (!mainFrameworksGroup.props.children.find((child) => child.uuid === file.uuid)) {
555
- mainFrameworksGroup.props.children.push(file);
556
- }
557
- });
558
- }
559
- function getFramework(project, name) {
560
- const frameworkName = name + ".framework";
561
- for (const [, entry] of project.entries()) {
562
- if (xcode_1.PBXFileReference.is(entry) &&
563
- entry.props.lastKnownFileType === "wrapper.framework" &&
564
- entry.props.sourceTree === "SDKROOT" &&
565
- entry.props.name === frameworkName) {
566
- return entry;
567
- }
568
- }
569
- return xcode_1.PBXFileReference.create(project, {
570
- path: "System/Library/Frameworks/" + frameworkName,
571
- });
572
- }
573
571
  async function applyXcodeChanges(config, project, props) {
574
572
  var _a, _b;
575
573
  const mainAppTarget = (0, target_1.getMainAppTarget)(project);
@@ -591,18 +589,6 @@ async function applyXcodeChanges(config, project, props) {
591
589
  console.log(`Target "${targetToUpdate.props.productName}" already exists, updating instead of creating a new one`);
592
590
  }
593
591
  const magicCwd = path_1.default.join(config._internal.projectRoot, "ios", props.cwd);
594
- function getOrCreateBuildFile(file) {
595
- for (const entry of file.getReferrers()) {
596
- if (xcode_1.PBXBuildFile.is(entry) && entry.props.fileRef.uuid === file.uuid) {
597
- return entry;
598
- }
599
- }
600
- return xcode_1.PBXBuildFile.create(project, {
601
- fileRef: file,
602
- });
603
- }
604
- // Add the widget target to the display folder (cosmetic)
605
- addFrameworksToDisplayFolder(project, props.frameworks.map((framework) => getFramework(project, framework)));
606
592
  const developmentTeamId = (_b = props.teamId) !== null && _b !== void 0 ? _b : mainAppTarget.getDefaultBuildSetting("DEVELOPMENT_TEAM");
607
593
  if (!developmentTeamId) {
608
594
  throw new Error("Couldn't find DEVELOPMENT_TEAM in Xcode project and none were provided in the Expo config.");
@@ -645,19 +631,11 @@ async function applyXcodeChanges(config, project, props) {
645
631
  }
646
632
  function configureTargetWithEntitlements(target) {
647
633
  const entitlements = (0, glob_1.sync)("*.entitlements", {
648
- absolute: true,
634
+ absolute: false,
649
635
  cwd: magicCwd,
650
- }).map((file) => {
651
- return xcode_1.PBXBuildFile.create(project, {
652
- fileRef: xcode_1.PBXFileReference.create(project, {
653
- path: path_1.default.basename(file),
654
- explicitFileType: "text.plist.entitlements",
655
- sourceTree: "<group>",
656
- }),
657
- });
658
636
  });
659
637
  if (entitlements.length > 0) {
660
- target.setBuildSetting("CODE_SIGN_ENTITLEMENTS", props.cwd + "/" + entitlements[0].props.fileRef.props.path);
638
+ target.setBuildSetting("CODE_SIGN_ENTITLEMENTS", props.cwd + "/" + entitlements[0]);
661
639
  }
662
640
  else {
663
641
  target.removeBuildSetting("CODE_SIGN_ENTITLEMENTS");
@@ -667,7 +645,6 @@ async function applyXcodeChanges(config, project, props) {
667
645
  }
668
646
  function syncMarketingVersions() {
669
647
  const mainVersion = getMainMarketingVersion(project);
670
- // console.log('main marketing version:', mainVersion)
671
648
  project.rootObject.props.targets.forEach((target) => {
672
649
  if (xcode_1.PBXNativeTarget.is(target)) {
673
650
  target.setBuildSetting("MARKETING_VERSION", mainVersion);
@@ -692,7 +669,9 @@ async function applyXcodeChanges(config, project, props) {
692
669
  const shellScript = mainAppTarget.props.buildPhases.find((phase) => xcode_1.PBXShellScriptBuildPhase.is(phase) &&
693
670
  phase.props.name === "Bundle React Native code and images");
694
671
  if (!shellScript) {
695
- throw new Error('Failed to find the "Bundle React Native code and images" build phase in the main app target.');
672
+ console.warn('Failed to find the "Bundle React Native code and images" build phase in the main app target. Will not be able to configure: ' +
673
+ props.type);
674
+ return;
696
675
  }
697
676
  const currentShellScript = target.props.buildPhases.find((phase) => xcode_1.PBXShellScriptBuildPhase.is(phase) &&
698
677
  phase.props.name === "Bundle React Native code and images");
@@ -743,118 +722,7 @@ async function applyXcodeChanges(config, project, props) {
743
722
  syncMarketingVersions();
744
723
  return project;
745
724
  }
746
- // Build Files
747
- // NOTE: Single-level only
748
- const swiftFiles = (0, glob_1.sync)("*.swift", {
749
- absolute: true,
750
- cwd: magicCwd,
751
- }).map((file) => {
752
- return xcode_1.PBXBuildFile.create(project, {
753
- fileRef: xcode_1.PBXFileReference.create(project, {
754
- path: path_1.default.basename(file),
755
- sourceTree: "<group>",
756
- }),
757
- });
758
- });
759
- // NOTE: Single-level only
760
- const intentFiles = (0, glob_1.sync)("*.intentdefinition", {
761
- absolute: true,
762
- cwd: magicCwd,
763
- }).map((file) => {
764
- return xcode_1.PBXFileReference.create(project, {
765
- lastKnownFileType: "file.intentdefinition",
766
- path: path_1.default.basename(file),
767
- sourceTree: "<group>",
768
- });
769
- });
770
- const intentBuildFiles = [0, 1].map((_) => intentFiles.map((file) => {
771
- return xcode_1.PBXBuildFile.create(project, {
772
- fileRef: file,
773
- });
774
- }));
775
- let assetFiles = [
776
- // All assets`
777
- // "assets/*",
778
- // NOTE: Single-level only
779
- "*.xcassets",
780
- ]
781
- .map((glob) => (0, glob_1.sync)(glob, {
782
- absolute: true,
783
- cwd: magicCwd,
784
- }).map((file) => {
785
- return xcode_1.PBXBuildFile.create(project, {
786
- fileRef: xcode_1.PBXFileReference.create(project, {
787
- path: path_1.default.basename(file),
788
- sourceTree: "<group>",
789
- }),
790
- });
791
- }))
792
- .flat();
793
- const resAssets = [];
794
- // Support for LaunchScreen files
795
- const baseProj = path_1.default.join(magicCwd, "Base.lproj");
796
- if (fs_1.default.existsSync(baseProj)) {
797
- // Link LaunchScreen.storyboard
798
- fs_1.default.readdirSync(baseProj).forEach((file) => {
799
- if (file === ".DS_Store")
800
- return;
801
- const stat = fs_1.default.statSync(path_1.default.join(baseProj, file));
802
- if (stat.isFile()) {
803
- if (file.endsWith(".storyboard")) {
804
- assetFiles.push(xcode_1.PBXBuildFile.create(project, {
805
- fileRef: xcode_1.PBXVariantGroup.create(project, {
806
- name: file,
807
- sourceTree: "<group>",
808
- children: [
809
- xcode_1.PBXFileReference.create(project, {
810
- lastKnownFileType: "file.storyboard",
811
- name: "Base",
812
- path: path_1.default.join("Base.lproj", file),
813
- sourceTree: "<group>",
814
- }),
815
- ],
816
- }),
817
- }));
818
- }
819
- }
820
- });
821
- }
822
- // TODO: Maybe just limit this to Safari?
823
- if (fs_1.default.existsSync(path_1.default.join(magicCwd, "assets"))) {
824
- // get top-level directories in `assets/` and append them to assetFiles as folder types
825
- fs_1.default.readdirSync(path_1.default.join(magicCwd, "assets")).forEach((file) => {
826
- if (file === ".DS_Store")
827
- return;
828
- const stat = fs_1.default.statSync(path_1.default.join(magicCwd, "assets", file));
829
- if (stat.isDirectory()) {
830
- resAssets.push(xcode_1.PBXBuildFile.create(project, {
831
- fileRef: xcode_1.PBXFileReference.create(project, {
832
- path: file,
833
- sourceTree: "<group>",
834
- lastKnownFileType: "folder",
835
- }),
836
- }));
837
- }
838
- else if (stat.isFile()) {
839
- resAssets.push(xcode_1.PBXBuildFile.create(project, {
840
- fileRef: xcode_1.PBXFileReference.create(project, {
841
- path: file,
842
- explicitFileType: file.endsWith(".js")
843
- ? "sourcecode.javascript"
844
- : file.endsWith(".json")
845
- ? "text.json"
846
- : file.endsWith(".html")
847
- ? "text.html"
848
- : file.endsWith(".css")
849
- ? "text.css"
850
- : "text",
851
- sourceTree: "<group>",
852
- }),
853
- }));
854
- }
855
- });
856
- }
857
- const alphaExtensionAppexBf = xcode_1.PBXBuildFile.create(project, {
725
+ const appExtensionBuildFile = xcode_1.PBXBuildFile.create(project, {
858
726
  fileRef: xcode_1.PBXFileReference.create(project, {
859
727
  explicitFileType: "wrapper.app-extension",
860
728
  includeInIndex: 0,
@@ -867,45 +735,30 @@ async function applyXcodeChanges(config, project, props) {
867
735
  });
868
736
  project.rootObject.ensureProductGroup().props.children.push(
869
737
  // @ts-expect-error
870
- alphaExtensionAppexBf.props.fileRef);
871
- const widgetTarget = project.rootObject.createNativeTarget({
738
+ appExtensionBuildFile.props.fileRef);
739
+ const extensionTarget = project.rootObject.createNativeTarget({
872
740
  buildConfigurationList: createConfigurationListForType(project, props),
873
741
  name: productName,
874
742
  productName,
875
743
  // @ts-expect-error
876
- productReference: alphaExtensionAppexBf.props.fileRef /* alphaExtension.appex */,
744
+ productReference: appExtensionBuildFile.props.fileRef /* alphaExtension.appex */,
877
745
  productType: (0, target_1.productTypeForType)(props.type),
878
746
  });
879
- configureTargetWithKnownSettings(widgetTarget);
880
- const entitlementFiles = configureTargetWithEntitlements(widgetTarget);
881
- configureTargetWithPreview(widgetTarget);
882
- // CD0706062A2EBE2E009C1192
883
- widgetTarget.createBuildPhase(xcode_1.PBXSourcesBuildPhase, {
884
- files: [
885
- ...swiftFiles,
886
- ...intentBuildFiles[0],
887
- // ...entitlementFiles
888
- ],
889
- // CD0706152A2EBE2E009C1192 /* index.swift in Sources */,
890
- // CD07061A2A2EBE2F009C1192 /* alpha.intentdefinition in Sources */,
891
- // CD0706112A2EBE2E009C1192 /* alphaBundle.swift in Sources */,
892
- // CD0706132A2EBE2E009C1192 /* alphaLiveActivity.swift in Sources */,
893
- });
894
- widgetTarget.createBuildPhase(xcode_1.PBXFrameworksBuildPhase, {
895
- files: props.frameworks.map((framework) => getOrCreateBuildFile(getFramework(project, framework))),
896
- });
897
- widgetTarget.createBuildPhase(xcode_1.PBXResourcesBuildPhase, {
898
- files: [...assetFiles, ...resAssets],
899
- });
900
- configureJsExport(widgetTarget);
747
+ configureTargetWithKnownSettings(extensionTarget);
748
+ configureTargetWithEntitlements(extensionTarget);
749
+ configureTargetWithPreview(extensionTarget);
750
+ extensionTarget.ensureFrameworks(props.frameworks);
751
+ extensionTarget.getSourcesBuildPhase();
752
+ extensionTarget.getResourcesBuildPhase();
753
+ configureJsExport(extensionTarget);
901
754
  const containerItemProxy = xcode_1.PBXContainerItemProxy.create(project, {
902
755
  containerPortal: project.rootObject,
903
756
  proxyType: 1,
904
- remoteGlobalIDString: widgetTarget.uuid,
757
+ remoteGlobalIDString: extensionTarget.uuid,
905
758
  remoteInfo: productName,
906
759
  });
907
760
  const targetDependency = xcode_1.PBXTargetDependency.create(project, {
908
- target: widgetTarget,
761
+ target: extensionTarget,
909
762
  targetProxy: containerItemProxy,
910
763
  });
911
764
  // Add the target dependency to the main app, should be only one.
@@ -924,112 +777,63 @@ async function applyXcodeChanges(config, project, props) {
924
777
  });
925
778
  if (copyFilesBuildPhase) {
926
779
  // Assume that this is the first run if there is no matching target that we identified from a previous run.
927
- copyFilesBuildPhase.props.files.push(alphaExtensionAppexBf);
780
+ copyFilesBuildPhase.props.files.push(appExtensionBuildFile);
928
781
  }
929
782
  else {
930
- const dstPath = { clip: "AppClips", watch: "Watch" }[props.type];
931
- if (dstPath) {
932
- mainAppTarget.createBuildPhase(xcode_1.PBXCopyFilesBuildPhase, {
933
- dstPath: "$(CONTENTS_FOLDER_PATH)/" + dstPath,
934
- dstSubfolderSpec: 16,
935
- buildActionMask: 2147483647,
936
- files: [alphaExtensionAppexBf],
937
- name: WELL_KNOWN_COPY_EXTENSIONS_NAME,
938
- runOnlyForDeploymentPostprocessing: 0,
939
- });
940
- }
941
- else {
942
- mainAppTarget.createBuildPhase(xcode_1.PBXCopyFilesBuildPhase, {
943
- dstSubfolderSpec: 13,
944
- buildActionMask: 2147483647,
945
- files: [alphaExtensionAppexBf],
946
- name: WELL_KNOWN_COPY_EXTENSIONS_NAME,
947
- runOnlyForDeploymentPostprocessing: 0,
948
- });
949
- }
783
+ mainAppTarget.createBuildPhase(xcode_1.PBXCopyFilesBuildPhase, {
784
+ files: [appExtensionBuildFile],
785
+ });
950
786
  }
951
- const mainSourcesBuildPhase = mainAppTarget.getBuildPhase(xcode_1.PBXSourcesBuildPhase);
952
- // TODO: Idempotent
953
- mainSourcesBuildPhase === null || mainSourcesBuildPhase === void 0 ? void 0 : mainSourcesBuildPhase.props.files.push(...intentBuildFiles[1]);
954
- const protectedGroup = ensureProtectedGroup(project).createGroup({
955
- // This is where it gets fancy
956
- // TODO: The user should be able to know that this is safe to modify and won't be overwritten.
957
- name: path_1.default.basename(props.cwd),
958
- // Like `../alpha`
959
- path: props.cwd,
960
- sourceTree: "<group>",
961
- children: [
962
- // @ts-expect-error
963
- ...swiftFiles
964
- .map((buildFile) => buildFile.props.fileRef)
965
- .sort((a, b) => a.getDisplayName().localeCompare(b.getDisplayName())),
966
- // @ts-expect-error
967
- ...intentFiles.sort((a, b) => a.getDisplayName().localeCompare(b.getDisplayName())),
968
- // @ts-expect-error
969
- ...assetFiles
970
- .map((buildFile) => buildFile.props.fileRef)
971
- .sort((a, b) => a.getDisplayName().localeCompare(b.getDisplayName())),
972
- // @ts-expect-error
973
- ...entitlementFiles
974
- .map((buildFile) => buildFile.props.fileRef)
975
- .sort((a, b) => a.getDisplayName().localeCompare(b.getDisplayName())),
976
- // CD0706192A2EBE2F009C1192 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
977
- // @ts-expect-error
978
- xcode_1.PBXFileReference.create(project, {
979
- path: "Info.plist",
980
- sourceTree: "<group>",
981
- }),
787
+ const syncException = xcode_1.PBXFileSystemSynchronizedBuildFileExceptionSet.create(project, {
788
+ target: extensionTarget,
789
+ membershipExceptions: [
790
+ // TODO: What other files belong here, why is this here?
791
+ "Info.plist",
792
+ // Exclude the config path
793
+ path_1.default.relative(magicCwd, props.configPath),
982
794
  ],
983
- // children = (
984
- // CD0706102A2EBE2E009C1192 /* alphaBundle.swift */,
985
- // CD0706122A2EBE2E009C1192 /* alphaLiveActivity.swift */,
986
- // CD0706142A2EBE2E009C1192 /* index.swift */,
987
- // CD0706162A2EBE2E009C1192 /* alpha.intentdefinition */,
988
- // CD0706172A2EBE2F009C1192 /* Assets.xcassets */,
989
- // CD0706192A2EBE2F009C1192 /* Info.plist */,
990
- // );
991
- // name = "expo:alpha";
992
- // path = "../alpha";
993
- // sourceTree = "<group>";
994
795
  });
995
- if (resAssets.length > 0) {
996
- protectedGroup.createGroup({
997
- name: "assets",
998
- path: "assets",
999
- sourceTree: "<group>",
1000
- // @ts-expect-error
1001
- children: resAssets
1002
- .map((buildFile) => buildFile.props.fileRef)
1003
- .sort((a, b) => a.getDisplayName().localeCompare(b.getDisplayName())),
1004
- });
796
+ const assetsDir = path_1.default.join(magicCwd, "assets");
797
+ // TODO: Maybe just limit this to Safari extensions?
798
+ const explicitFolders = !fs_1.default.existsSync(assetsDir)
799
+ ? []
800
+ : fs_1.default
801
+ .readdirSync(assetsDir)
802
+ .filter((file) => file !== ".DS_Store" &&
803
+ fs_1.default.statSync(path_1.default.join(assetsDir, file)).isDirectory())
804
+ .map((file) => path_1.default.join("assets", file));
805
+ const syncRootGroup = xcode_1.PBXFileSystemSynchronizedRootGroup.create(project, {
806
+ path: path_1.default.basename(props.cwd),
807
+ exceptions: [syncException],
808
+ explicitFileTypes: {},
809
+ explicitFolders: [
810
+ // Replaces the previous `lastKnownFileType: "folder",` system that's used in things like Safari extensions to include folders of assets.
811
+ // ex: `"Resources/_locales", "Resources/images"`
812
+ ...explicitFolders,
813
+ ],
814
+ sourceTree: "<group>",
815
+ });
816
+ if (!extensionTarget.props.fileSystemSynchronizedGroups) {
817
+ extensionTarget.props.fileSystemSynchronizedGroups = [];
1005
818
  }
819
+ extensionTarget.props.fileSystemSynchronizedGroups.push(syncRootGroup);
820
+ ensureProtectedGroup(project, path_1.default.dirname(props.cwd)).props.children.push(syncRootGroup);
1006
821
  applyDevelopmentTeamIdToTargets();
1007
822
  syncMarketingVersions();
1008
823
  return project;
1009
824
  }
1010
825
  const PROTECTED_GROUP_NAME = "expo:targets";
1011
- function ensureProtectedGroup(project) {
826
+ function ensureProtectedGroup(project, relativePath = "../targets") {
1012
827
  const hasProtectedGroup = project.rootObject.props.mainGroup
1013
828
  .getChildGroups()
1014
829
  .find((group) => group.getDisplayName() === PROTECTED_GROUP_NAME);
1015
830
  const protectedGroup = hasProtectedGroup !== null && hasProtectedGroup !== void 0 ? hasProtectedGroup : xcode_1.PBXGroup.create(project, {
1016
831
  name: PROTECTED_GROUP_NAME,
832
+ path: relativePath,
1017
833
  sourceTree: "<group>",
1018
834
  });
1019
835
  if (!hasProtectedGroup) {
1020
836
  project.rootObject.props.mainGroup.props.children.unshift(protectedGroup);
1021
- // let libIndex = project.rootObject.props.mainGroup
1022
- // .getChildGroups()
1023
- // .findIndex((group) => group.getDisplayName() === "Libraries");
1024
- // if (libIndex === -1) {
1025
- // libIndex = 0;
1026
- // }
1027
- // add above the group named "Libraries"
1028
- // project.rootObject.props.mainGroup.props.children.splice(
1029
- // libIndex,
1030
- // 0,
1031
- // protectedGroup
1032
- // );
1033
837
  }
1034
838
  return protectedGroup;
1035
839
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bacons/apple-targets",
3
- "version": "0.0.9",
3
+ "version": "0.1.0",
4
4
  "description": "Generate Apple Targets with Expo Prebuild",
5
5
  "main": "build/index.js",
6
6
  "files": [
@@ -28,9 +28,9 @@
28
28
  "author": "Evan Bacon",
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
- "@react-native/normalize-colors": "^0.75.4",
31
+ "@react-native/normalize-colors": "^0.76.1",
32
32
  "glob": "^10.2.6",
33
- "@bacons/xcode": "^1.0.0-alpha.13",
33
+ "@bacons/xcode": "^1.0.0-alpha.21",
34
34
  "fs-extra": "^11.2.0"
35
35
  },
36
36
  "devDependencies": {