Skip to content

Commit

Permalink
feat!: Pull in CordovaLib with SwiftPM
Browse files Browse the repository at this point in the history
  • Loading branch information
dpogue committed Sep 25, 2024
1 parent d6100b8 commit 849cfe1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 126 deletions.
80 changes: 17 additions & 63 deletions lib/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,8 @@ class ProjectCreator {
create () {
this.provideProjectTemplate();
this.provideCordovaJs();
this.provideCordovaLib();
this.provideBuildScripts();
this.updateBundleSettings();
this.updateProjectSettings();
}

provideProjectTemplate () {
Expand All @@ -92,85 +91,40 @@ class ProjectCreator {
);
}

provideCordovaLib () {
this.copyOrLinkCordovaLib();
this.configureCordovaLibPath();
}

provideBuildScripts () {
const srcScriptsDir = path.join(ROOT, 'templates', 'cordova');
const destScriptsDir = this.projectPath('cordova');
fs.cpSync(srcScriptsDir, destScriptsDir, { recursive: true });
}

updateBundleSettings () {
updateProjectSettings () {
const projectPath = this.projectPath('App.xcodeproj', 'project.pbxproj');
const xcodeproj = xcode.project(projectPath);
xcodeproj.parseSync();

xcodeproj.updateBuildProperty('PRODUCT_NAME', `"${this.project.name}"`, null, 'App');
xcodeproj.updateBuildProperty('PRODUCT_BUNDLE_IDENTIFIER', `"${this.project.id}"`, null, 'App');

fs.writeFileSync(projectPath, xcodeproj.writeSync());
}

copyOrLinkCordovaLib () {
const cordovaLibPathSrc = path.join(ROOT, 'CordovaLib');
const cordovaLibPathDest = this.projectPath('CordovaLib');

if (this.options.linkLib) {
// Symlink not used in project file, but is currently required for plugman because
// it reads the VERSION file from it (instead of using the cordova/version script
// like it should).
fs.symlinkSync(cordovaLibPathSrc, cordovaLibPathDest);
} else {
fs.cpSync(cordovaLibPathSrc, cordovaLibPathDest, { recursive: true });
}
}

configureCordovaLibPath () {
// CordovaLib could be a symlink, so we resolve it
const cdvLibRealPath = fs.realpathSync(this.projectPath('CordovaLib'));

const cdvLibXcodeAbsPath = path.join(cdvLibRealPath, 'CordovaLib.xcodeproj');
let cdvLibXcodePath = path.relative(this.project.path, cdvLibXcodeAbsPath);

if (path.sep !== path.posix.sep) {
// If the Cordova project is being created on Windows, we need to
// make sure the Xcode project file uses POSIX-style paths or else
// Xcode considers it invalid
cdvLibXcodePath = cdvLibXcodePath.replace(path.sep, path.posix.sep);
}

// Replace magic line in project.pbxproj
const pbxprojPath = this.projectPath('App.xcodeproj', 'project.pbxproj');
transformFileContents(pbxprojPath, contents => {
const regex = /(.+CordovaLib.xcodeproj.+PBXFileReference.+wrapper.pb-project.+)(path = .+?;)(.*)(sourceTree.+;)(.+)/;
const line = contents.split(/\r?\n/)
.find(l => regex.test(l));

if (!line) {
throw new Error(`Entry not found in project file for sub-project: ${cdvLibXcodePath}`);
}

let newLine = line
.replace(/path = .+?;/, `path = ${cdvLibXcodePath};`)
.replace(/sourceTree.+?;/, 'sourceTree = "<group>";');

if (!newLine.match('name')) {
newLine = newLine.replace('path = ', 'name = CordovaLib.xcodeproj; path = ');
// Update the CordovaLib Swift package reference path
const pkgRefs = xcodeproj.hash.project.objects.XCLocalSwiftPackageReference;
if (pkgRefs) {
for (const [key, ref] of Object.entries(pkgRefs)) {
/* istanbul ignore if */
if (key.endsWith('_comment')) {
continue;
}

if (ref.relativePath?.match(/\/cordova-ios/)) {
ref.relativePath = `"${path.relative(this.project.path, ROOT).replaceAll(path.sep, path.posix.sep)}"`;
break;
}
}
}

return contents.replace(line, newLine);
});
fs.writeFileSync(projectPath, xcodeproj.writeSync());
}

projectPath (...projectRelativePaths) {
return path.join(this.project.path, ...projectRelativePaths);
}
}

function transformFileContents (file, transform) {
const contents = fs.readFileSync(file, 'utf-8');
fs.writeFileSync(file, transform(contents));
}
79 changes: 22 additions & 57 deletions templates/project/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
objects = {

/* Begin PBXBuildFile section */
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 */; };
90A914592CA3D370003DB979 /* CordovaLib in Frameworks */ = {isa = PBXBuildFile; productRef = 90A914582CA3D370003DB979 /* CordovaLib */; };
90BD9B7A2C06907D000DEBAB /* Base in Resources */ = {isa = PBXBuildFile; fileRef = 90BD9B792C06907D000DEBAB /* Base */; };
90BD9B7C2C06907E000DEBAB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 90BD9B7B2C06907E000DEBAB /* Assets.xcassets */; };
90BD9B7F2C06907E000DEBAB /* Base in Resources */ = {isa = PBXBuildFile; fileRef = 90BD9B7E2C06907E000DEBAB /* Base */; };
Expand All @@ -37,31 +37,13 @@
90CBB52C2C06968500B805A2 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90CBB52B2C06968500B805A2 /* ViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
907F985C2C06B8DE00D2D242 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 907F98572C06B8DE00D2D242 /* CordovaLib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 68A32D7114102E1C006B237C;
remoteInfo = CordovaLib;
};
907F985E2C06B8DE00D2D242 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 907F98572C06B8DE00D2D242 /* CordovaLib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = C0C01EB21E3911D50056E6CB;
remoteInfo = Cordova;
};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */
902AE2152C6C059A0041150F /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
902AE2142C6C059A0041150F /* Cordova.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -72,13 +54,12 @@
9040B1872C6DD3EB00662C5D /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
9040B1882C6DD41B00662C5D /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; name = www; path = ../../www; sourceTree = "<group>"; };
907F98552C06B87200D2D242 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
907F98572C06B8DE00D2D242 /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
907F98622C06B97000D2D242 /* Entitlements-Debug.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Entitlements-Debug.plist"; sourceTree = "<group>"; };
907F98632C06B9C800D2D242 /* Entitlements-Release.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Entitlements-Release.plist"; sourceTree = "<group>"; };
907F98652C06BC1B00D2D242 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
907F98692C06BCD300D2D242 /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; };
9080B40F2C6DD7EC00078F33 /* config.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = config.xml; path = ../../config.xml; sourceTree = "<group>"; };
90BD9B6C2C06907D000DEBAB /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
90BD9B6C2C06907D000DEBAB /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
90BD9B792C06907D000DEBAB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
90BD9B7B2C06907E000DEBAB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
90BD9B7E2C06907E000DEBAB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/CDVLaunchScreen.storyboard; sourceTree = "<group>"; };
Expand All @@ -99,6 +80,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
90A914592CA3D370003DB979 /* CordovaLib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -119,15 +101,6 @@
path = Plugins;
sourceTree = "<group>";
};
907F98582C06B8DE00D2D242 /* Products */ = {
isa = PBXGroup;
children = (
907F985D2C06B8DE00D2D242 /* libCordova.a */,
907F985F2C06B8DE00D2D242 /* Cordova.framework */,
);
name = Products;
sourceTree = "<group>";
};
907F98602C06B8F000D2D242 /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -158,7 +131,6 @@
90BD9B632C06907D000DEBAB = {
isa = PBXGroup;
children = (
907F98572C06B8DE00D2D242 /* CordovaLib.xcodeproj */,
9080B40F2C6DD7EC00078F33 /* config.xml */,
9040B1882C6DD41B00662C5D /* www */,
90BD9B6E2C06907D000DEBAB /* App */,
Expand Down Expand Up @@ -196,7 +168,7 @@
9080B40D2C6DD79000078F33 /* config */,
9080B40E2C6DD7A100078F33 /* staging */,
);
path = "App";
path = App;
sourceTree = "<group>";
};
/* End PBXGroup section */
Expand All @@ -215,10 +187,11 @@
);
dependencies = (
);
name = "App";
name = App;
packageProductDependencies = (
90A914582CA3D370003DB979 /* CordovaLib */,
);
productName = "App";
productName = App;
productReference = 90BD9B6C2C06907D000DEBAB /* App.app */;
productType = "com.apple.product-type.application";
};
Expand Down Expand Up @@ -247,39 +220,17 @@
);
mainGroup = 90BD9B632C06907D000DEBAB;
packageReferences = (
90A914572CA3D370003DB979 /* XCLocalSwiftPackageReference "../../../cordova-ios" */,
);
productRefGroup = 90BD9B6D2C06907D000DEBAB /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 907F98582C06B8DE00D2D242 /* Products */;
ProjectRef = 907F98572C06B8DE00D2D242 /* CordovaLib.xcodeproj */;
},
);
projectRoot = "";
targets = (
90BD9B6B2C06907D000DEBAB /* App */,
);
};
/* End PBXProject section */

