diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index d47626112f..bab3bee3b7 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -706,7 +706,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject platformVersion = projectPackageJson.version; } } else { - return false; + return true; } } diff --git a/lib/services/livesync/livesync-service.ts b/lib/services/livesync/livesync-service.ts index d59bd34069..f81362c1c4 100644 --- a/lib/services/livesync/livesync-service.ts +++ b/lib/services/livesync/livesync-service.ts @@ -321,15 +321,19 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi // In case liveSync is called for a second time for the same projectDir. const isAlreadyLiveSyncing = this.liveSyncProcessesInfo[projectData.projectDir] && !this.liveSyncProcessesInfo[projectData.projectDir].isStopped; + // Prevent cases where liveSync is called consecutive times with the same device, for example [ A, B, C ] and then [ A, B, D ] - we want to execute initialSync only for D. + const currentlyRunningDeviceDescriptors = this.getLiveSyncDeviceDescriptors(projectData.projectDir); + const deviceDescriptorsForInitialSync = isAlreadyLiveSyncing ? _.differenceBy(deviceDescriptors, currentlyRunningDeviceDescriptors, deviceDescriptorPrimaryKey) : deviceDescriptors; + this.setLiveSyncProcessInfo(liveSyncData.projectDir, deviceDescriptors); if (!liveSyncData.skipWatcher && this.liveSyncProcessesInfo[projectData.projectDir].deviceDescriptors.length) { // Should be set after prepare this.$usbLiveSyncService.isInitialized = true; - await this.startWatcher(projectData, liveSyncData, deviceDescriptors, { isAlreadyLiveSyncing }); + await this.startWatcher(projectData, liveSyncData, deviceDescriptors); } - await this.initialSync(projectData, liveSyncData, deviceDescriptors, { isAlreadyLiveSyncing }); + await this.initialSync(projectData, liveSyncData, deviceDescriptorsForInitialSync); } private setLiveSyncProcessInfo(projectDir: string, deviceDescriptors: ILiveSyncDeviceInfo[]): void { @@ -342,13 +346,6 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi this.liveSyncProcessesInfo[projectDir].deviceDescriptors = _.uniqBy(currentDeviceDescriptors.concat(deviceDescriptors), deviceDescriptorPrimaryKey); } - private async initialSync(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[], options: { isAlreadyLiveSyncing: boolean }): Promise { - // Prevent cases where liveSync is called consecutive times with the same device, for example [ A, B, C ] and then [ A, B, D ] - we want to execute initialSync only for D. - const currentlyRunningDeviceDescriptors = this.getLiveSyncDeviceDescriptors(projectData.projectDir); - const deviceDescriptorsForInitialSync = options.isAlreadyLiveSyncing ? _.differenceBy(deviceDescriptors, currentlyRunningDeviceDescriptors, deviceDescriptorPrimaryKey) : deviceDescriptors; - await this.initialSyncCore(projectData, deviceDescriptorsForInitialSync, liveSyncData); - } - private getLiveSyncService(platform: string): IPlatformLiveSyncService { if (this.$mobileHelper.isiOSPlatform(platform)) { return this.$injector.resolve("iOSLiveSyncService"); @@ -450,7 +447,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi return null; } - private async initialSyncCore(projectData: IProjectData, deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise { + private async initialSync(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[]): Promise { const preparedPlatforms: string[] = []; const rebuiltInformation: ILiveSyncBuildInfo[] = []; @@ -524,7 +521,7 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi }; } - private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[], options: { isAlreadyLiveSyncing: boolean }): Promise { + private async startWatcher(projectData: IProjectData, liveSyncData: ILiveSyncInfo, deviceDescriptors: ILiveSyncDeviceInfo[]): Promise { const devicesIds = deviceDescriptors.map(dd => dd.identifier); const devices = _.filter(this.$devicesService.getDeviceInstances(), device => _.includes(devicesIds, device.deviceInfo.identifier)); const platforms = _(devices).map(device => device.deviceInfo.platform).uniq().value(); diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index 94fff61155..2002cbc543 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -263,7 +263,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { this.$errors.failWithoutHelp(`Unable to install dependencies. Make sure your package.json is valid and all dependencies are correct. Error is: ${err.message}`); } - await this.ensurePlatformInstalled(platform, platformTemplate, projectData, config, nativePrepare); + await this.ensurePlatformInstalled(platform, platformTemplate, projectData, config, appFilesUpdaterOptions, nativePrepare); const bundle = appFilesUpdaterOptions.bundle; const nativePlatformStatus = (nativePrepare && nativePrepare.skipNativePrepare) ? constants.NativePlatformStatus.requiresPlatformAdd : constants.NativePlatformStatus.requiresPrepare; @@ -603,7 +603,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { @helpers.hook('cleanApp') public async cleanDestinationApp(platformInfo: IPreparePlatformInfo): Promise { - await this.ensurePlatformInstalled(platformInfo.platform, platformInfo.platformTemplate, platformInfo.projectData, platformInfo.config, platformInfo.nativePrepare); + await this.ensurePlatformInstalled(platformInfo.platform, platformInfo.platformTemplate, platformInfo.projectData, platformInfo.config, platformInfo.appFilesUpdaterOptions, platformInfo.nativePrepare); const platformData = this.$platformsData.getPlatformData(platformInfo.platform, platformInfo.projectData); const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); @@ -711,14 +711,27 @@ export class PlatformService extends EventEmitter implements IPlatformService { } } - public async ensurePlatformInstalled(platform: string, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions, nativePrepare?: INativePrepare): Promise { + public async ensurePlatformInstalled(platform: string, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions, appFilesUpdaterOptions: IAppFilesUpdaterOptions, nativePrepare?: INativePrepare): Promise { let requiresNativePlatformAdd = false; + const platformData = this.$platformsData.getPlatformData(platform, projectData); + const prepareInfo = this.$projectChangesService.getPrepareInfo(platform, projectData); + // In case when no platform is added and webpack plugin is started it produces files in platforms folder. In this case {N} CLI needs to add platform and keeps the already produced files from webpack + if (appFilesUpdaterOptions.bundle && this.isPlatformInstalled(platform, projectData) && !this.$fs.exists(platformData.configurationFilePath) && (!prepareInfo || !prepareInfo.nativePlatformStatus || prepareInfo.nativePlatformStatus !== constants.NativePlatformStatus.alreadyPrepared)) { + const tmpDirectoryPath = path.join(projectData.projectDir, "platforms", "tmp"); + this.$fs.deleteDirectory(tmpDirectoryPath); + this.$fs.ensureDirectoryExists(tmpDirectoryPath); + this.$fs.copyFile(path.join(platformData.appDestinationDirectoryPath, "*"), tmpDirectoryPath); + await this.addPlatform(platform, platformTemplate, projectData, config, "", nativePrepare); + this.$fs.copyFile(path.join(tmpDirectoryPath, "*"), platformData.appDestinationDirectoryPath); + this.$fs.deleteDirectory(tmpDirectoryPath); + return; + } + if (!this.isPlatformInstalled(platform, projectData)) { await this.addPlatform(platform, platformTemplate, projectData, config, "", nativePrepare); } else { const shouldAddNativePlatform = !nativePrepare || !nativePrepare.skipNativePrepare; - const prepareInfo = this.$projectChangesService.getPrepareInfo(platform, projectData); // In case there's no prepare info, it means only platform add had been executed. So we've come from CLI and we do not need to prepare natively. requiresNativePlatformAdd = prepareInfo && prepareInfo.nativePlatformStatus === constants.NativePlatformStatus.requiresPlatformAdd; if (requiresNativePlatformAdd && shouldAddNativePlatform) { diff --git a/test/npm-support.ts b/test/npm-support.ts index 1252996825..61ebc1c2df 100644 --- a/test/npm-support.ts +++ b/test/npm-support.ts @@ -49,7 +49,9 @@ function createTestInjector(): IInjector { testInjector.register("platformsData", PlatformsDataLib.PlatformsData); testInjector.register("platformService", PlatformServiceLib.PlatformService); testInjector.register("logger", stubs.LoggerStub); - testInjector.register("npmInstallationManager", {}); + testInjector.register("npmInstallationManager", { + install: () => Promise.resolve() + }); testInjector.register("prompter", {}); testInjector.register("sysInfo", {}); testInjector.register("androidProjectService", {});