Skip to content

Commit ff5d1e5

Browse files
Add option to use chrome-devtools fronted from appspot (#3071)
* Add option to use chrome-devtools fronted from appspot URLs starting with `chrome-devtools://devtools/` cannot be opened in chrome with code. However, we can open the urls in https://chrome-devtools-frontend.appspot.com/, so add new option in Public API that allows using the remote version. Keep the current default behavior, i.e. for Android we are using the `bundled` DevTools, for iOS we are using a commit pointing to Chrome 55. In case both `useBundledDevTools` and `useHttpUrl` are passed, the value of `useBundledDevTools` is disregarded. Add unit tests for all of the cases. * Add `devToolsCommit` to debug options (and public API) Currently CLI uses specific SHA of dev tools, that corresponds to Chrome 55. However, we may need different version for Android or iOS, so add new option. This will also allow specifying it from public API, so external calls may pass the commit SHA.
1 parent db969b6 commit ff5d1e5

File tree

7 files changed

+425
-18
lines changed

7 files changed

+425
-18
lines changed

PublicAPI.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,25 @@ interface IDebugData {
496496
*/
497497
interface IDebugOptions {
498498
/**
499-
* Defines if bundled Chrome DevTools should be used or specific commit. Valid for iOS only.
499+
* Defines if bundled Chrome DevTools should be used or specific commit.
500+
* Default value is true for Android and false for iOS.
500501
*/
501502
useBundledDevTools?: boolean;
503+
504+
/**
505+
* Defines if https://chrome-devtools-frontend.appspot.com should be used instead of chrome-devtools://devtools
506+
* In case it is passed, the value of `useBundledDevTools` is disregarded.
507+
* Default value is false.
508+
*/
509+
useHttpUrl?: boolean;
510+
511+
/**
512+
* Defines the commit that will be used in cases where remote protocol is required.
513+
* For Android this is the case when useHttpUrl is set to true or useBundledDevTools is set to false.
514+
* For iOS the value is used by default and when useHttpUrl is set to true.
515+
* Default value is 02e6bde1bbe34e43b309d4ef774b1168d25fd024 which corresponds to 55.0.2883 Chrome version
516+
*/
517+
devToolsCommit?: string;
502518
}
503519
```
504520

lib/definitions/debug.d.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,25 @@ interface IDebugOptions {
6868
justlaunch?: boolean;
6969

7070
/**
71-
* Defines if bundled Chrome DevTools should be used or specific commit. Valid for iOS only.
71+
* Defines if bundled Chrome DevTools should be used or specific commit.
72+
* Default value is true for Android and false for iOS.
7273
*/
7374
useBundledDevTools?: boolean;
75+
76+
/**
77+
* Defines if https://chrome-devtools-frontend.appspot.com should be used instead of chrome-devtools://devtools
78+
* In case it is passed, the value of `useBundledDevTools` is disregarded.
79+
* Default value is false.
80+
*/
81+
useHttpUrl?: boolean;
82+
83+
/**
84+
* Defines the commit that will be used in cases where remote protocol is required.
85+
* For Android this is the case when useHttpUrl is set to true or useBundledDevTools is set to false.
86+
* For iOS the value is used by default and when useHttpUrl is set to true.
87+
* Default value is 02e6bde1bbe34e43b309d4ef774b1168d25fd024 which corresponds to 55.0.2883 Chrome version
88+
*/
89+
devToolsCommit?: string;
7490
}
7591

7692
/**

lib/services/android-debug-service.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { sleep } from "../common/helpers";
22
import { ChildProcess } from "child_process";
33
import { DebugServiceBase } from "./debug-service-base";
44

5-
class AndroidDebugService extends DebugServiceBase implements IPlatformDebugService {
5+
export class AndroidDebugService extends DebugServiceBase implements IPlatformDebugService {
66
private _device: Mobile.IAndroidDevice = null;
77
private _debuggerClientProcess: ChildProcess;
88

@@ -49,6 +49,14 @@ class AndroidDebugService extends DebugServiceBase implements IPlatformDebugServ
4949
return;
5050
}
5151

52+
protected getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string {
53+
const debugOpts = _.cloneDeep(debugOptions);
54+
debugOpts.useBundledDevTools = debugOpts.useBundledDevTools === undefined ? true : debugOpts.useBundledDevTools;
55+
56+
const chromeDebugUrl = super.getChromeDebugUrl(debugOpts, port);
57+
return chromeDebugUrl;
58+
}
59+
5260
private async debugOnEmulator(debugData: IDebugData, debugOptions: IDebugOptions): Promise<string> {
5361
// Assure we've detected the emulator as device
5462
// For example in case deployOnEmulator had stated new emulator instance
@@ -124,11 +132,12 @@ class AndroidDebugService extends DebugServiceBase implements IPlatformDebugServ
124132
this.$errors.failWithoutHelp(`The application ${packageName} does not appear to be running on ${deviceId} or is not built with debugging enabled.`);
125133
}
126134

127-
let startDebuggerCommand = ["am", "broadcast", "-a", `\"${packageName}-debug\"`, "--ez", "enable", "true"];
135+
const startDebuggerCommand = ["am", "broadcast", "-a", `\"${packageName}-debug\"`, "--ez", "enable", "true"];
128136
await this.device.adb.executeShellCommand(startDebuggerCommand);
129137

130-
let port = await this.getForwardedLocalDebugPortForPackageName(deviceId, packageName);
131-
return `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${port}`;
138+
const port = await this.getForwardedLocalDebugPortForPackageName(deviceId, packageName);
139+
140+
return this.getChromeDebugUrl(debugOptions, port);
132141
}
133142

134143
private detachDebugger(packageName: string): Promise<void> {

lib/services/debug-service-base.ts

+19
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,23 @@ export abstract class DebugServiceBase extends EventEmitter implements IPlatform
2626
}
2727
};
2828
}
29+
30+
protected getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string {
31+
// corresponds to 55.0.2883 Chrome version
32+
const commitSHA = debugOptions.devToolsCommit || "02e6bde1bbe34e43b309d4ef774b1168d25fd024";
33+
debugOptions.useHttpUrl = debugOptions.useHttpUrl === undefined ? false : debugOptions.useHttpUrl;
34+
35+
let chromeDevToolsPrefix = `chrome-devtools://devtools/remote/serve_file/@${commitSHA}`;
36+
37+
if (debugOptions.useBundledDevTools) {
38+
chromeDevToolsPrefix = "chrome-devtools://devtools/bundled";
39+
}
40+
41+
if (debugOptions.useHttpUrl) {
42+
chromeDevToolsPrefix = `https://chrome-devtools-frontend.appspot.com/serve_file/@${commitSHA}`;
43+
}
44+
45+
const chromeUrl = `${chromeDevToolsPrefix}/inspector.html?experiments=true&ws=localhost:${port}`;
46+
return chromeUrl;
47+
}
2948
}

