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
17 changes: 12 additions & 5 deletions src/api/PBXNativeTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,7 @@ export class PBXNativeTarget extends AbstractTarget<PBXNativeTargetModel> {
"com.apple.product-type.application.on-demand-install-capable"
) {
return "Embed App Clips";
} else if (
target.props.productType === "com.apple.product-type.application"
) {
} else if (target.isWatchOSTarget()) {
return "Embed Watch Content";
} else if (
target.props.productType ===
Expand Down Expand Up @@ -227,8 +225,17 @@ export class PBXNativeTarget extends AbstractTarget<PBXNativeTargetModel> {

isWatchOSTarget(): boolean {
return (
this.props.productType === "com.apple.product-type.application" &&
!!this.getDefaultBuildSetting("WATCHOS_DEPLOYMENT_TARGET")
this.props.productType === "com.apple.product-type.application.watchapp" ||
this.props.productType === "com.apple.product-type.application.watchapp2" ||
this.props.productType ===
"com.apple.product-type.application.watchapp2-container"
);
}

isWatchExtension(): boolean {
return (
this.props.productType === "com.apple.product-type.watchkit-extension" ||
this.props.productType === "com.apple.product-type.watchkit2-extension"
);
}

Expand Down
120 changes: 86 additions & 34 deletions src/api/__tests__/PBXNativeTarget.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,10 @@ describe("PBXNativeTarget", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();

// Create a watch app target
// Create a watch app target with correct watchOS product type
const watchTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatchApp",
productType: "com.apple.product-type.application",
productType: "com.apple.product-type.application.watchapp2",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

Expand Down Expand Up @@ -473,39 +473,43 @@ describe("PBXNativeTarget", () => {
});

describe("isWatchOSTarget", () => {
it("should return true for watchOS app targets", () => {
it("should return true for watchapp2 targets", () => {
const xcproj = XcodeProject.open(WATCH_FIXTURE);

// Find a target with WATCHOS_DEPLOYMENT_TARGET
let watchTarget: PBXNativeTarget | null = null;
for (const target of xcproj.rootObject.props.targets) {
if (
// Find a target with watchapp2 product type
const watchTarget = xcproj.rootObject.props.targets.find(
(target) =>
PBXNativeTarget.is(target) &&
target.props.productType === "com.apple.product-type.application" &&
target.getDefaultBuildSetting("WATCHOS_DEPLOYMENT_TARGET")
) {
watchTarget = target;
break;
}
}
target.props.productType ===
"com.apple.product-type.application.watchapp2"
) as PBXNativeTarget | undefined;

if (watchTarget) {
expect(watchTarget.isWatchOSTarget()).toBe(true);
} else {
// If no watchOS target found, create one for testing
const xcproj2 = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj2.rootObject.getMainAppTarget();
const testWatchTarget = xcproj2.rootObject.createNativeTarget({
name: "TestWatchApp",
productType: "com.apple.product-type.application",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

// Set WATCHOS_DEPLOYMENT_TARGET to make it a watchOS target
testWatchTarget.setBuildSetting("WATCHOS_DEPLOYMENT_TARGET", "8.0");

expect(testWatchTarget.isWatchOSTarget()).toBe(true);
}
expect(watchTarget).toBeDefined();
expect(watchTarget!.isWatchOSTarget()).toBe(true);
});

it("should return true for watchapp targets", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const testWatchTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatchApp",
productType: "com.apple.product-type.application.watchapp",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

expect(testWatchTarget.isWatchOSTarget()).toBe(true);
});

it("should return true for watchapp2-container targets", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const testWatchTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatchAppContainer",
productType: "com.apple.product-type.application.watchapp2-container",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

expect(testWatchTarget.isWatchOSTarget()).toBe(true);
});

it("should return false for iOS app targets", () => {
Expand All @@ -526,7 +530,7 @@ describe("PBXNativeTarget", () => {
expect(extensionTarget!.isWatchOSTarget()).toBe(false);
});

it("should return false for application targets without WATCHOS_DEPLOYMENT_TARGET", () => {
it("should return false for regular application targets even with WATCHOS_DEPLOYMENT_TARGET", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const testTarget = xcproj.rootObject.createNativeTarget({
Expand All @@ -535,13 +539,61 @@ describe("PBXNativeTarget", () => {
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

// Ensure no WATCHOS_DEPLOYMENT_TARGET is set
testTarget.removeBuildSetting("WATCHOS_DEPLOYMENT_TARGET");
// Even with WATCHOS_DEPLOYMENT_TARGET, a regular application is not a watchOS target
testTarget.setBuildSetting("WATCHOS_DEPLOYMENT_TARGET", "8.0");

expect(testTarget.isWatchOSTarget()).toBe(false);
});
});

describe("isWatchExtension", () => {
it("should return true for watchkit-extension targets", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const watchExtTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatchExtension",
productType: "com.apple.product-type.watchkit-extension",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

expect(watchExtTarget.isWatchExtension()).toBe(true);
});

it("should return true for watchkit2-extension targets", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const watchExtTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatch2Extension",
productType: "com.apple.product-type.watchkit2-extension",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

expect(watchExtTarget.isWatchExtension()).toBe(true);
});

it("should return false for watchOS app targets", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const mainTarget = xcproj.rootObject.getMainAppTarget();
const watchTarget = xcproj.rootObject.createNativeTarget({
name: "TestWatchApp",
productType: "com.apple.product-type.application.watchapp2",
buildConfigurationList: mainTarget!.props.buildConfigurationList,
});

expect(watchTarget.isWatchExtension()).toBe(false);
});

it("should return false for regular app extensions", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
const extensionTarget = xcproj.rootObject.getNativeTarget(
"com.apple.product-type.app-extension"
);

expect(extensionTarget).toBeDefined();
expect(extensionTarget!.isWatchExtension()).toBe(false);
});
});

describe("integration tests", () => {
it("should handle complex target relationships", () => {
const xcproj = XcodeProject.open(MULTITARGET_FIXTURE);
Expand Down
7 changes: 5 additions & 2 deletions src/api/__tests__/PBXSourcesBuildPhase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ const RN_FIXTURE = path.join(
"../../json/__tests__/fixtures/project-rn74.pbxproj"
);

it(`adds PBXCopyFilesBuildPhase for Watch extension`, () => {
it(`adds PBXCopyFilesBuildPhase for Watch app`, () => {
const xcproj = XcodeProject.open(WORKING_FIXTURE);

// Watch apps use wrapper.application file type, but we use .appex extension
// to trigger the isAppExtension() check in setupDefaults
const fileRef = PBXFileReference.create(xcproj, {
path: "Watchy.appex",
lastKnownFileType: "wrapper.app-extension",
});
const file = PBXBuildFile.create(xcproj, {
fileRef,
Expand Down Expand Up @@ -55,7 +58,7 @@ it(`adds PBXCopyFilesBuildPhase for Watch extension`, () => {
}),
name: "Watchy",
productName: "Watchy",
productType: "com.apple.product-type.application",
productType: "com.apple.product-type.application.watchapp2",
productReference: fileRef,
});

Expand Down