@bacons/apple-targets 3.0.6 → 4.0.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
@@ -1,11 +1,11 @@
1
- # Apple Targets plugin
1
+ # Apple Targets
2
2
 
3
3
  > [!WARNING]
4
- > This is highly experimental and not part of any official Expo workflow.
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
5
 
6
- <img width="1061" alt="Screenshot 2023-06-10 at 1 59 26 PM" src="https://github.com/EvanBacon/expo-apple-targets/assets/9664363/4cd8399d-53aa-401a-9caa-3a1432a0640c">
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/).
7
7
 
8
- 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.
8
+ <img width="1728" height="963" alt="targets" src="https://github.com/user-attachments/assets/aedaafa0-1ef0-403c-a797-9f4c82cdb9f1" />
9
9
 
10
10
  ## 🚀 How to use
11
11
 
@@ -308,10 +308,40 @@ Ideally, this would be generated automatically based on a fully qualified Xcode
308
308
  | network-app-proxy | App Proxy Network Extension |
309
309
  | network-dns-proxy | DNS Proxy Network Extension |
310
310
  | network-filter-data | Filter Data Network Extension |
311
+ | content-blocker | Safari Content Blocker Extension |
312
+ | file-provider | File Provider Extension |
313
+ | broadcast-upload | Broadcast Upload Extension |
314
+ | call-directory | Call Directory Extension |
315
+ | message-filter | Message Filter Extension |
316
+ | file-provider-ui | File Provider UI Extension |
317
+ | broadcast-setup-ui | Broadcast Setup UI Extension |
318
+ | classkit-context | ClassKit Context Provider Extension|
319
+ | unwanted-communication | Unwanted Communication Reporting |
320
+ | photo-editing | Photo Editing Extension |
321
+ | quicklook-preview | Quick Look Preview Extension |
322
+ | spotlight-delegate | CoreSpotlight Delegate Extension |
323
+ | virtual-conference | Virtual Conference Provider |
324
+ | shield-action | Shield Action Extension |
325
+ | shield-config | Shield Configuration Extension |
326
+ | print-service | Print Service Extension |
327
+ | smart-card | Smart Card / Persistent Token |
328
+ | authentication-services | Authentication Services Extension |
311
329
 
312
330
 
313
331
  <!-- | imessage | iMessage Extension | -->
314
332
 
333
+ ### Not yet supported
334
+
335
+ The following extension types exist in Xcode but aren't supported yet. Contributions welcome! See `docs/xcode-target-discovery.md` for details on how these were discovered.
336
+
337
+ | Extension Point Identifier | Xcode Template Name |
338
+ | --- | --- |
339
+ | `com.apple.tv-top-shelf` | TV Top Shelf Extension (tvOS) |
340
+ | `com.apple.FinderSync` | Finder Sync Extension (macOS) |
341
+ | `com.apple.email.extension` | Mail Extension (macOS) |
342
+
343
+ > Run `bun scripts/scan-xcode-targets.ts --diff` to regenerate this list from your local Xcode installation.
344
+
315
345
  ## Code Signing
316
346
 
