Skip to content

Commit

Permalink
fix(create): Copy config.xml data during creation
Browse files Browse the repository at this point in the history
This ensures that by the time plugin installation happens, the
preferences from the root application config.xml can be read as
expected.

Closes GH-1422.
  • Loading branch information
dpogue committed Nov 11, 2024
1 parent 18a80d2 commit 2c94f45
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 10 deletions.
2 changes: 0 additions & 2 deletions lib/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,6 @@ class Api {
* @param {Object} [options] An options object. The most common options are:
* @param {String} [options.customTemplate] A path to custom template, that
* should override the default one from platform.
* @param {Boolean} [options.link] Flag that indicates that platform's
* sources will be linked to installed platform instead of copying.
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
* logging purposes. If no EventEmitter provided, all events will be logged to
* console
Expand Down
26 changes: 22 additions & 4 deletions lib/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

const path = require('node:path');
const fs = require('node:fs');
const { CordovaError, events } = require('cordova-common');
const { ConfigParser, CordovaError, events, xmlHelpers } = require('cordova-common');
const xcode = require('xcode');
const pkg = require('../package');

Expand All @@ -31,10 +31,11 @@ const ROOT = path.join(__dirname, '..');
* @param {string} project_path Path to your new Cordova iOS project
* @param {string} package_name Package name, following reverse-domain style convention
* @param {string} project_name Project name
* @param {{ link: boolean, customTemplate: string }} opts Project creation options
* @param {{ customTemplate: string }} opts Project creation options
* @param {ConfigParser} root_config The application config.xml
* @returns {Promise<void>} resolves when the project has been created
*/
exports.createProject = async (project_path, package_name, project_name, opts) => {
exports.createProject = async (project_path, package_name, project_name, opts, root_config) => {
package_name = package_name || 'my.cordova.project';
project_name = project_name || 'CordovaExample';

Expand All @@ -56,7 +57,7 @@ exports.createProject = async (project_path, package_name, project_name, opts) =
},
options: {
templatePath: opts.customTemplate || path.join(ROOT, 'templates', 'project'),
linkLib: !!opts.link
rootConfig: root_config
}
}).create();

Expand All @@ -73,6 +74,7 @@ class ProjectCreator {
this.provideCordovaJs();
this.provideBuildScripts();
this.updateProjectSettings();
this.updatePlatformConfigFile();
}

