mirror of
https://github.com/VibedByKaKi/t3-code-android-nightly.git
synced 2026-10-09 20:01:15 +02:00
81 lines
3.1 KiB
JavaScript
81 lines
3.1 KiB
JavaScript
"use strict";
|
|
|
|
// Bundle the widget asset catalog into an app-extension (widget) target.
|
|
//
|
|
// expo-widgets generates the widget target without a Resources build phase, and
|
|
// hand-adding a PBXResourcesBuildPhase does NOT get picked up — xcodebuild's
|
|
// planner never schedules `actool` for it (verified: even a full re-plan skips
|
|
// it). So instead we add a shell-script phase that runs `actool` directly and
|
|
// drops the compiled Assets.car into the extension bundle. Marked
|
|
// alwaysOutOfDate so the build system always runs it.
|
|
//
|
|
// Idempotent across re-runs. Returns true when it added the phase, false when
|
|
// it was already present. Throws when the target does not exist — that means
|
|
// this ran before expo-widgets created the target (plugin ordering bug) and
|
|
// silently skipping would ship a widget without its assets.
|
|
|
|
const PHASE_NAME = "Compile Widget Assets";
|
|
|
|
// Compiles ExpoWidgetsTarget/Assets.xcassets into the extension's resources dir.
|
|
// Uses only Xcode-provided build settings so it works for device + simulator.
|
|
const ACTOOL_SCRIPT = [
|
|
"set -e",
|
|
'CATALOG="${SRCROOT}/ExpoWidgetsTarget/Assets.xcassets"',
|
|
'if [ ! -d "$CATALOG" ]; then',
|
|
' echo "error: widget asset catalog not found at $CATALOG (expo-widgets wiped it? check plugin ordering in app.config.ts)"',
|
|
" exit 1",
|
|
"fi",
|
|
'DEST="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"',
|
|
'mkdir -p "$DEST"',
|
|
'xcrun actool "$CATALOG" --compile "$DEST" --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET:-16.0}" --output-format human-readable-text',
|
|
].join("\n");
|
|
|
|
function stripComments(map) {
|
|
const out = {};
|
|
for (const key of Object.keys(map || {})) {
|
|
if (key.endsWith("_comment")) continue;
|
|
out[key] = map[key];
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function findByName(map, name) {
|
|
for (const [uuid, value] of Object.entries(stripComments(map))) {
|
|
if (value && value.name === name) return { uuid, value };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param {import('xcode').XcodeProject} proj
|
|
* @param {{ targetName: string }} opts
|
|
*/
|
|
function addWidgetAssetCatalog(proj, opts) {
|
|
const objects = proj.hash.project.objects;
|
|
const target = findByName(objects.PBXNativeTarget, opts.targetName);
|
|
if (!target) {
|
|
throw new Error(
|
|
`addWidgetAssetCatalog: target "${opts.targetName}" not found — ` +
|
|
"withWidgetLogoAsset must be registered before expo-widgets so its " +
|
|
"xcodeproj mod runs after the widget target is created.",
|
|
);
|
|
}
|
|
|
|
const phases = target.value.buildPhases || [];
|
|
const existing = objects.PBXShellScriptBuildPhase || {};
|
|
const already = Object.entries(stripComments(existing)).some(
|
|
([uuid, value]) =>
|
|
value && value.name === `"${PHASE_NAME}"` && phases.some((p) => p.value === uuid),
|
|
);
|
|
if (already) return false;
|
|
|
|
const { uuid } = proj.addBuildPhase([], "PBXShellScriptBuildPhase", PHASE_NAME, target.uuid, {
|
|
shellPath: "/bin/sh",
|
|
shellScript: ACTOOL_SCRIPT,
|
|
});
|
|
// Always run: input-analysis is exactly what skipped the Resources phase.
|
|
objects.PBXShellScriptBuildPhase[uuid].alwaysOutOfDate = 1;
|
|
return true;
|
|
}
|
|
|
|
module.exports = { addWidgetAssetCatalog };
|