diff --git a/lib/common b/lib/common index fba05a71d4..a20a105da0 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit fba05a71d43a878fe8547363237f1de9d871385f +Subproject commit a20a105da0789a4c57bc6420ce6bb2b594789d77 diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index f2b21b0e6b..5f7de2f4cd 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -643,7 +643,7 @@ interface ISocketProxyFactory extends NodeJS.EventEmitter { createWebSocketProxy(factory: () => Promise, deviceIdentifier: string): Promise; } -interface IiOSNotification { +interface IiOSNotification extends NodeJS.EventEmitter { getWaitForDebug(projectId: string): string; getAttachRequest(projectId: string, deviceId: string): string; getAppLaunching(projectId: string): string; @@ -843,4 +843,4 @@ interface IAssetsGenerationService { * @returns {Promise} */ generateSplashScreens(splashesGenerationData: ISplashesGenerationData): Promise; -} \ No newline at end of file +} diff --git a/lib/device-sockets/ios/notification.ts b/lib/device-sockets/ios/notification.ts index d5bef34de4..d72e46057e 100644 --- a/lib/device-sockets/ios/notification.ts +++ b/lib/device-sockets/ios/notification.ts @@ -15,6 +15,8 @@ export class IOSNotification extends EventEmitter implements IiOSNotification { } public getAttachRequest(appId: string, deviceId: string): string { + // It could be too early to emit this event, but we rely that if you construct attach request, + // you will execute it immediately. this.emit(ATTACH_REQUEST_EVENT_NAME, { deviceId, appId }); return this.formatNotification(IOSNotification.ATTACH_REQUEST_NOTIFICATION_NAME, appId); } diff --git a/lib/device-sockets/ios/socket-proxy-factory.ts b/lib/device-sockets/ios/socket-proxy-factory.ts index 89271a130c..368063faeb 100644 --- a/lib/device-sockets/ios/socket-proxy-factory.ts +++ b/lib/device-sockets/ios/socket-proxy-factory.ts @@ -95,7 +95,7 @@ export class SocketProxyFactory extends EventEmitter implements ISocketProxyFact err.deviceIdentifier = deviceIdentifier; this.$logger.trace(err); this.emit(CONNECTION_ERROR_EVENT_NAME, err); - this.$errors.failWithoutHelp("Cannot connect to device socket."); + this.$errors.failWithoutHelp(`Cannot connect to device socket. The error message is ${err.message}`); } this.$logger.info("Backend socket created."); diff --git a/lib/services/ios-debug-service.ts b/lib/services/ios-debug-service.ts index 98ba3493c0..efdb98c62e 100644 --- a/lib/services/ios-debug-service.ts +++ b/lib/services/ios-debug-service.ts @@ -39,7 +39,9 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS return "ios"; } - public debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + await this.device.openDeviceLogStream(); + if (debugOptions.debugBrk && debugOptions.start) { this.$errors.failWithoutHelp("Expected exactly one of the --debug-brk or --start options."); } @@ -106,12 +108,13 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS private async emulatorDebugBrk(debugData: IDebugData, debugOptions: IDebugOptions): Promise { const args = debugOptions.debugBrk ? "--nativescript-debug-brk" : "--nativescript-debug-start"; - const launchResult = await this.$iOSEmulatorServices.runApplicationOnEmulator(debugData.pathToAppPackage, { + const launchResult = await this.$iOSEmulatorServices.runApplicationOnEmulator(debugData.pathToAppPackage, { waitForDebugger: true, captureStdin: true, args: args, appId: debugData.applicationIdentifier, - skipInstall: true + skipInstall: true, + device: debugData.deviceIdentifier }); const pid = getPidFromiOSSimulatorLogs(debugData.applicationIdentifier, launchResult); @@ -126,6 +129,8 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } private async emulatorStart(debugData: IDebugData, debugOptions: IDebugOptions): Promise { + const device = await this.$devicesService.getDevice(debugData.deviceIdentifier); + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); const result = await this.wireDebuggerClient(debugData, debugOptions); const attachRequestMessage = this.$iOSNotification.getAttachRequest(debugData.applicationIdentifier, debugData.deviceIdentifier); @@ -174,6 +179,7 @@ export class IOSDebugService extends DebugServiceBase implements IPlatformDebugS } private async deviceStartCore(device: Mobile.IiOSDevice, debugData: IDebugData, debugOptions: IDebugOptions): Promise { + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); await this.$iOSSocketRequestExecutor.executeAttachRequest(device, AWAIT_NOTIFICATION_TIMEOUT_SECONDS, debugData.applicationIdentifier); return this.wireDebuggerClient(debugData, debugOptions, device); } diff --git a/lib/services/ios-debugger-port-service.ts b/lib/services/ios-debugger-port-service.ts index 5e94d373a6..64c4dc830f 100644 --- a/lib/services/ios-debugger-port-service.ts +++ b/lib/services/ios-debugger-port-service.ts @@ -9,6 +9,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { constructor(private $iOSLogParserService: IIOSLogParserService, private $iOSProjectService: IPlatformProjectService, + private $iOSNotification: IiOSNotification, private $logger: ILogger, private $projectData: IProjectData) { } @@ -62,7 +63,7 @@ export class IOSDebuggerPortService implements IIOSDebuggerPortService { @cache() private attachToAttachRequestEvent(device: Mobile.IDevice): void { - device.applicationManager.on(ATTACH_REQUEST_EVENT_NAME, (data: IIOSDebuggerPortData) => { + this.$iOSNotification.on(ATTACH_REQUEST_EVENT_NAME, (data: IIOSDebuggerPortData) => { this.$logger.trace(ATTACH_REQUEST_EVENT_NAME, data); const timer = setTimeout(() => { this.clearTimeout(data); diff --git a/lib/services/ios-log-parser-service.ts b/lib/services/ios-log-parser-service.ts index dd8108f34e..efd9d75fec 100644 --- a/lib/services/ios-log-parser-service.ts +++ b/lib/services/ios-log-parser-service.ts @@ -1,26 +1,29 @@ import { DEBUGGER_PORT_FOUND_EVENT_NAME, DEVICE_LOG_EVENT_NAME } from "../common/constants"; -import { cache } from "../common/decorators"; import { EventEmitter } from "events"; export class IOSLogParserService extends EventEmitter implements IIOSLogParserService { private static MESSAGE_REGEX = /NativeScript debugger has opened inspector socket on port (\d+?) for (.*)[.]/; + private startedDeviceLogInstances: IDictionary = {}; + constructor(private $deviceLogProvider: Mobile.IDeviceLogProvider, private $iosDeviceOperations: IIOSDeviceOperations, private $iOSSimulatorLogProvider: Mobile.IiOSSimulatorLogProvider, private $logger: ILogger, private $projectData: IProjectData) { - super(); - } + super(); + } public startParsingLog(device: Mobile.IDevice): void { this.$deviceLogProvider.setProjectNameForDevice(device.deviceInfo.identifier, this.$projectData.projectName); - this.startParsingLogCore(device); - this.startLogProcess(device); + if (!this.startedDeviceLogInstances[device.deviceInfo.identifier]) { + this.startParsingLogCore(device); + this.startLogProcess(device); + this.startedDeviceLogInstances[device.deviceInfo.identifier] = true; + } } - @cache() private startParsingLogCore(device: Mobile.IDevice): void { const logProvider = device.isEmulator ? this.$iOSSimulatorLogProvider : this.$iosDeviceOperations; logProvider.on(DEVICE_LOG_EVENT_NAME, (response: IOSDeviceLib.IDeviceLogData) => this.processDeviceLogResponse(response)); diff --git a/lib/services/livesync/ios-livesync-service.ts b/lib/services/livesync/ios-livesync-service.ts index da1e921fe0..31f66b768f 100644 --- a/lib/services/livesync/ios-livesync-service.ts +++ b/lib/services/livesync/ios-livesync-service.ts @@ -13,6 +13,7 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I $devicePathProvider: IDevicePathProvider, $logger: ILogger, $projectFilesProvider: IProjectFilesProvider, + private $iOSDebuggerPortService: IIOSDebuggerPortService, ) { super($fs, $logger, $platformsData, $projectFilesManager, $devicePathProvider, $projectFilesProvider); } @@ -24,6 +25,8 @@ export class IOSLiveSyncService extends PlatformLiveSyncServiceBase implements I return super.fullSync(syncInfo); } + this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(device); + const projectData = syncInfo.projectData; const platformData = this.$platformsData.getPlatformData(device.deviceInfo.platform, projectData); const deviceAppData = await this.getAppData(syncInfo); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b42340ae95..4f3c58ba23 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2868,9 +2868,9 @@ } }, "ios-sim-portable": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.4.1.tgz", - "integrity": "sha512-5zouPe8hjN6tLCwoxYXT4S1l2lY0aMZAXOGK9L8pPF8nXtanNKbVxpCrEszKcCbGzNQ/WyY/diJXTNL1ZO6HZg==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.4.3.tgz", + "integrity": "sha512-Ail75Gfk9FkEEeTbgoQwXOFR/+DJFGXWNbekZDpdd4zmyzYEMfp8ZG2J0KefKlDeYJ2H3lA/Y7OtDMcT3oF9ug==", "requires": { "bplist-parser": "https://github.com/telerik/node-bplist-parser/tarball/master", "colors": "0.6.2", diff --git a/package.json b/package.json index 180e50cbaf..51981060da 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "inquirer": "0.9.0", "ios-device-lib": "0.4.12", "ios-mobileprovision-finder": "1.0.10", - "ios-sim-portable": "3.4.1", + "ios-sim-portable": "3.4.3", "jimp": "0.2.28", "lockfile": "1.0.3", "lodash": "4.13.1", diff --git a/test/services/ios-debugger-port-service.ts b/test/services/ios-debugger-port-service.ts index fda70f07c9..a1a8cd2950 100644 --- a/test/services/ios-debugger-port-service.ts +++ b/test/services/ios-debugger-port-service.ts @@ -6,6 +6,7 @@ import { IOSLogParserService } from "../../lib/services/ios-log-parser-service"; import { IOSSimulatorLogProvider } from "../../lib/common/mobile/ios/simulator/ios-simulator-log-provider"; import { Yok } from "../../lib/common/yok"; import { EventEmitter } from "events"; +import * as sinon from "sinon"; class DeviceApplicationManagerMock extends EventEmitter { } @@ -50,6 +51,7 @@ function createTestInjector() { projectName: "test", projectId: appId }); + injector.register("iOSNotification", DeviceApplicationManagerMock); return injector; } @@ -82,11 +84,17 @@ function getMultilineDebuggerPortMessage(port: number) { describe("iOSDebuggerPortService", () => { let injector: IInjector, iOSDebuggerPortService: IIOSDebuggerPortService, iosDeviceOperations: IIOSDeviceOperations; + let clock: sinon.SinonFakeTimers = null; beforeEach(() => { injector = createTestInjector(); iOSDebuggerPortService = injector.resolve("iOSDebuggerPortService"); iosDeviceOperations = injector.resolve("iosDeviceOperations"); + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); }); function emitDeviceLog(message: string) { @@ -142,7 +150,9 @@ describe("iOSDebuggerPortService", () => { emitDeviceLog(getDebuggerPortMessage(testCase.emittedPort)); } - const port = await iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + clock.tick(10000); + const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); it(`${testCase.name} for multiline debugger port message.`, async () => { @@ -154,7 +164,9 @@ describe("iOSDebuggerPortService", () => { emitDeviceLog(getMultilineDebuggerPortMessage(testCase.emittedPort)); } - const port = await iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + const promise = iOSDebuggerPortService.getPort({ deviceId: deviceId, appId: appId }); + clock.tick(10000); + const port = await promise; assert.deepEqual(port, testCase.emittedPort); }); });