Skip to content

Commit ba861d8

Browse files
author
Fatme
authored
Merge pull request #4276 from NativeScript/fatme/merge-release-into-master
chore: merge release into master
2 parents f866831 + 2573c61 commit ba861d8

22 files changed

+246
-171
lines changed

lib/commands/preview.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,11 @@ export class PreviewCommand implements ICommand {
1919
this.$logger.info(message);
2020
});
2121

22-
await this.$liveSyncService.liveSync([], {
23-
syncToPreviewApp: true,
24-
projectDir: this.$projectData.projectDir,
25-
skipWatcher: !this.$options.watch,
26-
watchAllFiles: this.$options.syncAllFiles,
27-
clean: this.$options.clean,
22+
await this.$liveSyncService.liveSyncToPreviewApp({
2823
bundle: !!this.$options.bundle,
29-
release: this.$options.release,
30-
env: this.$options.env,
31-
timeout: this.$options.timeout,
32-
useHotModuleReload: this.$options.hmr
24+
useHotModuleReload: this.$options.hmr,
25+
projectDir: this.$projectData.projectDir,
26+
env: this.$options.env
3327
});
3428

3529
await this.$previewQrCodeService.printLiveSyncQrCode({ useHotModuleReload: this.$options.hmr, link: this.$options.link });

lib/declarations.d.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -474,10 +474,14 @@ interface IGenerateOptions {
474474
collection?: string;
475475
}
476476

477-
interface IDebugInformation extends IPort, Mobile.IDeviceIdentifier {
477+
interface IDebugInformation extends IPort, Mobile.IDeviceIdentifier, IHasHasReconnected {
478478
url: string;
479479
}
480480

481+
interface IHasHasReconnected {
482+
hasReconnected: boolean;
483+
}
484+
481485
interface IPort {
482486
port: Number;
483487
}
@@ -736,8 +740,7 @@ interface IAppDebugSocketProxyFactory extends NodeJS.EventEmitter {
736740
getTCPSocketProxy(deviceIdentifier: string, appId: string): any;
737741
addTCPSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<any>;
738742

739-
getWebSocketProxy(deviceIdentifier: string, appId: string): any;
740-
addWebSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<any>;
743+
ensureWebSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<any>;
741744

742745
removeAllProxies(): void;
743746
}

lib/definitions/debug.d.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ interface IDebugOptions {
100100
* Defines if the handshake(AppLaunching notification) between CLI and runtime should be executed. The handshake is not needed when CLI retries to attach to the debugger.
101101
*/
102102
skipHandshake?: boolean;
103+
/**
104+
* Forces the debugger attach event to be emitted.
105+
*/
106+
forceDebuggerAttachedEvent?: boolean;
103107
}
104108

105109
/**
@@ -161,5 +165,9 @@ interface IDeviceDebugService extends IPlatform, NodeJS.EventEmitter {
161165
* @param {IDebugOptions} debugOptions Describe possible options to modify the behaivor of the debug operation, for example stop on the first line.
162166
* @returns {Promise<string>} Full url where the frontend client may be connected.
163167
*/
164-
debug(debugData: IAppDebugData, debugOptions: IDebugOptions): Promise<string>;
168+
debug(debugData: IAppDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo>;
169+
}
170+
171+
interface IDebugResultInfo extends IHasHasReconnected {
172+
debugUrl: string;
165173
}

lib/definitions/livesync.d.ts

+19-7
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ interface ILiveSyncEventData {
188188
applicationIdentifier?: string,
189189
projectDir: string,
190190
syncedFiles?: string[],
191-
error? : Error,
191+
error?: Error,
192192
notification?: string,
193193
isFullSync?: boolean
194194
}
@@ -242,6 +242,13 @@ interface ILiveSyncService {
242242
*/
243243
liveSync(deviceDescriptors: ILiveSyncDeviceInfo[], liveSyncData: ILiveSyncInfo): Promise<void>;
244244

245+
/**
246+
* Starts LiveSync operation to Preview app.
247+
* @param {IPreviewAppLiveSyncData} data Describes information about the current operation.
248+
* @returns {Promise<IQrCodeImageData>} Data of the QR code that should be used to start the LiveSync operation.
249+
*/
250+
liveSyncToPreviewApp(data: IPreviewAppLiveSyncData): Promise<IQrCodeImageData>;
251+
245252
/**
246253
* Stops LiveSync operation for specified directory.
247254
* @param {string} projectDir The directory for which to stop the operation.
@@ -330,11 +337,9 @@ interface IEnableDebuggingDeviceOptions extends Mobile.IDeviceIdentifier, IOptio
330337
/**
331338
* Describes settings passed to livesync service in order to control event emitting during refresh application.
332339
*/
333-
interface IShouldSkipEmitLiveSyncNotification {
334-
/**
335-
* Whether to skip emitting an event during refresh. Default is false.
336-
*/
340+
interface IRefreshApplicationSettings {
337341
shouldSkipEmitLiveSyncNotification: boolean;
342+
shouldCheckDeveloperDiscImage: boolean;
338343
}
339344

340345
/**
@@ -390,11 +395,18 @@ interface ITransferFilesOptions {
390395
interface IPlatformLiveSyncService {
391396
fullSync(syncInfo: IFullSyncInfo): Promise<ILiveSyncResultInfo>;
392397
liveSyncWatchAction(device: Mobile.IDevice, liveSyncInfo: ILiveSyncWatchInfo): Promise<ILiveSyncResultInfo>;
393-
refreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise<void>;
398+
refreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise<IRefreshApplicationInfo>;
394399
prepareForLiveSync(device: Mobile.IDevice, data: IProjectDir, liveSyncInfo: ILiveSyncInfo, debugOptions: IDebugOptions): Promise<void>;
395400
getDeviceLiveSyncService(device: Mobile.IDevice, projectData: IProjectData): INativeScriptDeviceLiveSyncService;
396401
}
397402

403+
interface IHasDidRestart {
404+
didRestart: boolean;
405+
}
406+
407+
interface IRefreshApplicationInfo extends IHasDidRestart {
408+
}
409+
398410
interface INativeScriptDeviceLiveSyncService extends IDeviceLiveSyncServiceBase {
399411
/**
400412
* Refreshes the application's content on a device
@@ -405,7 +417,7 @@ interface INativeScriptDeviceLiveSyncService extends IDeviceLiveSyncServiceBase
405417
* @return {Promise<void>}
406418
*/
407419
refreshApplication(projectData: IProjectData,
408-
liveSyncInfo: ILiveSyncResultInfo): Promise<void>;
420+
liveSyncInfo: ILiveSyncResultInfo): Promise<IRefreshApplicationInfo>;
409421

410422
/**
411423
* Removes specified files from a connected device

lib/device-sockets/ios/app-debug-socket-proxy-factory.ts

+19-13
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu
2020
return this.deviceTcpServers[`${deviceIdentifier}-${appId}`];
2121
}
2222

23-
public getWebSocketProxy(deviceIdentifier: string, appId: string): ws.Server {
24-
return this.deviceWebServers[`${deviceIdentifier}-${appId}`];
25-
}
26-
2723
public async addTCPSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<net.Server> {
2824
const cacheKey = `${device.deviceInfo.identifier}-${appId}`;
2925
const existingServer = this.deviceTcpServers[cacheKey];
@@ -84,7 +80,17 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu
8480
return server;
8581
}
8682

87-
public async addWebSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<ws.Server> {
83+
public async ensureWebSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<ws.Server> {
84+
const existingWebProxy = this.deviceWebServers[`${device.deviceInfo.identifier}-${appId}`];
85+
const result = existingWebProxy || await this.addWebSocketProxy(device, appId);
86+
87+
// TODO: do not remove till VSCode waits for this message in order to reattach
88+
this.$logger.info("Opened localhost " + result.options.port);
89+
90+
return result;
91+
}
92+
93+
private async addWebSocketProxy(device: Mobile.IiOSDevice, appId: string): Promise<ws.Server> {
8894
const cacheKey = `${device.deviceInfo.identifier}-${appId}`;
8995
const existingServer = this.deviceWebServers[cacheKey];
9096
if (existingServer) {
@@ -104,21 +110,23 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu
104110
const server = new ws.Server(<any>{
105111
port: localPort,
106112
host: "localhost",
107-
verifyClient: async (info: any, callback: Function) => {
113+
verifyClient: async (info: any, callback: (res: boolean, code?: number, message?: string) => void) => {
114+
let acceptHandshake = true;
108115
this.$logger.info("Frontend client connected.");
109116
let appDebugSocket;
110117
try {
111118
appDebugSocket = await device.getDebugSocket(appId);
119+
this.$logger.info("Backend socket created.");
120+
info.req["__deviceSocket"] = appDebugSocket;
112121
} catch (err) {
113122
err.deviceIdentifier = device.deviceInfo.identifier;
114123
this.$logger.trace(err);
115124
this.emit(CONNECTION_ERROR_EVENT_NAME, err);
116-
this.$errors.failWithoutHelp(`Cannot connect to device socket.The error message is ${err.message} `);
125+
acceptHandshake = false;
126+
this.$logger.warn(`Cannot connect to device socket. The error message is '${err.message}'. Try starting the application manually.`);
117127
}
118128

119-
this.$logger.info("Backend socket created.");
120-
info.req["__deviceSocket"] = appDebugSocket;
121-
callback(true);
129+
callback(acceptHandshake);
122130
}
123131
});
124132
this.deviceWebServers[cacheKey] = server;
@@ -152,12 +160,11 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu
152160
appDebugSocket.on("close", () => {
153161
this.$logger.info("Backend socket closed!");
154162
webSocket.close();
155-
server.close();
156-
delete this.deviceWebServers[cacheKey];
157163
});
158164

159165
webSocket.on("close", () => {
160166
this.$logger.info('Frontend socket closed!');
167+
appDebugSocket.unpipe(packets);
161168
packets.destroy();
162169
device.destroyDebugSocket(appId);
163170
if (!this.$options.watch) {
@@ -167,7 +174,6 @@ export class AppDebugSocketProxyFactory extends EventEmitter implements IAppDebu
167174

168175
});
169176

170-
this.$logger.info("Opened localhost " + localPort);
171177
return server;
172178
}
173179

lib/services/android-device-debug-service.ts

+12-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class AndroidDeviceDebugService extends DebugServiceBase implements IDevi
2424
this.deviceIdentifier = device.deviceInfo.identifier;
2525
}
2626

27-
public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string> {
27+
public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo> {
2828
this._packageName = debugData.applicationIdentifier;
2929
const result = this.device.isEmulator
3030
? await this.debugOnEmulator(debugData, debugOptions)
@@ -59,7 +59,7 @@ export class AndroidDeviceDebugService extends DebugServiceBase implements IDevi
5959
return this.removePortForwarding();
6060
}
6161

62-
private async debugOnEmulator(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string> {
62+
private async debugOnEmulator(debugData: IDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo> {
6363
// Assure we've detected the emulator as device
6464
// For example in case deployOnEmulator had stated new emulator instance
6565
// we need some time to detect it. Let's force detection.
@@ -97,7 +97,7 @@ export class AndroidDeviceDebugService extends DebugServiceBase implements IDevi
9797
return this.device.adb.executeCommand(["forward", `tcp:${local}`, `localabstract:${remote}`]);
9898
}
9999

100-
private async debugOnDevice(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string> {
100+
private async debugOnDevice(debugData: IDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo> {
101101
let packageFile = "";
102102

103103
if (!debugOptions.start && !this.device.isEmulator) {
@@ -113,27 +113,32 @@ export class AndroidDeviceDebugService extends DebugServiceBase implements IDevi
113113
projectName
114114
};
115115

116-
const action = (device: Mobile.IAndroidDevice): Promise<string> => this.debugCore(device, packageFile, appData, debugOptions);
116+
const action = (device: Mobile.IAndroidDevice): Promise<IDebugResultInfo> => this.debugCore(device, packageFile, appData, debugOptions);
117117

118118
const deviceActionResult = await this.$devicesService.execute(action, this.getCanExecuteAction(this.deviceIdentifier));
119119
return deviceActionResult[0].result;
120120
}
121121

122-
private async debugCore(device: Mobile.IAndroidDevice, packageFile: string, appData: Mobile.IApplicationData, debugOptions: IDebugOptions): Promise<string> {
122+
private async debugCore(device: Mobile.IAndroidDevice, packageFile: string, appData: Mobile.IApplicationData, debugOptions: IDebugOptions): Promise<IDebugResultInfo> {
123+
const result: IDebugResultInfo = { hasReconnected: false, debugUrl: null };
124+
123125
if (debugOptions.stop) {
124126
await this.removePortForwarding();
125-
return null;
127+
return result;
126128
}
127129

128130
if (!debugOptions.start) {
129131
await this.debugStartCore(appData, debugOptions);
132+
result.hasReconnected = true;
130133
}
131134

132135
await this.validateRunningApp(device.deviceInfo.identifier, appData.appId);
133136
const debugPort = await this.getForwardedDebugPort(device.deviceInfo.identifier, appData.appId);
134137
await this.printDebugPort(device.deviceInfo.identifier, debugPort);
135138

136-
return this.getChromeDebugUrl(debugOptions, debugPort);
139+
result.debugUrl = this.getChromeDebugUrl(debugOptions, debugPort);
140+
141+
return result;
137142
}
138143

139144
private async printDebugPort(deviceId: string, port: number): Promise<void> {

lib/services/debug-service-base.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export abstract class DebugServiceBase extends EventEmitter implements IDeviceDe
1010

1111
public abstract get platform(): string;
1212

13-
public abstract async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string>;
13+
public abstract async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo>;
1414

1515
public abstract async debugStart(debugData: IDebugData, debugOptions: IDebugOptions): Promise<void>;
1616

lib/services/debug-service.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,6 @@ export class DebugService extends EventEmitter implements IDebugService {
4040
}
4141

4242
const debugOptions: IDebugOptions = _.cloneDeep(options);
43-
44-
// TODO: Check if app is running.
45-
// For now we can only check if app is running on Android.
46-
// After we find a way to check on iOS we should use it here.
47-
let result: string;
48-
4943
const debugService = this.getDeviceDebugService(device);
5044
if (!debugService) {
5145
this.$errors.failWithoutHelp(`Unsupported device OS: ${device.deviceInfo.platform}. You can debug your applications only on iOS or Android.`);
@@ -62,9 +56,9 @@ export class DebugService extends EventEmitter implements IDebugService {
6256
}
6357
}
6458

65-
result = await debugService.debug(debugData, debugOptions);
59+
const debugResultInfo = await debugService.debug(debugData, debugOptions);
6660

67-
return this.getDebugInformation(result, device.deviceInfo.identifier);
61+
return this.getDebugInformation(debugResultInfo, device.deviceInfo.identifier);
6862
}
6963

7064
public debugStop(deviceIdentifier: string): Promise<void> {
@@ -100,16 +94,17 @@ export class DebugService extends EventEmitter implements IDebugService {
10094
platformDebugService.on(CONNECTION_ERROR_EVENT_NAME, connectionErrorHandler);
10195
}
10296

103-
private getDebugInformation(fullUrl: string, deviceIdentifier: string): IDebugInformation {
97+
private getDebugInformation(debugResultInfo: IDebugResultInfo, deviceIdentifier: string): IDebugInformation {
10498
const debugInfo: IDebugInformation = {
105-
url: fullUrl,
99+
url: debugResultInfo.debugUrl,
106100
port: 0,
107-
deviceIdentifier
101+
deviceIdentifier,
102+
hasReconnected: debugResultInfo.hasReconnected
108103
};
109104

110-
if (fullUrl) {
105+
if (debugResultInfo.debugUrl) {
111106
const parseQueryString = true;
112-
const wsQueryParam = <string>parse(fullUrl, parseQueryString).query.ws;
107+
const wsQueryParam = <string>parse(debugResultInfo.debugUrl, parseQueryString).query.ws;
113108
const hostPortSplit = wsQueryParam && wsQueryParam.split(":");
114109
debugInfo.port = hostPortSplit && +hostPortSplit[1];
115110
}

lib/services/ios-device-debug-service.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,21 @@ export class IOSDeviceDebugService extends DebugServiceBase implements IDeviceDe
3838
return "ios";
3939
}
4040

41-
public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string> {
41+
public async debug(debugData: IDebugData, debugOptions: IDebugOptions): Promise<IDebugResultInfo> {
42+
const result: IDebugResultInfo = { hasReconnected: false, debugUrl: null };
4243
this.validateOptions(debugOptions);
4344

4445
await this.startDeviceLogProcess(debugData, debugOptions);
4546
await this.$iOSDebuggerPortService.attachToDebuggerPortFoundEvent(this.device, debugData, debugOptions);
4647

4748
if (!debugOptions.start) {
4849
await this.startApp(debugData, debugOptions);
50+
result.hasReconnected = true;
4951
}
5052

51-
return this.wireDebuggerClient(debugData, debugOptions);
53+
result.debugUrl = await this.wireDebuggerClient(debugData, debugOptions);
54+
55+
return result;
5256
}
5357

5458
public async debugStart(debugData: IDebugData, debugOptions: IDebugOptions): Promise<void> {
@@ -160,8 +164,7 @@ export class IOSDeviceDebugService extends DebugServiceBase implements IDeviceDe
160164
if (debugOptions.chrome) {
161165
this.$logger.info("'--chrome' is the default behavior. Use --inspector to debug iOS applications using the Safari Web Inspector.");
162166
}
163-
const existingWebProxy = this.$appDebugSocketProxyFactory.getWebSocketProxy(this.deviceIdentifier, debugData.applicationIdentifier);
164-
const webSocketProxy = existingWebProxy || await this.$appDebugSocketProxyFactory.addWebSocketProxy(this.device, debugData.applicationIdentifier);
167+
const webSocketProxy = await this.$appDebugSocketProxyFactory.ensureWebSocketProxy(this.device, debugData.applicationIdentifier);
165168

166169
return this.getChromeDebugUrl(debugOptions, webSocketProxy.options.port);
167170
}

0 commit comments

Comments
 (0)