Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ const config: ExpoConfig = {
},
],
"./plugins/withIosCocoaPodsUuidCache.cjs",
// Must be listed BEFORE expo-widgets: same-type mods run last-registered-
// first, so registering earlier makes this plugin's mods run AFTER
// expo-widgets' — its dangerous mod wipes ios/ExpoWidgetsTarget/ (which
// would delete the asset catalog) and its xcodeproj mod creates the widget
// target (which must exist before the compile phase can be attached).
"./plugins/withWidgetLogoAsset.cjs",
[
"expo-widgets",
{
Expand All @@ -174,9 +180,6 @@ const config: ExpoConfig = {
],
},
],
// Must run after expo-widgets so the widget target exists when it wires in
// the branded logo asset catalog.
"./plugins/withWidgetLogoAsset.cjs",
"./plugins/withIosSceneLifecycle.cjs",
"./plugins/withAndroidCleartextTraffic.cjs",
],
Expand Down
18 changes: 13 additions & 5 deletions apps/mobile/plugins/lib/addWidgetAssetCatalog.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
// 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 or the target was not found.
// 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";

Expand All @@ -20,8 +22,8 @@ const ACTOOL_SCRIPT = [
"set -e",
'CATALOG="${SRCROOT}/ExpoWidgetsTarget/Assets.xcassets"',
'if [ ! -d "$CATALOG" ]; then',
' echo "warning: widget asset catalog not found at $CATALOG"',
" exit 0",
' 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"',
Expand Down Expand Up @@ -51,7 +53,13 @@ function findByName(map, name) {
function addWidgetAssetCatalog(proj, opts) {
const objects = proj.hash.project.objects;
const target = findByName(objects.PBXNativeTarget, opts.targetName);
if (!target) return false;
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 || {};
Expand Down
12 changes: 9 additions & 3 deletions apps/mobile/plugins/withWidgetLogoAsset.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
// expo-widgets generates ExpoWidgetsTarget without a Resources build phase and
// has no asset support, so this plugin (a) writes an SVG template image set into
// the generated widget asset catalog and (b) wires that catalog into the widget
// target with a dedicated Resources build phase. Both steps are idempotent and
// survive `expo prebuild --clean`. Must be listed AFTER "expo-widgets" in the
// plugins array so the widget target exists when this runs.
// target with an actool build phase.
//
// ORDERING: must be listed BEFORE "expo-widgets" in the plugins array. Expo
// chains same-type mods so the last-registered runs FIRST; registering this
// plugin earlier makes its mods run AFTER expo-widgets' mods. That matters
// twice: expo-widgets' dangerous mod rmSync's ios/ExpoWidgetsTarget/ (deleting
// any catalog written before it), and its xcodeproj mod is what creates the
// widget target. Listed after expo-widgets, both steps silently no-op on a
// fresh prebuild — which is how prod build 8 shipped without the logo.

const path = require("path");
const fs = require("fs");
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/scripts/wire-widget-asset-catalog.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ if (added) {
fs.writeFileSync(pbxprojPath, proj.writeSync());
console.log("Added widget asset-compile phase to ExpoWidgetsTarget.");
} else {
console.log("No change: phase already present or target not found.");
console.log("No change: phase already present.");
}
Loading