Skip to content

Commit 7d47700

Browse files
committed
feat(iOS): Support .xcframework bundles
1 parent 77de5b5 commit 7d47700

File tree

1 file changed

+38
-11
lines changed

1 file changed

+38
-11
lines changed

lib/services/ios-project-service.ts

+38-11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface INativeSourceCodeGroup {
2323

2424
const DevicePlatformSdkName = "iphoneos";
2525
const SimulatorPlatformSdkName = "iphonesimulator";
26+
const FRAMEWORK_EXTENSIONS = [".framework", ".xcframework"];
2627

2728
const getPlatformSdkName = (forDevice: boolean): string => forDevice ? DevicePlatformSdkName : SimulatorPlatformSdkName;
2829
const getConfigurationName = (release: boolean): string => release ? Configurations.Release : Configurations.Debug;
@@ -89,7 +90,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
8990
};
9091
},
9192
frameworkFilesExtensions: [".a", ".framework", ".bin"],
92-
frameworkDirectoriesExtensions: [".framework"],
93+
frameworkDirectoriesExtensions: FRAMEWORK_EXTENSIONS,
9394
frameworkDirectoriesNames: ["Metadata", "metadataGenerator", "NativeScript", "internal"],
9495
targetedOS: ['darwin'],
9596
configurationFileName: constants.INFO_PLIST_FILE_NAME,
@@ -155,6 +156,9 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
155156
this.replaceFileName("-Info.plist", projectRootFilePath, projectData);
156157
}
157158
this.replaceFileName("-Prefix.pch", projectRootFilePath, projectData);
159+
if (this.$fs.exists(path.join(projectRootFilePath, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + ".entitlements"))) {
160+
this.replaceFileName(".entitlements", projectRootFilePath, projectData);
161+
}
158162

159163
const xcschemeDirPath = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IosProjectConstants.XcodeProjExtName, "xcshareddata/xcschemes");
160164
const xcschemeFilePath = path.join(xcschemeDirPath, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IosProjectConstants.XcodeSchemeExtName);
@@ -225,17 +229,38 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
225229
return Promise.resolve();
226230
}
227231

232+
private async isDynamicFramework(frameworkPath: string): Promise<boolean> {
233+
const frameworkName = path.basename(frameworkPath, path.extname(frameworkPath));
234+
const isDynamicFrameworkBundle = async (bundlePath: string) => {
235+
const frameworkBinaryPath = path.join(bundlePath, frameworkName);
236+
237+
return _.includes((await this.$childProcess.spawnFromEvent("file", [frameworkBinaryPath], "close")).stdout, "dynamically linked");
238+
};
239+
240+
if (path.extname(frameworkPath) === ".xcframework") {
241+
let isDynamic = true;
242+
const subDirs = this.$fs.readDirectory(frameworkPath).filter(entry => this.$fs.getFsStats(entry).isDirectory());
243+
for (const subDir of subDirs) {
244+
const singlePlatformFramework = path.join(subDir, frameworkName + ".framework");
245+
if (this.$fs.exists(singlePlatformFramework)) {
246+
isDynamic = await isDynamicFrameworkBundle(singlePlatformFramework);
247+
break;
248+
}
249+
}
250+
251+
return isDynamic;
252+
} else {
253+
return await isDynamicFrameworkBundle(frameworkName);
254+
}
255+
}
256+
228257
private async addFramework(frameworkPath: string, projectData: IProjectData): Promise<void> {
229258
if (!this.$hostInfo.isWindows) {
230259
this.validateFramework(frameworkPath);
231260

232261
const project = this.createPbxProj(projectData);
233-
const frameworkName = path.basename(frameworkPath, path.extname(frameworkPath));
234-
const frameworkBinaryPath = path.join(frameworkPath, frameworkName);
235-
const isDynamic = _.includes((await this.$childProcess.spawnFromEvent("file", [frameworkBinaryPath], "close")).stdout, "dynamically linked");
236262
const frameworkAddOptions: IXcode.Options = { customFramework: true };
237-
238-
if (isDynamic) {
263+
if (this.isDynamicFramework(frameworkPath)) {
239264
frameworkAddOptions["embed"] = true;
240265
}
241266

@@ -577,8 +602,10 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
577602
return target;
578603
}
579604

580-
private getAllLibsForPluginWithFileExtension(pluginData: IPluginData, fileExtension: string): string[] {
581-
const filterCallback = (fileName: string, pluginPlatformsFolderPath: string) => path.extname(fileName) === fileExtension;
605+
private getAllLibsForPluginWithFileExtension(pluginData: IPluginData, fileExtension: string | string[]): string[] {
606+
const fileExtensions = _.isArray(fileExtension) ? fileExtension : [fileExtension];
607+
const filterCallback = (fileName: string, pluginPlatformsFolderPath: string) =>
608+
fileExtensions.indexOf(path.extname(fileName)) !== -1;
582609
return this.getAllNativeLibrariesForPlugin(pluginData, IOSProjectService.IOS_PLATFORM_NAME, filterCallback);
583610
}
584611

@@ -599,7 +626,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
599626
const plistJson = this.$plistParser.parseFileSync(infoPlistPath);
600627
const packageType = plistJson["CFBundlePackageType"];
601628

602-
if (packageType !== "FMWK") {
629+
if (packageType !== "FMWK" && packageType !== "XFWK") {
603630
this.$errors.failWithoutHelp("The bundle at %s does not appear to be a dynamic framework.", libraryPath);
604631
}
605632
}
@@ -679,7 +706,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
679706
this.savePbxProj(project, projectData);
680707
}
681708
private async prepareFrameworks(pluginPlatformsFolderPath: string, pluginData: IPluginData, projectData: IProjectData): Promise<void> {
682-
for (const fileName of this.getAllLibsForPluginWithFileExtension(pluginData, ".framework")) {
709+
for (const fileName of this.getAllLibsForPluginWithFileExtension(pluginData, FRAMEWORK_EXTENSIONS)) {
683710
await this.addFramework(path.join(pluginPlatformsFolderPath, fileName), projectData);
684711
}
685712
}
@@ -700,7 +727,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
700727

701728
private removeFrameworks(pluginPlatformsFolderPath: string, pluginData: IPluginData, projectData: IProjectData): void {
702729
const project = this.createPbxProj(projectData);
703-
_.each(this.getAllLibsForPluginWithFileExtension(pluginData, ".framework"), fileName => {
730+
_.each(this.getAllLibsForPluginWithFileExtension(pluginData, FRAMEWORK_EXTENSIONS), fileName => {
704731
const relativeFrameworkPath = this.getLibSubpathRelativeToProjectPath(fileName, projectData);
705732
project.removeFramework(relativeFrameworkPath, { customFramework: true, embed: true });
706733
});

0 commit comments

Comments
 (0)