Skip to content

Commit 98558ff

Browse files
author
Fatme
authored
Merge pull request #4282 from NativeScript/tdermendzhiev/native-source-code-without-plugin
Native source code and a Podfile without a plugin
2 parents f83c95e + fa3546d commit 98558ff

9 files changed

+232
-40
lines changed

lib/constants.ts

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ require("colors");
33
export const APP_FOLDER_NAME = "app";
44
export const APP_RESOURCES_FOLDER_NAME = "App_Resources";
55
export const PROJECT_FRAMEWORK_FOLDER_NAME = "framework";
6+
export const NS_BASE_PODFILE = "NSPodfileBase";
67
export const NATIVESCRIPT_KEY_NAME = "nativescript";
78
export const NODE_MODULES_FOLDER_NAME = "node_modules";
89
export const TNS_MODULES_FOLDER_NAME = "tns_modules";
@@ -43,6 +44,8 @@ export const DEPENDENCIES_JSON_NAME = "dependencies.json";
4344
export const APK_EXTENSION_NAME = ".apk";
4445
export const AAB_EXTENSION_NAME = ".aab";
4546
export const HASHES_FILE_NAME = ".nshashes";
47+
export const TNS_NATIVE_SOURCE_GROUP_NAME = "TNSNativeSource";
48+
export const NATIVE_SOURCE_FOLDER = "src";
4649

