diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index cebe288593..27b44cf6ef 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -84,7 +84,7 @@ interface IPlatformService extends IBuildPlatformAction, NodeJS.EventEmitter { shouldInstall(device: Mobile.IDevice, projectData: IProjectData, release: IRelease, outputPath?: string): Promise; /** - * + * * @param {Mobile.IDevice} device The device where the application should be installed. * @param {IProjectData} projectData DTO with information about the project. * @param {string} @optional outputPath Directory containing build information and artifacts. @@ -259,9 +259,8 @@ interface IPlatformData { projectRoot: string; normalizedPlatformName: string; appDestinationDirectoryPath: string; - deviceBuildOutputPath: string; + getBuildOutputPath(options: IBuildOutputOptions): string; bundleBuildOutputPath?: string; - emulatorBuildOutputPath?: string; getValidBuildOutputData(buildOptions: IBuildOutputOptions): IValidBuildOutputData; frameworkFilesExtensions: string[]; frameworkDirectoriesExtensions?: string[]; @@ -315,7 +314,7 @@ interface INodeModulesDependenciesBuilder { interface IBuildInfo { prepareTime: string; buildTime: string; - /** + /** * Currently it is used only for iOS. * As `xcrun` command does not throw an error when IPHONEOS_DEPLOYMENT_TARGET is provided in `xcconfig` file and * the simulator's version does not match IPHONEOS_DEPLOYMENT_TARGET's value, we need to save it to buildInfo file diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index f53f16765e..0fff8c5a51 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -74,7 +74,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject appDestinationDirectoryPath: path.join(...appDestinationDirectoryArr), platformProjectService: this, projectRoot: projectRoot, - deviceBuildOutputPath: path.join(...deviceBuildOutputArr), + getBuildOutputPath: () => path.join(...deviceBuildOutputArr), bundleBuildOutputPath: path.join(projectRoot, constants.APP_FOLDER_NAME, constants.BUILD_DIR, constants.OUTPUTS_DIR, constants.BUNDLE_DIR), getValidBuildOutputData: (buildOptions: IBuildOutputOptions): IValidBuildOutputData => { const buildMode = buildOptions.release ? Configurations.Release.toLowerCase() : Configurations.Debug.toLowerCase(); @@ -332,7 +332,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject const gradleArgs = this.getGradleBuildOptions(buildConfig, projectData); const baseTask = buildConfig.androidBundle ? "bundle" : "assemble"; const platformData = this.getPlatformData(projectData); - const outputPath = buildConfig.androidBundle ? platformData.bundleBuildOutputPath : platformData.deviceBuildOutputPath; + const outputPath = buildConfig.androidBundle ? platformData.bundleBuildOutputPath : platformData.getBuildOutputPath(buildConfig); if (this.$logger.getLevel() === "TRACE") { gradleArgs.unshift("--stacktrace"); gradleArgs.unshift("--debug"); diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 6845651be2..4d583f11fd 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -2,6 +2,7 @@ import * as path from "path"; import * as shell from "shelljs"; import * as semver from "semver"; import * as constants from "../constants"; +import { Configurations } from "../common/constants"; import * as helpers from "../common/helpers"; import { attachAwaitDetach } from "../common/helpers"; import * as projectServiceBaseLib from "./platform-project-service-base"; @@ -21,6 +22,12 @@ interface INativeSourceCodeGroup { files: string[]; } +const DevicePlatformSdkName = "iphoneos"; +const SimulatorPlatformSdkName = "iphonesimulator"; + +const getPlatformSdkName = (forDevice: boolean): string => forDevice ? DevicePlatformSdkName : SimulatorPlatformSdkName; +const getConfigurationName = (release: boolean): string => release ? Configurations.Release : Configurations.Debug; + export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService { private static XCODEBUILD_MIN_VERSION = "6.0"; private static IOS_PROJECT_NAME_PLACEHOLDER = "__PROJECT_NAME__"; @@ -67,8 +74,10 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ appDestinationDirectoryPath: path.join(projectRoot, projectData.projectName), platformProjectService: this, projectRoot: projectRoot, - deviceBuildOutputPath: path.join(projectRoot, constants.BUILD_DIR, "device"), - emulatorBuildOutputPath: path.join(projectRoot, constants.BUILD_DIR, "emulator"), + getBuildOutputPath: (options : IBuildOutputOptions): string => { + const config = getConfigurationName(!options || options.release); + return path.join(projectRoot, constants.BUILD_DIR, `${config}-${getPlatformSdkName(!options || options.buildForDevice)}`); + }, getValidBuildOutputData: (buildOptions: IBuildOutputOptions): IValidBuildOutputData => { const forDevice = !buildOptions || !!buildOptions.buildForDevice; if (forDevice) { @@ -206,10 +215,11 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ * Returns the path to the .xcarchive. */ public async archive(projectData: IProjectData, buildConfig?: IBuildConfig, options?: { archivePath?: string, additionalArgs?: string[] }): Promise { + const platformData = this.getPlatformData(projectData); const projectRoot = this.getPlatformData(projectData).projectRoot; - const archivePath = options && options.archivePath ? path.resolve(options.archivePath) : path.join(projectRoot, "/build/archive/", projectData.projectName + ".xcarchive"); + const archivePath = options && options.archivePath ? path.resolve(options.archivePath) : path.join(platformData.getBuildOutputPath(buildConfig), projectData.projectName + ".xcarchive"); let args = ["archive", "-archivePath", archivePath, "-configuration", - (!buildConfig || buildConfig.release) ? "Release" : "Debug"] + getConfigurationName(!buildConfig || buildConfig.release)] .concat(this.xcbuildProjectArgs(projectRoot, projectData, "scheme")); if (options && options.additionalArgs) { @@ -278,12 +288,11 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ /** * Exports .xcarchive for a development device. */ - private async exportDevelopmentArchive(projectData: IProjectData, buildConfig: IBuildConfig, options: { archivePath: string, exportDir?: string, teamID?: string, provision?: string }): Promise { + private async exportDevelopmentArchive(projectData: IProjectData, buildConfig: IBuildConfig, options: { archivePath: string, provision?: string }): Promise { const platformData = this.getPlatformData(projectData); const projectRoot = platformData.projectRoot; const archivePath = options.archivePath; - const buildOutputPath = path.join(projectRoot, "build", "device"); - const exportOptionsMethod = await this.getExportOptionsMethod(projectData); + const exportOptionsMethod = await this.getExportOptionsMethod(projectData, archivePath); let plistTemplate = ` @@ -311,7 +320,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ this.$fs.writeFile(exportOptionsPlist, plistTemplate); // The xcodebuild exportPath expects directory and writes the .ipa at that directory. - const exportPath = path.resolve(options.exportDir || buildOutputPath); + const exportPath = path.resolve(path.dirname(archivePath)); const exportFile = path.join(exportPath, projectData.projectName + ".ipa"); await this.xcodebuild( @@ -407,8 +416,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ args = args.concat((buildConfig && buildConfig.architectures) || this.getBuildArchitectures(projectData, buildConfig, ["armv7", "arm64"])); args = args.concat([ - "-sdk", "iphoneos", - "CONFIGURATION_BUILD_DIR=" + path.join(projectRoot, "build", "device") + "-sdk", DevicePlatformSdkName, + "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR) ]); const xcodeBuildVersion = await this.getXcodeVersion(); @@ -574,10 +583,10 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ .concat(architectures) .concat([ "build", - "-configuration", buildConfig.release ? "Release" : "Debug", - "-sdk", "iphonesimulator", + "-configuration", getConfigurationName(buildConfig.release), + "-sdk", SimulatorPlatformSdkName, "ONLY_ACTIVE_ARCH=NO", - "CONFIGURATION_BUILD_DIR=" + path.join(projectRoot, "build", "emulator"), + "BUILD_DIR=" + path.join(projectRoot, constants.BUILD_DIR), "CODE_SIGN_IDENTITY=", ]) .concat(this.xcbuildProjectArgs(projectRoot, projectData)); @@ -1390,8 +1399,8 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f } } - private getExportOptionsMethod(projectData: IProjectData): string { - const embeddedMobileProvisionPath = path.join(this.getPlatformData(projectData).projectRoot, "build", "archive", `${projectData.projectName}.xcarchive`, 'Products', 'Applications', `${projectData.projectName}.app`, "embedded.mobileprovision"); + private getExportOptionsMethod(projectData: IProjectData, archivePath: string): string { + const embeddedMobileProvisionPath = path.join(archivePath, 'Products', 'Applications', `${projectData.projectName}.app`, "embedded.mobileprovision"); const provision = mobileprovision.provision.readFromFile(embeddedMobileProvisionPath); return { diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index 4a188cdfed..eda6449b9f 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -376,8 +376,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { } const platformData = this.$platformsData.getPlatformData(platform, projectData); - const forDevice = !buildConfig || !!buildConfig.buildForDevice; - outputPath = outputPath || (forDevice ? platformData.deviceBuildOutputPath : platformData.emulatorBuildOutputPath || platformData.deviceBuildOutputPath); + outputPath = outputPath || platformData.getBuildOutputPath(buildConfig); if (!this.$fs.exists(outputPath)) { return true; } @@ -533,7 +532,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { } let hashes = {}; - const hashesFilePath = path.join(outputFilePath || platformData.deviceBuildOutputPath, constants.HASHES_FILE_NAME); + const hashesFilePath = path.join(outputFilePath || platformData.getBuildOutputPath(null), constants.HASHES_FILE_NAME); if (this.$fs.exists(hashesFilePath)) { hashes = this.$fs.readJson(hashesFilePath); } @@ -618,10 +617,10 @@ export class PlatformService extends EventEmitter implements IPlatformService { } if (platform.toLowerCase() === this.$devicePlatformsConstants.iOS.toLowerCase()) { - return options.buildForDevice ? platformData.deviceBuildOutputPath : platformData.emulatorBuildOutputPath; + return platformData.getBuildOutputPath(options); } - return platformData.deviceBuildOutputPath; + return platformData.getBuildOutputPath(options); } private async getDeviceBuildInfoFilePath(device: Mobile.IDevice, projectData: IProjectData): Promise { @@ -904,13 +903,13 @@ export class PlatformService extends EventEmitter implements IPlatformService { } public getLatestApplicationPackageForDevice(platformData: IPlatformData, buildConfig: IBuildConfig, outputPath?: string): IApplicationPackage { - return this.getLatestApplicationPackage(outputPath || platformData.deviceBuildOutputPath, platformData.getValidBuildOutputData({ buildForDevice: true, release: buildConfig.release, androidBundle: buildConfig.androidBundle })); + return this.getLatestApplicationPackage(outputPath || platformData.getBuildOutputPath(buildConfig), platformData.getValidBuildOutputData({ buildForDevice: true, release: buildConfig.release, androidBundle: buildConfig.androidBundle })); } public getLatestApplicationPackageForEmulator(platformData: IPlatformData, buildConfig: IBuildConfig, outputPath?: string): IApplicationPackage { + outputPath = outputPath || this.getBuildOutputPath(platformData.normalizedPlatformName.toLowerCase(), platformData, buildConfig); const buildOutputOptions: IBuildOutputOptions = { buildForDevice: false, release: buildConfig.release, androidBundle: buildConfig.androidBundle }; - outputPath = outputPath || this.getBuildOutputPath(platformData.normalizedPlatformName.toLowerCase(), platformData, buildOutputOptions); - return this.getLatestApplicationPackage(outputPath || platformData.emulatorBuildOutputPath || platformData.deviceBuildOutputPath, platformData.getValidBuildOutputData(buildOutputOptions)); + return this.getLatestApplicationPackage(outputPath || platformData.getBuildOutputPath(buildConfig), platformData.getValidBuildOutputData(buildOutputOptions)); } private async updatePlatform(platform: string, version: string, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions): Promise { diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 61bfcad100..80146078d7 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -203,12 +203,12 @@ describe("iOSProjectService", () => { if (hasCustomArchivePath) { archivePath = path.resolve(options.archivePath); } else { - archivePath = path.join(projectPath, "platforms", "ios", "build", "archive", projectName + ".xcarchive"); + archivePath = path.join(projectPath, "platforms", "ios", "build", "Release-iphoneos", projectName + ".xcarchive"); } assert.ok(args.indexOf("archive") >= 0, "Expected xcodebuild to be executed with archive param."); - expectOption(args, "-archivePath", archivePath, hasCustomArchivePath ? "Wrong path passed to xcarchive" : "Default xcarchive path is wrong."); + expectOption(args, "-archivePath", archivePath, hasCustomArchivePath ? "Wrong path passed to xcarchive" : "exports xcodearchive to platforms/ios/build/archive."); expectOption(args, "-project", path.join(projectPath, "platforms", "ios", projectName + ".xcodeproj"), "Path to Xcode project is wrong."); expectOption(args, "-scheme", projectName, "The provided scheme is wrong."); diff --git a/test/platform-commands.ts b/test/platform-commands.ts index c63686abaa..13c01603ed 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -39,7 +39,7 @@ class PlatformData implements IPlatformData { } }; projectRoot = ""; - deviceBuildOutputPath = ""; + getBuildOutputPath = () => ""; getValidBuildOutputData = (buildOptions: IBuildOutputOptions) => ({ packageNames: [""] }); validPackageNamesForDevice: string[] = []; frameworkFilesExtensions = [".jar", ".dat"]; diff --git a/test/platform-service.ts b/test/platform-service.ts index 16881a7d57..d2a6cd7799 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -264,7 +264,7 @@ describe('Platform Service Tests', () => { projectRoot: "", normalizedPlatformName: "", appDestinationDirectoryPath: "", - deviceBuildOutputPath: "", + getBuildOutputPath: () => "", getValidBuildOutputData: (buildOptions: IBuildOutputOptions) => ({ packageNames: [] }), frameworkFilesExtensions: [], relativeToFrameworkConfigurationFilePath: "", @@ -981,6 +981,7 @@ describe('Platform Service Tests', () => { return { deviceBuildOutputPath: "", normalizedPlatformName: "", + getBuildOutputPath: () => "", platformProjectService: { buildProject: () => Promise.resolve(), on: () => ({}), diff --git a/test/services/android-project-service.ts b/test/services/android-project-service.ts index 2c6abdb18e..aad86d5916 100644 --- a/test/services/android-project-service.ts +++ b/test/services/android-project-service.ts @@ -76,7 +76,8 @@ describe("androidDeviceDebugService", () => { const getPlatformDataStub: sinon.SinonStub = sandbox.stub(androidProjectService, "getPlatformData"); getPlatformDataStub.callsFake(() => { return { - configurationFilePath: "" + configurationFilePath: "", + getBuildOutputPath: () => "" }; }); }); diff --git a/test/stubs.ts b/test/stubs.ts index a8182dfb6c..02d55b1ee3 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -379,7 +379,7 @@ export class PlatformProjectServiceStub extends EventEmitter implements IPlatfor normalizedPlatformName: "", platformProjectService: this, projectRoot: "", - deviceBuildOutputPath: "", + getBuildOutputPath: () => "", getValidBuildOutputData: (buildOptions: IBuildOutputOptions) => ({ packageNames: [] }), frameworkFilesExtensions: [], appDestinationDirectoryPath: "", @@ -490,7 +490,7 @@ export class PlatformsDataStub extends EventEmitter implements IPlatformsData { projectRoot: "", normalizedPlatformName: "", appDestinationDirectoryPath: "", - deviceBuildOutputPath: "", + getBuildOutputPath: () => "", getValidBuildOutputData: (buildOptions: IBuildOutputOptions) => ({ packageNames: [] }), frameworkFilesExtensions: [], relativeToFrameworkConfigurationFilePath: "",