lib/services/ios-debug-service.ts

+10-12
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const inspectorAppName = "NativeScript Inspector.app";
1414
const inspectorNpmPackageName = "tns-ios-inspector";
1515
const inspectorUiDir = "WebInspectorUI/";
1616

17-
class IOSDebugService extends DebugServiceBase implements IPlatformDebugService {
17+
export class IOSDebugService extends DebugServiceBase implements IPlatformDebugService {
1818
private _lldbProcess: ChildProcess;
1919
private _sockets: net.Socket[] = [];
2020
private _childProcess: ChildProcess;
@@ -93,6 +93,14 @@ class IOSDebugService extends DebugServiceBase implements IPlatformDebugService
9393
}
9494
}
9595

96+
protected getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string {
97+
const debugOpts = _.cloneDeep(debugOptions);
98+
debugOpts.useBundledDevTools = debugOpts.useBundledDevTools === undefined ? false : debugOpts.useBundledDevTools;
99+
100+
const chromeDebugUrl = super.getChromeDebugUrl(debugOpts, port);
101+
return chromeDebugUrl;
102+
}
103+
96104
private async killProcess(childProcess: ChildProcess): Promise<void> {
97105
if (childProcess) {
98106
return new Promise<void>((resolve, reject) => {
@@ -195,17 +203,7 @@ class IOSDebugService extends DebugServiceBase implements IPlatformDebugService
195203
if (debugOptions.chrome) {
196204
this._socketProxy = await this.$socketProxyFactory.createWebSocketProxy(this.getSocketFactory(device));
197205

198-
let chromeDevToolsPrefix = `chrome-devtools://devtools/`;
199-
200-
if (debugOptions.useBundledDevTools) {
201-
chromeDevToolsPrefix += "bundled";
202-
} else {
203-
// corresponds to 55.0.2883 Chrome version
204-
const commitSHA = "02e6bde1bbe34e43b309d4ef774b1168d25fd024";
205-
chromeDevToolsPrefix += `remote/serve_file/@${commitSHA}`;
206-
}
207-
208-
return `${chromeDevToolsPrefix}/inspector.html?experiments=true&ws=localhost:${this._socketProxy.options.port}`;
206+
return this.getChromeDebugUrl(debugOptions, this._socketProxy.options.port);
209207
} else {
210208
this._socketProxy = await this.$socketProxyFactory.createTCPSocketProxy(this.getSocketFactory(device));
211209
await this.openAppInspector(this._socketProxy.address(), debugData, debugOptions);
+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { AndroidDebugService } from "../../lib/services/android-debug-service";
2+
import { Yok } from "../../lib/common/yok";
3+
import * as stubs from "../stubs";
4+
import { assert } from "chai";
5+
6+
const expectedDevToolsCommitSha = "02e6bde1bbe34e43b309d4ef774b1168d25fd024";
7+
8+
class AndroidDebugServiceInheritor extends AndroidDebugService {
9+
constructor(protected $devicesService: Mobile.IDevicesService,
10+
$errors: IErrors,
11+
$logger: ILogger,
12+
$config: IConfiguration,
13+
$androidDeviceDiscovery: Mobile.IDeviceDiscovery,
14+
$androidProcessService: Mobile.IAndroidProcessService,
15+
$net: INet) {
16+
super($devicesService, $errors, $logger, $config, $androidDeviceDiscovery, $androidProcessService, $net);
17+
}
18+
19+
public getChromeDebugUrl(debugOptions: IDebugOptions, port: number): string {
20+
return super.getChromeDebugUrl(debugOptions, port);
21+
}
22+
}
23+
24+
const createTestInjector = (): IInjector => {
25+
const testInjector = new Yok();
26+
testInjector.register("devicesService", {});
27+
testInjector.register("errors", stubs.ErrorsStub);
28+
testInjector.register("logger", stubs.LoggerStub);
29+
testInjector.register("config", {});
30+
testInjector.register("androidDeviceDiscovery", {});
31+
testInjector.register("androidProcessService", {});
32+
testInjector.register("net", {});
33+
34+
return testInjector;
35+
};
36+
37+
interface IChromeUrlTestCase {
38+
debugOptions: IDebugOptions;
39+
expectedChromeUrl: string;
40+
scenarioName: string;
41+
}
42+
43+
describe("androidDebugService", () => {
44+
describe("getChromeDebugUrl", () => {
45+
const expectedPort = 12345;
46+
const customDevToolsCommit = "customDevToolsCommit";
47+
48+
const chromUrlTestCases: IChromeUrlTestCase[] = [
49+
// Default CLI behavior:
50+
{
51+
scenarioName: "useBundledDevTools and useHttpUrl are not passed",
52+
debugOptions: {},
53+
expectedChromeUrl: `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
54+
},
55+
56+
// When useBundledDevTools is true
57+
{
58+
scenarioName: "useBundledDevTools is true and useHttpUrl is not passed",
59+
debugOptions: {
60+
useBundledDevTools: true
61+
},
62+
expectedChromeUrl: `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
63+
},
64+
{
65+
scenarioName: "useBundledDevTools is true and useHttpUrl is false",
66+
debugOptions: {
67+
useBundledDevTools: true,
68+
useHttpUrl: false
69+
},
70+
expectedChromeUrl: `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
71+
},
72+
{
73+
scenarioName: "useBundledDevTools is true and useHttpUrl is true",
74+
debugOptions: {
75+
useBundledDevTools: true,
76+
useHttpUrl: true
77+
},
78+
expectedChromeUrl: `https://chrome-devtools-frontend.appspot.com/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
79+
},
80+
81+
// When useBundledDevTools is false
82+
{
83+
scenarioName: "useBundledDevTools is false and useHttpUrl is not passed",
84+
debugOptions: {
85+
useBundledDevTools: false
86+
},
87+
expectedChromeUrl: `chrome-devtools://devtools/remote/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
88+
},
89+
{
90+
scenarioName: "useBundledDevTools is false and useHttpUrl is false",
91+
debugOptions: {
92+
useBundledDevTools: false,
93+
useHttpUrl: false
94+
},
95+
expectedChromeUrl: `chrome-devtools://devtools/remote/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
96+
},
97+
{
98+
scenarioName: "useBundledDevTools is false and useHttpUrl is true",
99+
debugOptions: {
100+
useBundledDevTools: false,
101+
useHttpUrl: true
102+
},
103+
expectedChromeUrl: `https://chrome-devtools-frontend.appspot.com/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
104+
},
105+
106+
// When useBundledDevTools is not passed
107+
{
108+
scenarioName: "useBundledDevTools is not passed and useHttpUrl is false",
109+
debugOptions: {
110+
useHttpUrl: false
111+
},
112+
expectedChromeUrl: `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
113+
},
114+
{
115+
scenarioName: "useBundledDevTools is not passed and useHttpUrl is true",
116+
debugOptions: {
117+
useHttpUrl: true
118+
},
119+
expectedChromeUrl: `https://chrome-devtools-frontend.appspot.com/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
120+
},
121+
122+
// devToolsCommit tests
123+
{
124+
scenarioName: "devToolsCommit defaults to ${expectedDevToolsCommitSha} when useBundledDevTools is set to false",
125+
debugOptions: {
126+
useBundledDevTools: false
127+
},
128+
expectedChromeUrl: `chrome-devtools://devtools/remote/serve_file/@${expectedDevToolsCommitSha}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
129+
},
130+
{
131+
scenarioName: "devToolsCommit is disregarded when useBundledDevTools is not passed",
132+
debugOptions: {},
133+
expectedChromeUrl: `chrome-devtools://devtools/bundled/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
134+
},
135+
{
136+
scenarioName: "devToolsCommit is set to passed value when useBundledDevTools is set to false",
137+
debugOptions: {
138+
useBundledDevTools: false,
139+
devToolsCommit: customDevToolsCommit
140+
},
141+
expectedChromeUrl: `chrome-devtools://devtools/remote/serve_file/@${customDevToolsCommit}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
142+
},
143+
{
144+
scenarioName: "devToolsCommit is set to passed value when useHttpUrl is set to true",
145+
debugOptions: {
146+
useHttpUrl: true,
147+
devToolsCommit: customDevToolsCommit
148+
},
149+
expectedChromeUrl: `https://chrome-devtools-frontend.appspot.com/serve_file/@${customDevToolsCommit}/inspector.html?experiments=true&ws=localhost:${expectedPort}`,
150+
}
151+
];
152+
153+
for (const testCase of chromUrlTestCases) {
154+
it(`returns correct url when ${testCase.scenarioName}`, () => {
155+
const testInjector = createTestInjector();
156+
const androidDebugService = testInjector.resolve<AndroidDebugServiceInheritor>(AndroidDebugServiceInheritor);
157+
const actualChromeUrl = androidDebugService.getChromeDebugUrl(testCase.debugOptions, expectedPort);
158+
assert.equal(actualChromeUrl, testCase.expectedChromeUrl);
159+
});
160+
}
161+
});
162+
});

0 commit comments

Comments
 (0)