4750
export class PackageVersion {
4851
static NEXT = "next";

lib/definitions/project.d.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ interface IProjectData extends ICreateProjectData {
9292
gradleFilesDirectoryPath: string;
9393
infoPlistPath: string;
9494
buildXcconfigPath: string;
95+
podfilePath: string;
9596
/**
9697
* Defines if the project is a code sharing one.
9798
* Value is true when project has nsconfig.json and it has `shared: true` in it.
@@ -409,7 +410,7 @@ interface IPlatformProjectService extends NodeJS.EventEmitter, IPlatformProjectS
409410
getAppResourcesDestinationDirectoryPath(projectData: IProjectData): string;
410411

411412
cleanDeviceTempFolder(deviceIdentifier: string, projectData: IProjectData): Promise<void>;
412-
processConfigurationFilesFromAppResources(release: boolean, projectData: IProjectData): Promise<void>;
413+
processConfigurationFilesFromAppResources(projectData: IProjectData, opts: { release: boolean, installPods: boolean }): Promise<void>;
413414

414415
/**
415416
* Ensures there is configuration file (AndroidManifest.xml, Info.plist) in app/App_Resources.
@@ -449,7 +450,7 @@ interface IPlatformProjectService extends NodeJS.EventEmitter, IPlatformProjectS
449450
* Traverse through the production dependencies and find plugins that need build/rebuild
450451
*/
451452
checkIfPluginsNeedBuild(projectData: IProjectData): Promise<Array<any>>;
452-
453+
453454
/**
454455
* Get the deployment target's version
455456
* Currently implemented only for iOS -> returns the value of IPHONEOS_DEPLOYMENT_TARGET property from xcconfig file
@@ -484,21 +485,30 @@ interface ICocoaPodsService {
484485

485486
/**
486487
* Prepares the Podfile content of a plugin and merges it in the project's Podfile.
487-
* @param {IPluginData} pluginData Information about the plugin.
488+
* @param {string} moduleName The module which the Podfile is from.
489+
* @param {string} podfilePath The path to the podfile.
488490
* @param {IProjectData} projectData Information about the project.
489491
* @param {string} nativeProjectPath Path to the native Xcode project.
490492
* @returns {Promise<void>}
491493
*/
492-
applyPluginPodfileToProject(pluginData: IPluginData, projectData: IProjectData, nativeProjectPath: string): Promise<void>;
494+
applyPodfileToProject(moduleName: string, podfilePath: string, projectData: IProjectData, nativeProjectPath: string): Promise<void>;
493495

494496
/**
495-
* Removes plugins Podfile content from the project.
497+
* Gives the path to the plugin's Podfile.
496498
* @param {IPluginData} pluginData Information about the plugin.
497-
* @param {IProjectData} projectData Information about the project.
499+
* @returns {string} Path to plugin's Podfile
500+
*/
501+
getPluginPodfilePath(pluginData: IPluginData): string;
502+
503+
/**
504+
* Removes plugins Podfile content from the project.
505+
* @param {string} moduleName The name of the module.
506+
* @param {string} podfilePath The path to the module's Podfile.
507+
* @param {string} projectData Information about the project.
498508
* @param {string} nativeProjectPath Path to the native Xcode project.
499509
* @returns {void}
500510
*/
501-
removePluginPodfileFromProject(pluginData: IPluginData, projectData: IProjectData, nativeProjectPath: string): void;
511+
removePodfileFromProject(moduleName: string, podfilePath: string, projectData: IProjectData, nativeProjectPath: string): void;
502512

503513
/**
504514
* Gives the path to project's Podfile.

lib/project-data.ts

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class ProjectData implements IProjectData {
5959
public appGradlePath: string;
6060
public gradleFilesDirectoryPath: string;
6161
public buildXcconfigPath: string;
62+
public podfilePath: string;
6263
public isShared: boolean;
6364

6465
constructor(private $fs: IFileSystem,
@@ -132,6 +133,7 @@ export class ProjectData implements IProjectData {
132133
this.appGradlePath = path.join(this.gradleFilesDirectoryPath, constants.APP_GRADLE_FILE_NAME);
133134
this.infoPlistPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.INFO_PLIST_FILE_NAME);
134135
this.buildXcconfigPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.BUILD_XCCONFIG_FILE_NAME);
136+
this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME);
135137
this.isShared = !!(this.nsConfig && this.nsConfig.shared);
136138
return;
137139
}

lib/services/cocoapods-service.ts

+18-19
Original file line numberDiff line numberDiff line change
@@ -52,39 +52,38 @@ export class CocoaPodsService implements ICocoaPodsService {
5252
return podInstallResult;
5353
}
5454

55-
public async applyPluginPodfileToProject(pluginData: IPluginData, projectData: IProjectData, nativeProjectPath: string): Promise<void> {
56-
const pluginPodFilePath = this.getPluginPodfilePath(pluginData);
57-
if (!this.$fs.exists(pluginPodFilePath)) {
55+
public async applyPodfileToProject(moduleName: string, podfilePath: string, projectData: IProjectData, nativeProjectPath: string): Promise<void> {
56+
if (!this.$fs.exists(podfilePath)) {
57+
this.removePodfileFromProject(moduleName, podfilePath, projectData, nativeProjectPath);
5858
return;
5959
}
6060

61-
const { pluginPodfileContent, replacedFunctions } = this.buildPodfileContent(pluginPodFilePath, pluginData.name);
61+
const { podfileContent, replacedFunctions } = this.buildPodfileContent(podfilePath, moduleName);
6262
const pathToProjectPodfile = this.getProjectPodfilePath(nativeProjectPath);
6363
const projectPodfileContent = this.$fs.exists(pathToProjectPodfile) ? this.$fs.readText(pathToProjectPodfile).trim() : "";
6464

65-
if (projectPodfileContent.indexOf(pluginPodfileContent) === -1) {
65+
if (projectPodfileContent.indexOf(podfileContent) === -1) {
6666
// Remove old occurences of the plugin from the project's Podfile.
67-
this.removePluginPodfileFromProject(pluginData, projectData, nativeProjectPath);
67+
this.removePodfileFromProject(moduleName, podfilePath, projectData, nativeProjectPath);
6868
let finalPodfileContent = this.$fs.exists(pathToProjectPodfile) ? this.getPodfileContentWithoutTarget(projectData, this.$fs.readText(pathToProjectPodfile)) : "";
6969

70-
if (pluginPodfileContent.indexOf(CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME) !== -1) {
71-
finalPodfileContent = this.addPostInstallHook(replacedFunctions, finalPodfileContent, pluginPodfileContent);
70+
if (podfileContent.indexOf(CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME) !== -1) {
71+
finalPodfileContent = this.addPostInstallHook(replacedFunctions, finalPodfileContent, podfileContent);
7272
}
7373

74-
finalPodfileContent = `${pluginPodfileContent}${EOL}${finalPodfileContent}`;
74+
finalPodfileContent = `${podfileContent}${EOL}${finalPodfileContent}`;
7575
this.saveProjectPodfile(projectData, finalPodfileContent, nativeProjectPath);
7676
}
7777
}
7878

79-
public removePluginPodfileFromProject(pluginData: IPluginData, projectData: IProjectData, projectRoot: string): void {
80-
const pluginPodfilePath = this.getPluginPodfilePath(pluginData);
79+
public removePodfileFromProject(moduleName: string, podfilePath: string, projectData: IProjectData, projectRoot: string): void {
8180

82-
if (this.$fs.exists(pluginPodfilePath) && this.$fs.exists(this.getProjectPodfilePath(projectRoot))) {
81+
if (this.$fs.exists(this.getProjectPodfilePath(projectRoot))) {
8382
let projectPodFileContent = this.$fs.readText(this.getProjectPodfilePath(projectRoot));
8483
// Remove the data between #Begin Podfile and #EndPodfile
85-
const regExpToRemove = new RegExp(`${this.getPluginPodfileHeader(pluginPodfilePath)}[\\s\\S]*?${this.getPluginPodfileEnd()}`, "mg");
84+
const regExpToRemove = new RegExp(`${this.getPluginPodfileHeader(podfilePath)}[\\s\\S]*?${this.getPluginPodfileEnd()}`, "mg");
8685
projectPodFileContent = projectPodFileContent.replace(regExpToRemove, "");
87-
projectPodFileContent = this.removePostInstallHook(pluginData, projectPodFileContent);
86+
projectPodFileContent = this.removePostInstallHook(moduleName, projectPodFileContent);
8887

8988
const defaultPodfileBeginning = this.getPodfileHeader(projectData.projectName);
9089
const defaultContentWithPostInstallHook = `${defaultPodfileBeginning}${EOL}${this.getPostInstallHookHeader()}end${EOL}end`;
@@ -98,7 +97,7 @@ export class CocoaPodsService implements ICocoaPodsService {
9897
}
9998
}
10099

101-
private getPluginPodfilePath(pluginData: IPluginData): string {
100+
public getPluginPodfilePath(pluginData: IPluginData): string {
102101
const pluginPlatformsFolderPath = pluginData.pluginPlatformsFolderPath(PluginNativeDirNames.iOS);
103102
const pluginPodFilePath = path.join(pluginPlatformsFolderPath, PODFILE_NAME);
104103
return pluginPodFilePath;
@@ -157,8 +156,8 @@ export class CocoaPodsService implements ICocoaPodsService {
157156
this.$fs.writeFile(projectPodfilePath, contentToWrite);
158157
}
159158

160-
private removePostInstallHook(pluginData: IPluginData, projectPodFileContent: string): string {
161-
const regExp = new RegExp(`^.*?${this.getHookBasicFuncNameForPlugin(CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME, pluginData.name)}.*?$\\r?\\n`, "gm");
159+
private removePostInstallHook(moduleName: string, projectPodFileContent: string): string {
160+
const regExp = new RegExp(`^.*?${this.getHookBasicFuncNameForPlugin(CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME, moduleName)}.*?$\\r?\\n`, "gm");
162161
projectPodFileContent = projectPodFileContent.replace(regExp, "");
163162
return projectPodFileContent;
164163
}
@@ -206,12 +205,12 @@ export class CocoaPodsService implements ICocoaPodsService {
206205
return `${CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME} do |${CocoaPodsService.INSTALLER_BLOCK_PARAMETER_NAME}|${EOL}`;
207206
}
208207

209-
private buildPodfileContent(pluginPodFilePath: string, pluginName: string): { pluginPodfileContent: string, replacedFunctions: IRubyFunction[] } {
208+
private buildPodfileContent(pluginPodFilePath: string, pluginName: string): { podfileContent: string, replacedFunctions: IRubyFunction[] } {
210209
const pluginPodfileContent = this.$fs.readText(pluginPodFilePath);
211210
const { replacedContent, newFunctions: replacedFunctions } = this.replaceHookContent(CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME, pluginPodfileContent, pluginName);
212211

213212
return {
214-
pluginPodfileContent: `${this.getPluginPodfileHeader(pluginPodFilePath)}${EOL}${replacedContent}${EOL}${this.getPluginPodfileEnd()}`,
213+
podfileContent: `${this.getPluginPodfileHeader(pluginPodFilePath)}${EOL}${replacedContent}${EOL}${this.getPluginPodfileEnd()}`,
215214
replacedFunctions
216215
};
217216
}

lib/services/ios-project-service.ts

+26-8
Original file line numberDiff line numberDiff line change
@@ -771,28 +771,39 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
771771
this.$logger.trace(`Images to remove from xcode project: ${imagesToRemove.join(", ")}`);
772772
_.each(imagesToRemove, image => project.removeResourceFile(path.join(this.getAppResourcesDestinationDirectoryPath(projectData), image)));
773773

774+
await this.prepareNativeSourceCode(constants.TNS_NATIVE_SOURCE_GROUP_NAME, path.join(projectData.getAppResourcesDirectoryPath(), constants.APP_RESOURCES_FOLDER_NAME, this.getPlatformData(projectData).normalizedPlatformName, constants.NATIVE_SOURCE_FOLDER), projectData);
775+
774776
this.savePbxProj(project, projectData);
775777
}
778+
776779
}
777780

778781
public prepareAppResources(appResourcesDirectoryPath: string, projectData: IProjectData): void {
779782
const platformFolder = path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName);
780783
const filterFile = (filename: string) => this.$fs.deleteFile(path.join(platformFolder, filename));
781784

782785
filterFile(this.getPlatformData(projectData).configurationFileName);
786+
filterFile(constants.PODFILE_NAME);
787+
788+
// src folder should not be copied as the pbxproject will have references to its files
789+
this.$fs.deleteDirectory(path.join(appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, constants.NATIVE_SOURCE_FOLDER));
783790

784791
this.$fs.deleteDirectory(this.getAppResourcesDestinationDirectoryPath(projectData));
785792
}
786793

787-
public async processConfigurationFilesFromAppResources(release: boolean, projectData: IProjectData): Promise<void> {
788-
await this.mergeInfoPlists({ release }, projectData);
794+
public async processConfigurationFilesFromAppResources(projectData: IProjectData, opts: { release: boolean, installPods: boolean }): Promise<void> {
795+
await this.mergeInfoPlists({ release: opts.release }, projectData);
789796
await this.$iOSEntitlementsService.merge(projectData);
790-
await this.mergeProjectXcconfigFiles(release, projectData);
797+
await this.mergeProjectXcconfigFiles(opts.release, projectData);
791798
for (const pluginData of await this.getAllInstalledPlugins(projectData)) {
792799
await this.$pluginVariablesService.interpolatePluginVariables(pluginData, this.getPlatformData(projectData).configurationFilePath, projectData.projectDir);
793800
}
794801

795802
this.$pluginVariablesService.interpolateAppIdentifier(this.getPlatformData(projectData).configurationFilePath, projectData.projectIdentifiers.ios);
803+
804+
if (opts.installPods) {
805+
await this.installPodsIfAny(projectData);
806+
}
796807
}
797808

798809
private getInfoPlistPath(projectData: IProjectData): string {
@@ -955,7 +966,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
955966
await this.prepareStaticLibs(pluginPlatformsFolderPath, pluginData, projectData);
956967

957968
const projectRoot = this.getPlatformData(projectData).projectRoot;
958-
await this.$cocoapodsService.applyPluginPodfileToProject(pluginData, projectData, projectRoot);
969+
await this.$cocoapodsService.applyPodfileToProject(pluginData.name, this.$cocoapodsService.getPluginPodfilePath(pluginData), projectData, projectRoot);
959970
}
960971

961972
public async removePluginNativeCode(pluginData: IPluginData, projectData: IProjectData): Promise<void> {
@@ -966,12 +977,17 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
966977
this.removeStaticLibs(pluginPlatformsFolderPath, pluginData, projectData);
967978
const projectRoot = this.getPlatformData(projectData).projectRoot;
968979

969-
this.$cocoapodsService.removePluginPodfileFromProject(pluginData, projectData, projectRoot);
980+
this.$cocoapodsService.removePodfileFromProject(pluginData.name, this.$cocoapodsService.getPluginPodfilePath(pluginData), projectData, projectRoot);
970981
}
971982

972983
public async afterPrepareAllPlugins(projectData: IProjectData): Promise<void> {
984+
await this.installPodsIfAny(projectData);
985+
}
986+
987+
public async installPodsIfAny(projectData: IProjectData): Promise<void> {
973988
const projectRoot = this.getPlatformData(projectData).projectRoot;
974-
if (this.$fs.exists(this.$cocoapodsService.getProjectPodfilePath(projectRoot))) {
989+
const mainPodfilePath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, constants.PODFILE_NAME);
990+
if (this.$fs.exists(this.$cocoapodsService.getProjectPodfilePath(projectRoot)) || this.$fs.exists(mainPodfilePath)) {
975991
const xcodeProjPath = this.getXcodeprojPath(projectData);
976992
const xcuserDataPath = path.join(xcodeProjPath, "xcuserdata");
977993
const sharedDataPath = path.join(xcodeProjPath, "xcshareddata");
@@ -984,6 +1000,8 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
9841000
await this.$childProcess.exec(createSchemeRubyScript, { cwd: this.getPlatformData(projectData).projectRoot });
9851001
}
9861002

1003+
await this.$cocoapodsService.applyPodfileToProject(constants.NS_BASE_PODFILE, mainPodfilePath, projectData, this.getPlatformData(projectData).projectRoot);
1004+
9871005
await this.$cocoapodsService.executePodInstall(projectRoot, xcodeProjPath);
9881006
}
9891007
}
@@ -1094,9 +1112,9 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
10941112
this.$fs.rename(path.join(fileRootLocation, oldFileName), path.join(fileRootLocation, newFileName));
10951113
}
10961114

1097-
private async prepareNativeSourceCode(pluginName: string, pluginPlatformsFolderPath: string, projectData: IProjectData): Promise<void> {
1115+
private async prepareNativeSourceCode(groupName: string, sourceFolderPath: string, projectData: IProjectData): Promise<void> {
10981116
const project = this.createPbxProj(projectData);
1099-
const group = this.getRootGroup(pluginName, pluginPlatformsFolderPath);
1117+
const group = this.getRootGroup(groupName, sourceFolderPath);
11001118
project.addPbxGroup(group.files, group.name, group.path, null, { isMain: true });
11011119
project.addToHeaderSearchPaths(group.path);
11021120
this.savePbxProj(project, projectData);

lib/services/prepare-platform-native-service.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ export class PreparePlatformNativeService extends PreparePlatformService impleme
4242
await config.platformData.platformProjectService.prepareProject(config.projectData, config.platformSpecificData);
4343
}
4444

45-
if (!config.changesInfo || config.changesInfo.modulesChanged) {
45+
const shouldPrepareModules = !config.changesInfo || config.changesInfo.modulesChanged;
46+
47+
if (shouldPrepareModules) {
4648
await this.$pluginsService.validate(config.platformData, config.projectData);
4749

4850
const appDestinationDirectoryPath = path.join(config.platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
@@ -63,7 +65,8 @@ export class PreparePlatformNativeService extends PreparePlatformService impleme
6365
}
6466

6567
if (!config.changesInfo || config.changesInfo.configChanged || config.changesInfo.modulesChanged) {
66-
await config.platformData.platformProjectService.processConfigurationFilesFromAppResources(config.appFilesUpdaterOptions.release, config.projectData);
68+
// Passing !shouldPrepareModules` we assume that if the node modules are prepared base Podfile content is added and `pod install` is executed.
69+
await config.platformData.platformProjectService.processConfigurationFilesFromAppResources(config.projectData, {release:config.appFilesUpdaterOptions.release, installPods: !shouldPrepareModules});
6770
}
6871

6972
config.platformData.platformProjectService.interpolateConfigurationFile(config.projectData, config.platformSpecificData);

test/cocoapods-service.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ end`,
511511
it(testCase.testCaseDescription, async () => {
512512
mockFileSystem(testInjector, testCase.input, testCase.projectPodfileContent);
513513

514-
await cocoapodsService.applyPluginPodfileToProject(testCase.pluginData || mockPluginData, mockProjectData, nativeProjectPath);
514+
await cocoapodsService.applyPodfileToProject(testCase.pluginData ? testCase.pluginData.name : mockPluginData.name, cocoapodsService.getPluginPodfilePath(testCase.pluginData || mockPluginData), mockProjectData, nativeProjectPath);
515515

516516
assert.deepEqual(changeNewLineCharacter(newPodfileContent), changeNewLineCharacter(testCase.output));
517517
});
@@ -720,7 +720,7 @@ end`
720720
it(testCase.testCaseDescription, async () => {
721721
mockFileSystem(testInjector, testCase.input, testCase.projectPodfileContent);
722722

723-
cocoapodsService.removePluginPodfileFromProject(mockPluginData, mockProjectData, nativeProjectPath);
723+
cocoapodsService.removePodfileFromProject(mockPluginData.name, cocoapodsService.getPluginPodfilePath(mockPluginData), mockProjectData, nativeProjectPath);
724724

725725
assert.deepEqual(changeNewLineCharacter(newPodfileContent), changeNewLineCharacter(testCase.output));
726726
});

0 commit comments

Comments
 (0)