Skip to content

Commit a8f9c57

Browse files
authored
refactor!: Consistent app template/Xcode project name (#1485)
* refactor!(project): Use consistent project name * chore(deps): Remove unneeded xmlescape dependency * fix(build): Consistent handling of archivePath flags * feat!: Pull in CordovaLib with SwiftPM * fix(orientation): Set orientation values in Xcodeproj Otherwise when Xcode consolidates the plist file it will probably overwrite the ones in the plist with the ones defined in the Xcodeproj file (which is where it wants to put things by default nowadays). * fix(pbxproj): Fix compat with some plugins Some plugins look up the root group of the Xcode project based on the name "CustomTemplate", which isn't really an ideal thing to do but I'm unsure if there are better options and this name doesn't actually get displayed anywhere so we might as well keep the label for compatibility reasons. * fix(project): Validate that App.xcodeproj exists This is a guard against running a newer version of Cordova iOS tools against an older project with a different name (which will fail due to now-hardcoded assumptions about the project name). * fix(run): Launch app based on the product name
1 parent 98a3bcd commit a8f9c57

File tree

72 files changed

+585
-770
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+585
-770
lines changed

lib/Api.js

+7-26
Original file line numberDiff line numberDiff line change
@@ -81,39 +81,20 @@ class Api {
8181

8282
setupEvents(events);
8383

84-
let xcodeProjDir;
85-
let xcodeCordovaProj;
86-
87-
try {
88-
const xcodeProjDir_array = fs.readdirSync(this.root).filter(e => e.match(/\.xcodeproj$/i));
89-
if (xcodeProjDir_array.length > 1) {
90-
for (let x = 0; x < xcodeProjDir_array.length; x++) {
91-
if (xcodeProjDir_array[x].substring(0, 2) === '._') {
92-
xcodeProjDir_array.splice(x, 1);
93-
}
94-
}
95-
}
96-
xcodeProjDir = xcodeProjDir_array[0];
97-
98-
if (!xcodeProjDir) {
99-
throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`);
100-
}
101-
102-
const cordovaProjName = xcodeProjDir.substring(xcodeProjDir.lastIndexOf(path.sep) + 1, xcodeProjDir.indexOf('.xcodeproj'));
103-
xcodeCordovaProj = path.join(this.root, cordovaProjName);
104-
} catch (e) {
105-
throw new CordovaError(`The provided path "${this.root}" is not a Cordova iOS project.`);
84+
const xcodeProjDir = path.join(this.root, 'App.xcodeproj');
85+
if (!fs.existsSync(xcodeProjDir)) {
86+
throw new CordovaError(`The provided path "${this.root}" is not an up-to-date Cordova iOS project.`);
10687
}
10788

10889
this.locations = {
10990
root: this.root,
11091
www: path.join(this.root, 'www'),
11192
platformWww: path.join(this.root, 'platform_www'),
112-
configXml: path.join(xcodeCordovaProj, 'config.xml'),
93+
configXml: path.join(this.root, 'App', 'config.xml'),
11394
defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
114-
pbxproj: path.join(this.root, xcodeProjDir, 'project.pbxproj'),
115-
xcodeProjDir: path.join(this.root, xcodeProjDir),
116-
xcodeCordovaProj
95+
pbxproj: path.join(xcodeProjDir, 'project.pbxproj'),
96+
xcodeProjDir,
97+
xcodeCordovaProj: path.join(this.root, 'App')
11798
};
11899
}
119100

lib/Podfile.js

+6-12
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,6 @@ function Podfile (podFilePath, projectName, minDeploymentTarget) {
5050
throw new CordovaError(util.format('Podfile: The file at %s is not `%s`.', this.path, Podfile.FILENAME));
5151
}
5252

53-
if (!projectName) {
54-
throw new CordovaError('Podfile: The projectName was not specified in the constructor.');
55-
}
56-
5753
if (!fs.existsSync(this.path)) {
5854
events.emit('verbose', util.format('Podfile: The file at %s does not exist.', this.path));
5955
events.emit('verbose', 'Creating new Podfile in platforms/ios');
@@ -168,18 +164,16 @@ Podfile.prototype.escapeSingleQuotes = function (string) {
168164
};
169165

170166
Podfile.prototype.getTemplate = function () {
171-
// Escaping possible ' in the project name
172-
const projectName = this.escapeSingleQuotes(this.projectName);
173167
return util.format(
174168
'# DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
175169
'%s\n' +
176170
'platform :ios, \'%s\'\n' +
177171
'%s\n' +
178-
'target \'%s\' do\n' +
179-
'\tproject \'%s.xcodeproj\'\n' +
172+
'target \'App\' do\n' +
173+
'\tproject \'App.xcodeproj\'\n' +
180174
'%s\n' +
181175
'end\n',
182-
this.sourceToken, this.minDeploymentTarget, this.declarationToken, projectName, projectName, this.podToken);
176+
this.sourceToken, this.minDeploymentTarget, this.declarationToken, this.podToken);
183177
};
184178

185179
Podfile.prototype.addSpec = function (name, spec) {
@@ -361,10 +355,10 @@ Podfile.prototype.before_install = function (toolOptions) {
361355
// Template tokens in order: project name, project name, debug | release
362356
const template =
363357
'// DO NOT MODIFY -- auto-generated by Apache Cordova\n' +
364-
'#include "Pods/Target Support Files/Pods-%s/Pods-%s.%s.xcconfig"';
358+
'#include "Pods/Target Support Files/Pods-App/Pods-App.%s.xcconfig"';
365359

366-
const debugContents = util.format(template, this.projectName, this.projectName, 'debug');
367-
const releaseContents = util.format(template, this.projectName, this.projectName, 'release');
360+
const debugContents = util.format(template, 'debug');
361+
const releaseContents = util.format(template, 'release');
368362

369363
const debugConfigPath = path.join(this.path, '..', 'pods-debug.xcconfig');
370364
const releaseConfigPath = path.join(this.path, '..', 'pods-release.xcconfig');

lib/build.js

+30-45
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,11 @@ const buildFlagMatchers = {
6161
* a project path and name
6262
*
6363
* @param {*} projectPath
64-
* @param {*} projectName
6564
*/
66-
function createProjectObject (projectPath, projectName) {
65+
function createProjectObject (projectPath) {
6766
const locations = {
6867
root: projectPath,
69-
pbxproj: path.join(projectPath, `${projectName}.xcodeproj`, 'project.pbxproj')
68+
pbxproj: path.join(projectPath, 'App.xcodeproj', 'project.pbxproj')
7069
};
7170

7271
return projectFile.parse(locations);
@@ -103,7 +102,6 @@ function getDefaultSimulatorTarget () {
103102
module.exports.run = function (buildOpts) {
104103
const projectPath = this.root;
105104
let emulatorTarget = 'iOS Device';
106-
let projectName = '';
107105

108106
buildOpts = buildOpts || {};
109107

@@ -180,9 +178,7 @@ module.exports.run = function (buildOpts) {
180178
}
181179
})
182180
.then(() => check_reqs.run())
183-
.then(() => findXCodeProjectIn(projectPath))
184-
.then(name => {
185-
projectName = name;
181+
.then(() => {
186182
let extraConfig = '';
187183
if (buildOpts.codeSignIdentity) {
188184
extraConfig += `CODE_SIGN_IDENTITY = ${buildOpts.codeSignIdentity}\n`;
@@ -201,7 +197,7 @@ module.exports.run = function (buildOpts) {
201197
}
202198

203199
function writeCodeSignStyle (value) {
204-
const project = createProjectObject(projectPath, projectName);
200+
const project = createProjectObject(projectPath);
205201

206202
events.emit('verbose', `Set CODE_SIGN_STYLE Build Property to ${value}.`);
207203
project.xcode.updateBuildProperty('CODE_SIGN_STYLE', value);
@@ -223,7 +219,7 @@ module.exports.run = function (buildOpts) {
223219
}).then(() => {
224220
const configuration = buildOpts.release ? 'Release' : 'Debug';
225221

226-
events.emit('log', `Building project: ${path.join(projectPath, `${projectName}.xcworkspace`)}`);
222+
events.emit('log', `Building project: ${path.join(projectPath, 'App.xcworkspace')}`);
227223
events.emit('log', `\tConfiguration: ${configuration}`);
228224
events.emit('log', `\tPlatform: ${buildOpts.device ? 'device' : 'emulator'}`);
229225
events.emit('log', `\tTarget: ${emulatorTarget}`);
@@ -233,14 +229,14 @@ module.exports.run = function (buildOpts) {
233229
// remove the build output folder before building
234230
fs.rmSync(buildOutputDir, { recursive: true, force: true });
235231

236-
const xcodebuildArgs = getXcodeBuildArgs(projectName, projectPath, configuration, emulatorTarget, buildOpts);
232+
const xcodebuildArgs = getXcodeBuildArgs(projectPath, configuration, emulatorTarget, buildOpts);
237233
return execa('xcodebuild', xcodebuildArgs, { cwd: projectPath, stdio: 'inherit' });
238234
}).then(() => {
239235
if (!buildOpts.device || buildOpts.catalyst || buildOpts.noSign) {
240236
return;
241237
}
242238

243-
const project = createProjectObject(projectPath, projectName);
239+
const project = createProjectObject(projectPath);
244240
const bundleIdentifier = project.getPackageName();
245241
const exportOptions = { ...buildOpts.exportOptions, compileBitcode: false, method: 'development' };
246242

@@ -287,7 +283,7 @@ module.exports.run = function (buildOpts) {
287283
}
288284

289285
function packageArchive () {
290-
const xcodearchiveArgs = getXcodeArchiveArgs(projectName, projectPath, buildOutputDir, exportOptionsPath, buildOpts);
286+
const xcodearchiveArgs = getXcodeArchiveArgs(projectPath, buildOutputDir, exportOptionsPath, buildOpts);
291287
return execa('xcodebuild', xcodearchiveArgs, { cwd: projectPath, stdio: 'inherit' });
292288
}
293289

@@ -298,38 +294,15 @@ module.exports.run = function (buildOpts) {
298294
.then(() => {}); // resolve to undefined
299295
};
300296

301-
/**
302-
* Searches for first XCode project in specified folder
303-
* @param {String} projectPath Path where to search project
304-
* @return {Promise} Promise either fulfilled with project name or rejected
305-
*/
306-
function findXCodeProjectIn (projectPath) {
307-
// 'Searching for Xcode project in ' + projectPath);
308-
const xcodeProjFiles = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');
309-
310-
if (xcodeProjFiles.length === 0) {
311-
return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
312-
}
313-
if (xcodeProjFiles.length > 1) {
314-
events.emit('warn', `Found multiple .xcodeproj directories in \n${projectPath}\nUsing first one`);
315-
}
316-
317-
const projectName = path.basename(xcodeProjFiles[0], '.xcodeproj');
318-
return Promise.resolve(projectName);
319-
}
320-
321-
module.exports.findXCodeProjectIn = findXCodeProjectIn;
322-
323297
/**
324298
* Returns array of arguments for xcodebuild
325-
* @param {String} projectName Name of xcode project
326299
* @param {String} projectPath Path to project file. Will be used to set CWD for xcodebuild
327300
* @param {String} configuration Configuration name: debug|release
328301
* @param {String} emulatorTarget Target for emulator (rather than default)
329302
* @param {Object} buildConfig The build configuration options
330303
* @return {Array} Array of arguments that could be passed directly to spawn method
331304
*/
332-
function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTarget, buildConfig = {}) {
305+
function getXcodeBuildArgs (projectPath, configuration, emulatorTarget, buildConfig = {}) {
333306
let options;
334307
let buildActions;
335308
let settings;
@@ -349,11 +322,11 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
349322

350323
if (buildConfig.device && !buildConfig.catalyst) {
351324
options = [
352-
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
353-
'-scheme', customArgs.scheme || projectName,
325+
'-workspace', customArgs.workspace || 'App.xcworkspace',
326+
'-scheme', customArgs.scheme || 'App',
354327
'-configuration', customArgs.configuration || configuration,
355328
'-destination', customArgs.destination || 'generic/platform=iOS',
356-
'-archivePath', customArgs.archivePath || `${projectName}.xcarchive`
329+
'-archivePath', customArgs.archivePath || 'App.xcarchive'
357330
];
358331
buildActions = ['archive'];
359332
settings = [];
@@ -386,8 +359,8 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
386359
}
387360
} else { // emulator
388361
options = [
389-
'-workspace', customArgs.workspace || `${projectName}.xcworkspace`,
390-
'-scheme', customArgs.scheme || projectName,
362+
'-workspace', customArgs.workspace || 'App.xcworkspace',
363+
'-scheme', customArgs.scheme || 'App',
391364
'-configuration', customArgs.configuration || configuration
392365
];
393366

@@ -425,15 +398,27 @@ function getXcodeBuildArgs (projectName, projectPath, configuration, emulatorTar
425398

426399
/**
427400
* Returns array of arguments for xcodebuild
428-
* @param {String} projectName Name of xcode project
429401
* @param {String} projectPath Path to project file. Will be used to set CWD for xcodebuild
430402
* @param {String} outputPath Output directory to contain the IPA
431403
* @param {String} exportOptionsPath Path to the exportOptions.plist file
432404
* @param {Object} buildConfig Build configuration options
433405
* @return {Array} Array of arguments that could be passed directly to spawn method
434406
*/
435-
function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOptionsPath, buildConfig = {}) {
407+
function getXcodeArchiveArgs (projectPath, outputPath, exportOptionsPath, buildConfig = {}) {
436408
const options = [];
409+
const buildFlags = buildConfig.buildFlag;
410+
const customArgs = {};
411+
customArgs.otherFlags = [];
412+
413+
if (buildFlags) {
414+
if (typeof buildFlags === 'string' || buildFlags instanceof String) {
415+
parseBuildFlag(buildFlags, customArgs);
416+
} else { // buildFlags is an Array of strings
417+
buildFlags.forEach(flag => {
418+
parseBuildFlag(flag, customArgs);
419+
});
420+
}
421+
}
437422

438423
if (buildConfig.automaticProvisioning) {
439424
options.push('-allowProvisioningUpdates');
@@ -450,10 +435,10 @@ function getXcodeArchiveArgs (projectName, projectPath, outputPath, exportOption
450435

451436
return [
452437
'-exportArchive',
453-
'-archivePath', `${projectName}.xcarchive`,
438+
'-archivePath', customArgs.archivePath || 'App.xcarchive',
454439
'-exportOptionsPlist', exportOptionsPath,
455440
'-exportPath', outputPath
456-
].concat(options);
441+
].concat(options).concat(customArgs.otherFlags);
457442
}
458443

459444
function parseBuildFlag (buildFlag, args) {

lib/clean.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,15 @@
2020
const path = require('node:path');
2121
const fs = require('node:fs');
2222
const execa = require('execa');
23-
const { CordovaError } = require('cordova-common');
2423

2524
module.exports.run = function () {
2625
const projectPath = this.root;
27-
const projectName = fs.readdirSync(projectPath).filter(name => path.extname(name) === '.xcodeproj');
28-
29-
if (!projectName) {
30-
return Promise.reject(new CordovaError(`No Xcode project found in ${projectPath}`));
31-
}
3226

3327
const xcodebuildClean = configName => {
3428
return execa(
3529
'xcodebuild',
36-
['-project', projectName, '-configuration', configName, '-alltargets', 'clean'],
37-
{ cwd: projectPath, stdio: 'inherit' }
30+
['-project', 'App.xcodeproj', '-configuration', configName, '-alltargets', 'clean'],
31+
{ cwd: this.root, stdio: 'inherit' }
3832
);
3933
};
4034

0 commit comments

Comments
 (0)