Skip to content
Source
Sign inSign up

addWidgetAssetCatalog.cjs

64 lines2.2 KB

1"use strict";
2​
3// xcodebuild ignores Resources phases on expo-widgets targets; compile assets in a shell phase.
4​
5const PHASE_NAME = "Compile Widget Assets";
6​
7const ACTOOL_SCRIPT = [
8 "set -e",
9 'CATALOG="${SRCROOT}/ExpoWidgetsTarget/Assets.xcassets"',
10 'if [ ! -d "$CATALOG" ]; then',
11 ' echo "error: widget asset catalog not found at $CATALOG (expo-widgets wiped it? check plugin ordering in app.config.ts)"',
12 " exit 1",
13 "fi",
14 'DEST="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"',
15 'mkdir -p "$DEST"',
16 'xcrun actool "$CATALOG" --compile "$DEST" --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET:-16.0}" --output-format human-readable-text',
17].join("\n");
18​
19function stripComments(map) {
20 const out = {};
21 for (const key of Object.keys(map || {})) {
22 if (key.endsWith("_comment")) continue;
23 out[key] = map[key];
24 }
25 return out;
27​
28function findByName(map, name) {
29 for (const [uuid, value] of Object.entries(stripComments(map))) {
30 if (value && value.name === name) return { uuid, value };
31 }
32 return null;
34​
35/** @param {import('xcode').XcodeProject} proj
36 * @param {{ targetName: string }} opts */
37function addWidgetAssetCatalog(proj, opts) {
38 const objects = proj.hash.project.objects;
39 const target = findByName(objects.PBXNativeTarget, opts.targetName);
40 if (!target) {
41 throw new Error(
42 `addWidgetAssetCatalog: target "${opts.targetName}" not found — ` +
43 "withWidgetLogoAsset must be registered before expo-widgets so its " +
44 "xcodeproj mod runs after the widget target is created.",
45 );
46 }
47​
48 const phases = target.value.buildPhases || [];
49 const existing = objects.PBXShellScriptBuildPhase || {};
50 const already = Object.entries(stripComments(existing)).some(
51 ([uuid, value]) =>
52 value && value.name === `"${PHASE_NAME}"` && phases.some((p) => p.value === uuid),
53 );
54 if (already) return false;
55​
56 const { uuid } = proj.addBuildPhase([], "PBXShellScriptBuildPhase", PHASE_NAME, target.uuid, {
57 shellPath: "/bin/sh",
58 shellScript: ACTOOL_SCRIPT,
59 });
60 objects.PBXShellScriptBuildPhase[uuid].alwaysOutOfDate = 1;
61 return true;
63​
64module.exports = { addWidgetAssetCatalog };