Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Better Catalyst build support #1313

Merged
merged 5 commits into from
Aug 30, 2024
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
20 changes: 16 additions & 4 deletions CordovaLib/CordovaLib.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,10 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
PUBLIC_HEADERS_FOLDER_PATH = include/Cordova;
TARGETED_DEVICE_FAMILY = "1,2";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,7";
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Debug;
};
Expand All @@ -649,7 +652,10 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
PUBLIC_HEADERS_FOLDER_PATH = include/Cordova;
TARGETED_DEVICE_FAMILY = "1,2";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,7";
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Release;
};
Expand Down Expand Up @@ -809,9 +815,12 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
PRODUCT_BUNDLE_IDENTIFIER = org.apache.cordova.Cordova;
SKIP_INSTALL = NO;
TARGETED_DEVICE_FAMILY = "1,2";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,7";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Debug;
};
Expand All @@ -832,9 +841,12 @@
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
PRODUCT_BUNDLE_IDENTIFIER = org.apache.cordova.Cordova;
SKIP_INSTALL = NO;
TARGETED_DEVICE_FAMILY = "1,2";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator xros xrsimulator";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,7";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
XROS_DEPLOYMENT_TARGET = 1.0;
};
name = Release;
};
Expand Down
51 changes: 36 additions & 15 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function getDefaultSimulatorTarget () {
/** @returns {Promise<void>} */
module.exports.run = function (buildOpts) {
const projectPath = this.root;
let emulatorTarget = '';
let emulatorTarget = 'iOS Device';
let projectName = '';

buildOpts = buildOpts || {};
Expand All @@ -115,6 +115,14 @@ module.exports.run = function (buildOpts) {
return Promise.reject(new CordovaError('Cannot specify "device" and "emulator" options together.'));
}

if (buildOpts.target && buildOpts.target.match(/mac/i)) {
buildOpts.catalyst = true;
buildOpts.device = true;
buildOpts.emulator = false;

emulatorTarget = 'macOS Catalyst';
}

if (buildOpts.buildConfig) {
if (!fs.existsSync(buildOpts.buildConfig)) {
return Promise.reject(new CordovaError(`Build config file does not exist: ${buildOpts.buildConfig}`));
Expand All @@ -133,15 +141,18 @@ module.exports.run = function (buildOpts) {
}
}

return require('./listDevices').run()
.then(devices => {
if (devices.length > 0 && !(buildOpts.emulator)) {
// we also explicitly set device flag in options as we pass
// those parameters to other api (build as an example)
buildOpts.device = true;
return check_reqs.check_ios_deploy();
return Promise.resolve()
.then(() => {
if (!buildOpts.emulator && !buildOpts.catalyst) {
return require('./listDevices').run().then(devices => {
if (devices.length > 0) {
// we explicitly set device flag in options
buildOpts.device = true;
}
});
}
}).then(() => {
})
.then(() => {
// CB-12287: Determine the device we should target when building for a simulator
if (!buildOpts.device) {
let newTarget = buildOpts.target || '';
Expand Down Expand Up @@ -175,8 +186,8 @@ module.exports.run = function (buildOpts) {
let extraConfig = '';
if (buildOpts.codeSignIdentity) {
extraConfig += `CODE_SIGN_IDENTITY = ${buildOpts.codeSignIdentity}\n`;
extraConfig += `CODE_SIGN_IDENTITY[sdk=iphoneos*] = ${buildOpts.codeSignIdentity}\n`;
}

if (buildOpts.provisioningProfile) {
if (typeof buildOpts.provisioningProfile === 'string') {
extraConfig += `PROVISIONING_PROFILE_SPECIFIER = ${buildOpts.provisioningProfile}\n`;
Expand Down Expand Up @@ -225,7 +236,7 @@ module.exports.run = function (buildOpts) {
const xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, emulatorTarget, buildOpts);
return execa('xcodebuild', xcodebuildArgs, { cwd: projectPath, stdio: 'inherit' });
}).then(() => {
if (!buildOpts.device || buildOpts.noSign) {
if (!buildOpts.device || buildOpts.catalyst || buildOpts.noSign) {
return;
}

Expand Down Expand Up @@ -336,7 +347,7 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
}
}

if (buildConfig.device) {
if (buildConfig.device && !buildConfig.catalyst) {
options = [
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
Expand Down Expand Up @@ -377,10 +388,20 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
options = [
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
'-scheme', customArgs.scheme || projectName,
'-configuration', customArgs.configuration || configuration,
'-sdk', customArgs.sdk || 'iphonesimulator',
'-destination', customArgs.destination || `platform=iOS Simulator,name=${emulatorTarget}`
'-configuration', customArgs.configuration || configuration
];

if (buildConfig.catalyst) {
options = options.concat([
'-destination', customArgs.destination || 'generic/platform=macOS,variant=Mac Catalyst'
]);
} else {
options = options.concat([
'-sdk', customArgs.sdk || 'iphonesimulator',
'-destination', customArgs.destination || `platform=iOS Simulator,name=${emulatorTarget}`
]);
}

buildActions = ['build'];
settings = [`SYMROOT=${path.join(projectPath, 'build')}`];

Expand Down
82 changes: 57 additions & 25 deletions lib/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,38 @@ module.exports.run = function (runOptions) {
return module.exports.listDevices().then(() => module.exports.listEmulators());
}

let useDevice = !!runOptions.device;
const useCatalyst = runOptions.target && runOptions.target.match(/mac/i);
let useDevice = !!runOptions.device && !useCatalyst;
const configuration = runOptions.release ? 'Release' : 'Debug';

return require('./listDevices').run()
.then(devices => {
if (devices.length > 0 && !(runOptions.emulator)) {
useDevice = true;
// we also explicitly set device flag in options as we pass
// those parameters to other api (build as an example)
runOptions.device = true;
return check_reqs.check_ios_deploy();
return Promise.resolve()
.then(() => {
if (!runOptions.emulator && !useCatalyst) {
return module.exports.execListDevices().then(devices => {
if (devices.length > 0) {
useDevice = true;

// we also explicitly set device flag in options as we pass
// those parameters to other api (build as an example)
runOptions.device = true;
return check_reqs.check_ios_deploy();
}
});
}
}).then(() => {
})
.then(() => {
if (!runOptions.nobuild) {
return build.run(runOptions);
} else {
return Promise.resolve();
}
}).then(() => build.findXCodeProjectIn(projectPath))
})
.then(() => build.findXCodeProjectIn(projectPath))
.then(projectName => {
let appPath = path.join(projectPath, 'build', `${configuration}-iphonesimulator`, `${projectName}.app`);
const buildOutputDir = path.join(projectPath, 'build', `${configuration}-iphoneos`);

// select command to run and arguments depending whether
// we're running on device/emulator
// we're running on device/catalyst/emulator
if (useDevice) {
const buildOutputDir = path.join(projectPath, 'build', `${configuration}-iphoneos`);
const appPath = path.join(buildOutputDir, `${projectName}.app`);

return module.exports.checkDeviceConnected()
.then(() => {
// Unpack IPA
Expand All @@ -78,21 +84,19 @@ module.exports.run = function (runOptions) {
.then(() => {
// Uncompress IPA (zip file)
const appFileInflated = path.join(buildOutputDir, 'Payload', `${projectName}.app`);
const appFile = path.join(buildOutputDir, `${projectName}.app`);
const payloadFolder = path.join(buildOutputDir, 'Payload');

// delete the existing platform/ios/build/device/appname.app
fs.rmSync(appFile, { recursive: true, force: true });
fs.rmSync(appPath, { recursive: true, force: true });
// move the platform/ios/build/device/Payload/appname.app to parent
fs.renameSync(appFileInflated, appFile);
fs.renameSync(appFileInflated, appPath);
// delete the platform/ios/build/device/Payload folder
fs.rmSync(payloadFolder, { recursive: true, force: true });

return null;
})
.then(
() => {
appPath = path.join(projectPath, 'build', `${configuration}-iphoneos`, `${projectName}.app`);
let extraArgs = [];
if (runOptions.argv) {
// argv.slice(2) removes node and run.js, filterSupportedArgs removes the run.js args
Expand All @@ -101,9 +105,14 @@ module.exports.run = function (runOptions) {
return module.exports.deployToDevice(appPath, runOptions.target, extraArgs);
},
// if device connection check failed use emulator then
// This might fail due to being the wrong type of app bundle
() => module.exports.deployToSim(appPath, runOptions.target)
);
} else if (useCatalyst) {
const appPath = path.join(projectPath, 'build', `${configuration}-maccatalyst`, `${projectName}.app`);
return module.exports.deployToMac(appPath);
} else {
const appPath = path.join(projectPath, 'build', `${configuration}-iphonesimulator`, `${projectName}.app`);
return module.exports.deployToSim(appPath, runOptions.target);
}
})
Expand All @@ -113,10 +122,13 @@ module.exports.run = function (runOptions) {
module.exports.filterSupportedArgs = filterSupportedArgs;
module.exports.checkDeviceConnected = checkDeviceConnected;
module.exports.deployToDevice = deployToDevice;
module.exports.deployToMac = deployToMac;
module.exports.deployToSim = deployToSim;
module.exports.startSim = startSim;
module.exports.listDevices = listDevices;
module.exports.listEmulators = listEmulators;
module.exports.execListDevices = execListDevices;
module.exports.execListEmulatorTargets = execListEmulatorTargets;

/**
* Filters the args array and removes supported args for the 'run' command.
Expand Down Expand Up @@ -164,6 +176,16 @@ function deployToDevice (appPath, target, extraArgs) {
return execa('ios-deploy', args.concat(extraArgs), { stdio: 'inherit' });
}

/**
* Runs specified app package on the local macOS system.
* @param {String} appPath Path to application package
* @return {Promise} Resolves when deploy succeeds otherwise rejects
*/
function deployToMac (appPath) {
events.emit('log', 'Deploying to local macOS system');
return execa('open', [appPath], { stdio: 'inherit' });
}

/**
* Deploy specified app package to ios-sim simulator
* @param {String} appPath Path to application package
Expand All @@ -175,13 +197,13 @@ async function deployToSim (appPath, target) {

if (!target) {
// Select target device for emulator (preferring iPhone Emulators)
const emulators = await require('./listEmulatorImages').run();
const emulators = await module.exports.execListEmulatorTargets();
const iPhoneEmus = emulators.filter(emulator => emulator.startsWith('iPhone'));
target = iPhoneEmus.concat(emulators)[0];
events.emit('log', `No target specified for emulator. Deploying to "${target}" simulator.`);
}

return startSim(appPath, target);
return module.exports.startSim(appPath, target);
}

function startSim (appPath, target) {
Expand Down Expand Up @@ -210,8 +232,18 @@ function startSim (appPath, target) {
return subprocess;
}

/* istanbul ignore next */
function execListDevices () {
return require('./listDevices').run();
}

/* istanbul ignore next */
function execListEmulatorTargets () {
return require('./listEmulatorTargets').run();
}

function listDevices () {
return require('./listDevices').run()
return module.exports.execListDevices()
.then(devices => {
events.emit('log', 'Available iOS Devices:');
devices.forEach(device => {
Expand All @@ -221,7 +253,7 @@ function listDevices () {
}

function listEmulators () {
return require('./listEmulatorImages').run()
return module.exports.execListEmulatorTargets()
.then(emulators => {
events.emit('log', 'Available iOS Simulators:');
emulators.forEach(emulator => {
Expand Down
8 changes: 7 additions & 1 deletion templates/project/__PROJECT_NAME__.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
objects = {

/* Begin PBXBuildFile section */
902AE2142C6C059A0041150F /* Cordova.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 907F985F2C06B8DE00D2D242 /* Cordova.framework */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
902AE2142C6C059A0041150F /* Cordova.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 907F985F2C06B8DE00D2D242 /* Cordova.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
907F98562C06B87200D2D242 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 907F98552C06B87200D2D242 /* PrivacyInfo.xcprivacy */; };
907F98662C06BC1B00D2D242 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 907F98652C06BC1B00D2D242 /* config.xml */; };
907F986A2C06BCD300D2D242 /* www in Resources */ = {isa = PBXBuildFile; fileRef = 907F98692C06BCD300D2D242 /* www */; };
Expand Down Expand Up @@ -388,8 +388,11 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_WORKSPACE = NO;
};
name = Debug;
};
Expand Down Expand Up @@ -445,8 +448,11 @@
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SUPPORTS_MACCATALYST = YES;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_COMPILATION_MODE = wholemodule;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VALIDATE_WORKSPACE = NO;
};
name = Release;
};
Expand Down
Loading