provideProjectTemplate () {
Expand All @@ -97,6 +99,17 @@ class ProjectCreator {
fs.cpSync(srcScriptsDir, destScriptsDir, { recursive: true });
}

updatePlatformConfigFile () {
const defaultXmlPath = this.projectPath('cordova', 'defaults.xml');
const configXmlPath = this.projectPath('App', 'config.xml');

fs.cpSync(defaultXmlPath, configXmlPath);

const config = new ConfigParser(configXmlPath);
xmlHelpers.mergeXml(this.options.rootConfig.doc.getroot(), config.doc.getroot(), 'ios', /* clobber= */true);
config.write();
}

updateProjectSettings () {
const projectPath = this.projectPath('App.xcodeproj', 'project.pbxproj');
const xcodeproj = xcode.project(projectPath);
Expand All @@ -105,6 +118,11 @@ class ProjectCreator {
xcodeproj.updateBuildProperty('PRODUCT_NAME', `"${this.project.name}"`, null, 'App');
xcodeproj.updateBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', `"${this.project.id}"`, null, 'App');

const deploymentTarget = this.options.rootConfig.getPreference('deployment-target', 'ios');
if (deploymentTarget) {
xcodeproj.updateBuildProperty('IPHONEOS_DEPLOYMENT_TARGET', deploymentTarget);
}

// Update the CordovaLib Swift package reference path
const pkgRefs = xcodeproj.hash.project.objects.XCLocalSwiftPackageReference;
if (pkgRefs) {
Expand Down
7 changes: 6 additions & 1 deletion tests/spec/createAndBuild.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const xcode = require('xcode');
const { ConfigParser } = require('cordova-common');
const create = require('../../lib/create');

const makeTempDir = () => path.join(
fs.realpathSync(os.tmpdir()),
`cordova-ios-create-test-${Date.now()}`
);

const defaultConfigXmlPath = path.join(__dirname, '..', '..', 'templates', 'project', 'App', 'config.xml');

/**
* Verifies that some of the project file exists. Not all will be tested.
* E.g. App's resource directory, xcodeproj, xcworkspace, and CordovaLib.
Expand Down Expand Up @@ -90,7 +93,9 @@ function verifyBuild (tmpDir) {
* @returns {Promise}
*/
async function verifyCreateAndBuild (tmpDir, packageName, projectName) {
await create.createProject(tmpDir, packageName, projectName, {}, undefined)
const configXml = new ConfigParser(defaultConfigXmlPath);

await create.createProject(tmpDir, packageName, projectName, {}, configXml)
.then(() => verifyProjectFiles(tmpDir, projectName))
.then(() => verifyProjectBundleIdentifier(tmpDir, projectName, packageName))
.then(() => verifyBuild(tmpDir));
Expand Down
27 changes: 25 additions & 2 deletions tests/spec/unit/create.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const xcode = require('xcode');
const { ConfigParser } = require('cordova-common');
const create = require('../../../lib/create');

const makeTempDir = () => path.join(
fs.realpathSync(os.tmpdir()),
`cordova-ios-create-test-${Date.now()}`
);

const defaultConfigXmlPath = path.join(__dirname, '..', '..', '..', 'templates', 'project', 'App', 'config.xml');

/**
* Verifies that some of the project file exists. Not all will be tested.
* E.g. App's resource directory, xcodeproj, xcworkspace, and CordovaLib.
Expand Down Expand Up @@ -82,6 +85,15 @@ function verifyProjectBundleIdentifier (tmpDir, projectName, expectedBundleIdent
expect(actualBundleName).toBe(`"${projectName}"`);
}

function verifyProjectDeploymentTarget (tmpDir, expectedTarget) {
const pbxproj = path.join(tmpDir, 'App.xcodeproj', 'project.pbxproj');
const xcodeproj = xcode.project(pbxproj);
xcodeproj.parseSync();

const actualDeploymentTarget = xcodeproj.getBuildProperty('IPHONEOS_DEPLOYMENT_TARGET');
expect(actualDeploymentTarget).toBe(expectedTarget);
}

/**
* Runs various project creation checks.
*
Expand All @@ -90,8 +102,10 @@ function verifyProjectBundleIdentifier (tmpDir, projectName, expectedBundleIdent
* @param {String} projectName
* @returns {Promise}
*/
async function verifyCreatedProject (tmpDir, packageName, projectName) {
await create.createProject(tmpDir, packageName, projectName, {}, undefined)
async function verifyCreatedProject (tmpDir, packageName, projectName, configFile = defaultConfigXmlPath) {
const configXml = new ConfigParser(configFile);

await create.createProject(tmpDir, packageName, projectName, {}, configXml)
.then(() => verifyProjectFiles(tmpDir, projectName))
.then(() => verifyProjectBundleIdentifier(tmpDir, projectName, packageName));
}
Expand All @@ -118,4 +132,13 @@ describe('create', () => {
const projectName = '応応応応 hello & إثرا 用用用用';
return verifyCreatedProject(tmpDir, packageName, projectName);
});

it('should copy config.xml into the newly created project', () => {
const configPath = path.join(__dirname, 'fixtures', 'test-config-3.xml');
const packageName = 'io.cordova.hellocordova.ios';
const projectName = 'Hello Cordova';

return verifyCreatedProject(tmpDir, packageName, projectName, configPath)
.then(() => verifyProjectDeploymentTarget(tmpDir, '15.0'));
});
});
2 changes: 1 addition & 1 deletion tests/spec/unit/fixtures/test-config-3.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<platform name="ios">
<preference name="orientation" value="all" />
<preference name="target-device" value="handset" />
<preference name="deployment-target" value="13.0" />
<preference name="deployment-target" value="15.0" />
<preference name="SwiftVersion" value="4.1" />
</platform>

Expand Down

0 comments on commit 2c94f45

Please sign in to comment.