317
347
  The codesigning is theoretically handled entirely by [EAS Build](https://docs.expo.dev/build/introduction/). This plugin will add the requisite entitlements for target signing to work. I've only tested this end-to-end with my Pillar Valley Widget.
@@ -1,4 +1,4 @@
1
- import { ConfigPlugin } from "@expo/config-plugins";
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
2
  import type { Config, ConfigFunction } from "./config";
3
3
  export declare const withTargetsDir: ConfigPlugin<{
4
4
  appleTeamId?: string;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createConfigurationListForType = void 0;
4
4
  const xcode_1 = require("@bacons/xcode");
5
5
  const target_1 = require("./target");
6
- function createNotificationContentConfigurationList({ name, displayName, cwd, bundleId, deploymentTarget, currentProjectVersion, }) {
6
+ function createDefaultConfigurationList({ name, displayName, cwd, bundleId, deploymentTarget, currentProjectVersion, }) {
7
7
  const common = {
8
8
  CLANG_ANALYZER_NONNULL: "YES",
9
9
  CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: "YES_AGGRESSIVE",
@@ -484,6 +484,8 @@ function createWidgetConfigurationList({ name, displayName, cwd, bundleId, deplo
484
484
  debug: {
485
485
  ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "$accent",
486
486
  ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME: "$widgetBackground",
487
+ // Add app icon name when icon is provided to prevent inheriting main app's icon setting
488
+ ...(icon && { ASSETCATALOG_COMPILER_APPICON_NAME: "AppIcon" }),
487
489
  CLANG_ANALYZER_NONNULL: "YES",
488
490
  CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: "YES_AGGRESSIVE",
489
491
  CLANG_CXX_LANGUAGE_STANDARD: "gnu++20",
@@ -520,6 +522,8 @@ function createWidgetConfigurationList({ name, displayName, cwd, bundleId, deplo
520
522
  release: {
521
523
  ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: "$accent",
522
524
  ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME: "$widgetBackground",
525
+ // Add app icon name when icon is provided to prevent inheriting main app's icon setting
526
+ ...(icon && { ASSETCATALOG_COMPILER_APPICON_NAME: "AppIcon" }),
523
527
  CLANG_ANALYZER_NONNULL: "YES",
524
528
  CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION: "YES_AGGRESSIVE",
525
529
  CLANG_CXX_LANGUAGE_STANDARD: "gnu++20",
@@ -630,7 +634,25 @@ function getConfigurationListBuildSettingsForType(project, props) {
630
634
  case "network-packet-tunnel":
631
635
  case "quicklook-thumbnail":
632
636
  case "spotlight":
633
- return createNotificationContentConfigurationList(props);
637
+ case "content-blocker":
638
+ case "file-provider":
639
+ case "broadcast-upload":
640
+ case "call-directory":
641
+ case "message-filter":
642
+ case "file-provider-ui":
643
+ case "broadcast-setup-ui":
644
+ case "classkit-context":
645
+ case "unwanted-communication":
646
+ case "photo-editing":
647
+ case "quicklook-preview":
648
+ case "spotlight-delegate":
649
+ case "virtual-conference":
650
+ case "shield-action":
651
+ case "shield-config":
652
+ case "print-service":
653
+ case "smart-card":
654
+ case "authentication-services":
655
+ return createDefaultConfigurationList(props);
634
656
  default:
635
657
  const exhaustiveCheck = props.type;
636
658
  throw new Error(`Unhandled case: ${exhaustiveCheck}`);
@@ -1,4 +1,4 @@
1
- import { ConfigPlugin } from "@expo/config-plugins";
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
2
  import { ContentsJsonImageIdiom, ContentsJsonImage } from "@expo/prebuild-config/build/plugins/icons/AssetContents";
3
3
  export declare const withImageAsset: ConfigPlugin<{
4
4
  cwd: string;
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.generateWatchIconsInternalAsync = exports.generateIconsInternalAsync = exports.generateResizedImageAsync = exports.setIconsAsync = exports.ICON_CONTENTS = exports.withImageAsset = void 0;
27
- const config_plugins_1 = require("@expo/config-plugins");
27
+ const config_plugins_1 = require("expo/config-plugins");
28
28
  const image_utils_1 = require("@expo/image-utils");
29
29
  const AssetContents_1 = require("@expo/prebuild-config/build/plugins/icons/AssetContents");
30
30
  const fs = __importStar(require("fs"));
@@ -43,13 +43,18 @@ const withImageAsset = (config, { cwd, name, image }) => {
43
43
  const userDefinedIcon = typeof image === "string"
44
44
  ? { "1x": image, "2x": undefined, "3x": undefined }
45
45
  : image;
46
- // Finally, write the Config.json
47
- await (0, AssetContents_1.writeContentsJsonAsync)((0, path_1.join)(iosNamedProjectRoot, imgPath), {
48
- images: await generateResizedImageAsync(Object.fromEntries(Object.entries(userDefinedIcon).map(([key, value]) => [
49
- key,
50
- (value === null || value === void 0 ? void 0 : value.match(/^[./]/)) ? path_1.default.join(cwd, value) : value,
51
- ])), name, projectRoot, iosNamedProjectRoot, path_1.default.join(cwd, "gen-image", name)),
52
- });
46
+ try {
47
+ // Finally, write the Config.json
48
+ await (0, AssetContents_1.writeContentsJsonAsync)((0, path_1.join)(iosNamedProjectRoot, imgPath), {
49
+ images: await generateResizedImageAsync(Object.fromEntries(Object.entries(userDefinedIcon).map(([key, value]) => [
50
+ key,
51
+ (value === null || value === void 0 ? void 0 : value.match(/^[./]/)) ? path_1.default.join(cwd, value) : value,
52
+ ])), name, projectRoot, iosNamedProjectRoot, path_1.default.join(cwd, "gen-image", name)),
53
+ });
54
+ }
55
+ catch (error) {
56
+ console.warn(`Failed to generate image asset "${name}" for target "${cwd}": ${error.message}. Skipping image generation.`);
57
+ }
53
58
  return config;
54
59
  },
55
60
  ]);
@@ -1,4 +1,4 @@
1
- import { ConfigPlugin } from "@expo/config-plugins";
1
+ import { ConfigPlugin } from "expo/config-plugins";
2
2
  import { ContentsJsonImageIdiom } from "@expo/prebuild-config/build/plugins/icons/AssetContents";
3
3
  import { ExtensionType } from "../target";
4
4
  export declare const withIosIcon: ConfigPlugin<{
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.generateWatchIconsInternalAsync = exports.generateIconsInternalAsync = exports.setIconsAsync = exports.ICON_CONTENTS = exports.withIosIcon = void 0;
27
- const config_plugins_1 = require("@expo/config-plugins");
27
+ const config_plugins_1 = require("expo/config-plugins");
28
28
  const image_utils_1 = require("@expo/image-utils");
29
29
  const AssetContents_1 = require("@expo/prebuild-config/build/plugins/icons/AssetContents");
30
30
  const fs = __importStar(require("fs"));
@@ -36,18 +36,23 @@ const withIosIcon = (config, { cwd, type, iconFilePath, isTransparent = false })
36
36
  async (config) => {
37
37
  const projectRoot = config.modRequest.projectRoot;
38
38
  const namedProjectRoot = (0, path_1.join)(projectRoot, cwd);
39
- if (type === "watch") {
40
- // Ensure the Images.xcassets/AppIcon.appiconset path exists
41
- await fs.promises.mkdir((0, path_1.join)(namedProjectRoot, IMAGESET_PATH), {
42
- recursive: true,
43
- });
44
- // Finally, write the Config.json
45
- await (0, AssetContents_1.writeContentsJsonAsync)((0, path_1.join)(namedProjectRoot, IMAGESET_PATH), {
46
- images: await generateWatchIconsInternalAsync(iconFilePath, projectRoot, namedProjectRoot, cwd, isTransparent),
47
- });
39
+ try {
40
+ if (type === "watch") {
41
+ // Ensure the Images.xcassets/AppIcon.appiconset path exists
42
+ await fs.promises.mkdir((0, path_1.join)(namedProjectRoot, IMAGESET_PATH), {
43
+ recursive: true,
44
+ });
45
+ // Finally, write the Config.json
46
+ await (0, AssetContents_1.writeContentsJsonAsync)((0, path_1.join)(namedProjectRoot, IMAGESET_PATH), {
47
+ images: await generateWatchIconsInternalAsync(iconFilePath, projectRoot, namedProjectRoot, cwd, isTransparent),
48
+ });
49
+ }
50
+ else {
51
+ await setIconsAsync(iconFilePath, projectRoot, (0, path_1.join)(projectRoot, cwd), cwd, isTransparent);
52
+ }
48
53
  }
49
- else {
50
- await setIconsAsync(iconFilePath, projectRoot, (0, path_1.join)(projectRoot, cwd), cwd, isTransparent);
54
+ catch (error) {
55
+ console.warn(`Failed to generate icon for target "${cwd}" using "${iconFilePath}": ${error.message}. Skipping icon generation.`);
51
56
  }
52
57
  return config;
53
58
  },