/* Begin PBXReferenceProxy section */
907F985D2C06B8DE00D2D242 /* libCordova.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libCordova.a;
remoteRef = 907F985C2C06B8DE00D2D242 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
907F985F2C06B8DE00D2D242 /* Cordova.framework */ = {
isa = PBXReferenceProxy;
fileType = wrapper.framework;
path = Cordova.framework;
remoteRef = 907F985E2C06B8DE00D2D242 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */

/* Begin PBXResourcesBuildPhase section */
90BD9B6A2C06907D000DEBAB /* Resources */ = {
isa = PBXResourcesBuildPhase;
Expand Down Expand Up @@ -551,6 +502,20 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
90A914572CA3D370003DB979 /* XCLocalSwiftPackageReference "../../../cordova-ios" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "../../../cordova-ios";
};
/* End XCLocalSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
90A914582CA3D370003DB979 /* CordovaLib */ = {
isa = XCSwiftPackageProductDependency;
productName = CordovaLib;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 90BD9B642C06907D000DEBAB /* Project object */;
}
1 change: 0 additions & 1 deletion tests/spec/createAndBuild.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ function verifyProjectFiles (tmpDir, projectName) {
expect(fs.existsSync(path.join(tmpDir, 'App'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'App.xcodeproj'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'App.xcworkspace'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'CordovaLib'))).toBe(true);
}

/**
Expand Down
24 changes: 19 additions & 5 deletions tests/spec/unit/create.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,28 @@ function verifyProjectFiles (tmpDir, projectName) {
expect(fs.existsSync(path.join(tmpDir, 'App'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'App.xcodeproj'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'App.xcworkspace'))).toBe(true);
expect(fs.existsSync(path.join(tmpDir, 'CordovaLib'))).toBe(true);

const pbxproj = path.join(tmpDir, 'App.xcodeproj', 'project.pbxproj');
const pbxcontents = fs.readFileSync(pbxproj, 'utf-8');
const regex = /(.+CordovaLib.xcodeproj.+PBXFileReference.+wrapper.pb-project.+)(path = .+?;)(.*)(sourceTree.+;)(.+)/;
const line = pbxcontents.split(/\r?\n/).find(l => regex.test(l));
const xcodeproj = xcode.project(pbxproj);
xcodeproj.parseSync();

expect(line).toMatch(/path = CordovaLib\/CordovaLib.xcodeproj;/);
const packageLoc = path.dirname(require.resolve('../../../package.json'));
const relativePath = path.relative(tmpDir, packageLoc).replaceAll(path.sep, path.posix.sep);

let foundRef = false;
const pkgRefs = xcodeproj.hash.project.objects.XCLocalSwiftPackageReference;
for (const [key, ref] of Object.entries(pkgRefs)) {
if (key.endsWith('_COMMENT')) {
continue;
}

if (ref.relativePath.match(/\/cordova-ios/)) {
foundRef = true;
expect(ref.relativePath).toMatch(relativePath);
break;
}
}
expect(foundRef).toBeTruthy();
}

/**
Expand Down

0 comments on commit 849cfe1

Please sign in to comment.