Skip to content

Commit ca96fa5

Browse files
farfromrefugclaude
andcommitted
fix(ios/catalyst): make debug builds launch
Report iOS as the platform name again. Ecosystem hooks and plugins switch on `normalizedPlatformName`, and an unknown value leaves them in a branch that never resolves, hanging the prepare. Only `projectRoot` stays catalyst specific. Read entitlements from App_Resources/iOS, since catalyst has no folder of its own. The merge silently produced nothing before, so the app group was dropped and the template sandbox entitlement survived. Disable the app sandbox for debug builds, which have no provisioning profile, and point metadata generation at the iOSSupport frameworks so UIKit resolves. Recreate the symlink layout of versioned frameworks after unzipping, as the runtime archives them flattened and codesign then rejects the bundle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 5b9438e commit ca96fa5

3 files changed

Lines changed: 68 additions & 6 deletions

File tree

lib/services/ios-entitlements-service.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@ export class IOSEntitlementsService {
2020

2121
private getDefaultAppEntitlementsPath(projectData: IProjectData): string {
2222
const entitlementsName = IOSEntitlementsService.DefaultEntitlementsName;
23+
const requestedPlatform = this.$mobileHelper.normalizePlatformName(
24+
this.$options.platformOverride ?? this.$devicePlatformsConstants.iOS,
25+
);
26+
// Catalyst has no App_Resources folder of its own, it reuses the iOS one.
27+
const platform = this.$mobileHelper.isCatalystPlatform(requestedPlatform)
28+
? this.$devicePlatformsConstants.iOS
29+
: requestedPlatform;
2330
const entitlementsPath = path.join(
2431
projectData.appResourcesDirectoryPath,
25-
this.$mobileHelper.normalizePlatformName(
26-
this.$options.platformOverride ?? this.$devicePlatformsConstants.iOS,
27-
),
32+
platform,
2833
entitlementsName,
2934
);
3035
return entitlementsPath;

lib/services/ios-project-service.ts

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as path from "path";
2+
import * as fs from "fs";
23
import * as shell from "shelljs";
34
import * as _ from "lodash";
45
import * as constants from "../constants";
@@ -166,7 +167,7 @@ export class IOSProjectService
166167
const requestedPlatform = this.$mobileHelper.normalizePlatformName(
167168
this.$options.platformOverride ?? this.$devicePlatformsConstants.iOS,
168169
);
169-
// Mac Catalyst ships no runtime of its own, it reuses the iOS one.
170+
// Hooks and plugins switch on the iOS name, Catalyst must keep it.
170171
const runtimePlatform = this.$mobileHelper.isCatalystPlatform(
171172
requestedPlatform,
172173
)
@@ -182,8 +183,8 @@ export class IOSProjectService
182183

183184
this._platformData = {
184185
frameworkPackageName: runtimePackage.name,
185-
normalizedPlatformName: requestedPlatform,
186-
platformNameLowerCase: requestedPlatform.toLowerCase(),
186+
normalizedPlatformName: runtimePlatform,
187+
platformNameLowerCase: runtimePlatform.toLowerCase(),
187188
appDestinationDirectoryPath: path.join(
188189
projectRoot,
189190
projectData.projectName,
@@ -427,6 +428,57 @@ export class IOSProjectService
427428
if (this.$fs.exists(xcframeworksFilePath)) {
428429
await this.$fs.unzip(xcframeworksFilePath, internalDirPath);
429430
this.$fs.deleteFile(xcframeworksFilePath);
431+
this.restoreVersionedFrameworkSymlinks(internalDirPath);
432+
}
433+
}
434+
435+
/**
436+
* Recreates the symlink layout of versioned frameworks after extraction.
437+
*/
438+
private restoreVersionedFrameworkSymlinks(rootPath: string): void {
439+
// Runtimes zip macOS style frameworks flattened, which breaks codesign.
440+
const frameworks = fastGlob.sync("**/*.framework", {
441+
cwd: rootPath,
442+
onlyDirectories: true,
443+
absolute: true,
444+
deep: 4,
445+
});
446+
447+
for (const frameworkPath of frameworks) {
448+
const versionsPath = path.join(frameworkPath, "Versions");
449+
if (!this.$fs.exists(versionsPath)) {
450+
continue;
451+
}
452+
453+
const versions = this.$fs
454+
.readDirectory(versionsPath)
455+
.filter((name) => name !== "Current");
456+
if (!versions.length) {
457+
continue;
458+
}
459+
460+
const version = versions.includes("A") ? "A" : versions[0];
461+
const currentPath = path.join(versionsPath, "Current");
462+
if (!fs.lstatSync(currentPath, { throwIfNoEntry: false })?.isSymbolicLink()) {
463+
shell.rm("-rf", currentPath);
464+
fs.symlinkSync(version, currentPath);
465+
}
466+
467+
for (const name of this.$fs.readDirectory(
468+
path.join(versionsPath, version),
469+
)) {
470+
const topLevelPath = path.join(frameworkPath, name);
471+
if (
472+
fs
473+
.lstatSync(topLevelPath, { throwIfNoEntry: false })
474+
?.isSymbolicLink()
475+
) {
476+
continue;
477+
}
478+
479+
shell.rm("-rf", topLevelPath);
480+
fs.symlinkSync(path.join("Versions", "Current", name), topLevelPath);
481+
}
430482
}
431483
}
432484

lib/services/ios/xcodebuild-args-service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export class XcodebuildArgsService implements IXcodebuildArgsService {
4747
buildConfig.release ? Configurations.Release : Configurations.Debug,
4848
"-allowProvisioningUpdates",
4949
"SUPPORTS_MACCATALYST=YES",
50+
// Sandbox needs a provisioning profile, debug runs have none.
51+
...(buildConfig.release ? [] : ["ENABLE_APP_SANDBOX=NO"]),
52+
// Metadata generation needs UIKit, which lives under iOSSupport.
53+
"OTHER_CFLAGS=$(inherited) -iframework " +
54+
"$(SDKROOT)/System/iOSSupport/System/Library/Frameworks",
5055
// no `-sdk` here: the destination already selects macOS + the Mac Catalyst
5156
// variant, and forcing an SDK on top of it makes xcodebuild pick iphoneos
5257
"BUILD_DIR=" + path.join(platformData.projectRoot, constants.BUILD_DIR),

0 commit comments

Comments
 (0)