diff --git a/lib/controllers/run-controller.ts b/lib/controllers/run-controller.ts index fad79b8705..d85e2f5df2 100644 --- a/lib/controllers/run-controller.ts +++ b/lib/controllers/run-controller.ts @@ -124,6 +124,16 @@ export class RunController extends EventEmitter implements IRunController { await this.refreshApplicationWithDebug(projectData, liveSyncResultInfo, filesChangeEventData, deviceDescriptor, settings) : await this.refreshApplicationWithoutDebug(projectData, liveSyncResultInfo, filesChangeEventData, deviceDescriptor, settings); + const device = liveSyncResultInfo.deviceAppData.device; + + this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { + projectDir: projectData.projectDir, + deviceIdentifier: device.deviceInfo.identifier, + applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], + syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), + isFullSync: liveSyncResultInfo.isFullSync + }); + return result; } @@ -282,14 +292,6 @@ export class RunController extends EventEmitter implements IRunController { await this.refreshApplication(projectData, liveSyncResultInfo, null, deviceDescriptor); - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); - this.$logger.info(`Successfully synced application ${liveSyncResultInfo.deviceAppData.appIdentifier} on device ${liveSyncResultInfo.deviceAppData.device.deviceInfo.identifier}.`); this.emitCore(RunOnDeviceEvents.runOnDeviceStarted, { @@ -327,81 +329,64 @@ export class RunController extends EventEmitter implements IRunController { }); try { - if (data.hasNativeChanges) { - const rebuiltInfo = this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator); - if (!rebuiltInfo) { - await this.$prepareNativePlatformService.prepareNativePlatform(platformData, projectData, prepareData); - await deviceDescriptor.buildAction(); - this.rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath: null }; - } - - await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); - } - - const isInHMRMode = liveSyncInfo.useHotModuleReload && data.hmrData && data.hmrData.hash; - if (isInHMRMode) { - this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); - } - const platformLiveSyncService = this.$liveSyncServiceResolver.resolveLiveSyncService(device.deviceInfo.platform); const watchInfo = { liveSyncDeviceData: deviceDescriptor, projectData, filesToRemove: [], filesToSync: data.files, - isReinstalled: false, hmrData: data.hmrData, useHotModuleReload: liveSyncInfo.useHotModuleReload, force: liveSyncInfo.force, connectTimeout: 1000 }; - let liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + const deviceAppData = await platformLiveSyncService.getAppData(_.merge({ device, watch: true }, watchInfo)); - await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); + if (data.hasNativeChanges) { + const rebuiltInfo = this.rebuiltInformation[platformData.platformNameLowerCase] && (this.$mobileHelper.isAndroidPlatform(platformData.platformNameLowerCase) || this.rebuiltInformation[platformData.platformNameLowerCase].isEmulator === device.isEmulator); + if (!rebuiltInfo) { + await this.$prepareNativePlatformService.prepareNativePlatform(platformData, projectData, prepareData); + await deviceDescriptor.buildAction(); + this.rebuiltInformation[platformData.platformNameLowerCase] = { isEmulator: device.isEmulator, platform: platformData.platformNameLowerCase, packageFilePath: null }; + } - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); + await this.$deviceInstallAppService.installOnDevice(device, deviceDescriptor.buildData, this.rebuiltInformation[platformData.platformNameLowerCase].packageFilePath); + await platformLiveSyncService.syncAfterInstall(device, watchInfo); + await platformLiveSyncService.restartApplication(projectData, { deviceAppData, modifiedFilesData: [], isFullSync: false, useHotModuleReload: liveSyncInfo.useHotModuleReload }); + } else { + const isInHMRMode = liveSyncInfo.useHotModuleReload && data.hmrData && data.hmrData.hash; + if (isInHMRMode) { + this.$hmrStatusService.watchHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); + } - if (!liveSyncResultInfo.didRecover && isInHMRMode) { - const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); - if (status === HmrConstants.HMR_ERROR_STATUS) { - watchInfo.filesToSync = data.hmrData.fallbackFiles; - liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); - // We want to force a restart of the application. - liveSyncResultInfo.isFullSync = true; - await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); - - this.emitCore(RunOnDeviceEvents.runOnDeviceExecuted, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - syncedFiles: liveSyncResultInfo.modifiedFilesData.map(m => m.getLocalPath()), - isFullSync: liveSyncResultInfo.isFullSync - }); + let liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + + if (!liveSyncResultInfo.didRecover && isInHMRMode) { + const status = await this.$hmrStatusService.getHmrStatus(device.deviceInfo.identifier, data.hmrData.hash); + if (status === HmrConstants.HMR_ERROR_STATUS) { + watchInfo.filesToSync = data.hmrData.fallbackFiles; + liveSyncResultInfo = await platformLiveSyncService.liveSyncWatchAction(device, watchInfo); + // We want to force a restart of the application. + liveSyncResultInfo.isFullSync = true; + await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); + } } + + await this.refreshApplication(projectData, liveSyncResultInfo, data, deviceDescriptor); } - this.$logger.info(`Successfully synced application ${liveSyncResultInfo.deviceAppData.appIdentifier} on device ${liveSyncResultInfo.deviceAppData.device.deviceInfo.identifier}.`); + this.$logger.info(`Successfully synced application ${deviceAppData.appIdentifier} on device ${device.deviceInfo.identifier}.`); } catch (err) { - const allErrors = (err).allErrors; + this.$logger.warn(`Unable to apply changes for device: ${device.deviceInfo.identifier}. Error is: ${err && err.message}.`); - if (allErrors && _.isArray(allErrors)) { - for (const deviceError of allErrors) { - this.$logger.warn(`Unable to apply changes for device: ${deviceError.deviceIdentifier}. Error is: ${deviceError.message}.`); + this.emitCore(RunOnDeviceEvents.runOnDeviceError, { + projectDir: projectData.projectDir, + deviceIdentifier: device.deviceInfo.identifier, + applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], + error: err, + }); - this.emitCore(RunOnDeviceEvents.runOnDeviceError, { - projectDir: projectData.projectDir, - deviceIdentifier: device.deviceInfo.identifier, - applicationIdentifier: projectData.projectIdentifiers[device.deviceInfo.platform.toLowerCase()], - error: err, - }); - } - } + await this.stop({ projectDir: projectData.projectDir, deviceIdentifiers: [device.deviceInfo.identifier] }); } }; diff --git a/lib/definitions/livesync.d.ts b/lib/definitions/livesync.d.ts index b224149091..b692609ccb 100644 --- a/lib/definitions/livesync.d.ts +++ b/lib/definitions/livesync.d.ts @@ -210,7 +210,6 @@ declare global { interface ILiveSyncWatchInfo extends IProjectDataComposition, IHasUseHotModuleReloadOption, IConnectTimeoutOption { filesToRemove: string[]; filesToSync: string[]; - isReinstalled: boolean; liveSyncDeviceData: ILiveSyncDeviceDescriptor; hmrData: IPlatformHmrData; force?: boolean; @@ -250,6 +249,8 @@ declare global { restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; shouldRestart(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise; getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService; + getAppData(syncInfo: IFullSyncInfo): Promise; + syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise; } interface IRestartApplicationInfo { diff --git a/lib/services/livesync/ios-livesync-service.ts b/lib/services/livesync/ios-livesync-service.ts index 70928ea873..df2d34e063 100644 --- a/lib/services/livesync/ios-livesync-service.ts +++ b/lib/services/livesync/ios-livesync-service.ts @@ -55,19 +55,16 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I }; } - @performanceLog() - public liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { - if (liveSyncInfo.isReinstalled) { + public async syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { + if (!device.isEmulator) { // In this case we should execute fullsync because iOS Runtime requires the full content of app dir to be extracted in the root of sync dir. - return this.fullSync({ + await this.fullSync({ projectData: liveSyncInfo.projectData, device, liveSyncDeviceData: liveSyncInfo.liveSyncDeviceData, watch: true, useHotModuleReload: liveSyncInfo.useHotModuleReload }); - } else { - return super.liveSyncWatchAction(device, liveSyncInfo); } } diff --git a/lib/services/livesync/platform-livesync-service-base.ts b/lib/services/livesync/platform-livesync-service-base.ts index 2534daff0d..c2be0b0adf 100644 --- a/lib/services/livesync/platform-livesync-service-base.ts +++ b/lib/services/livesync/platform-livesync-service-base.ts @@ -2,6 +2,7 @@ import * as path from "path"; import * as util from "util"; import { APP_FOLDER_NAME } from "../../constants"; import { getHash } from "../../common/helpers"; +import { performanceLog } from "../../common/decorators"; export abstract class PlatformLiveSyncServiceBase { private _deviceLiveSyncServicesCache: IDictionary = {}; @@ -32,6 +33,8 @@ export abstract class PlatformLiveSyncServiceBase { return shouldRestart; } + public async syncAfterInstall(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { /* intentionally left blank */ } + public async restartApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise { const deviceLiveSyncService = this.getDeviceLiveSyncService(liveSyncInfo.deviceAppData.device, projectData); this.$logger.info(`Restarting application on device ${liveSyncInfo.deviceAppData.device.deviceInfo.identifier}...`); @@ -72,6 +75,7 @@ export abstract class PlatformLiveSyncServiceBase { }; } + @performanceLog() public async liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise { const projectData = liveSyncInfo.projectData; const deviceLiveSyncService = this.getDeviceLiveSyncService(device, projectData); @@ -122,7 +126,7 @@ export abstract class PlatformLiveSyncServiceBase { return { modifiedFilesData: modifiedLocalToDevicePaths, - isFullSync: liveSyncInfo.isReinstalled, + isFullSync: false, deviceAppData, useHotModuleReload: liveSyncInfo.useHotModuleReload }; @@ -141,7 +145,7 @@ export abstract class PlatformLiveSyncServiceBase { return transferredFiles; } - protected async getAppData(syncInfo: IFullSyncInfo): Promise { + public async getAppData(syncInfo: IFullSyncInfo): Promise { const platform = syncInfo.device.deviceInfo.platform.toLowerCase(); const appIdentifier = syncInfo.projectData.projectIdentifiers[platform]; const deviceProjectRootOptions: IDeviceProjectRootOptions = _.assign({ appIdentifier }, syncInfo);