@aiot-toolkit/emulator 2.0.2-beta.5 → 2.0.2-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/instance/common.d.ts +8 -11
- package/lib/instance/common.js +28 -136
- package/lib/instance/dev.d.ts +24 -4
- package/lib/instance/dev.js +62 -36
- package/lib/instance/miwear.d.ts +12 -2
- package/lib/instance/miwear.js +96 -46
- package/lib/instance/preDev.d.ts +0 -6
- package/lib/instance/preDev.js +9 -44
- package/lib/static/constants.d.ts +2 -0
- package/lib/static/constants.js +3 -1
- package/lib/typing/Instance.d.ts +2 -0
- package/package.json +4 -4
package/lib/instance/common.d.ts
CHANGED
|
@@ -10,33 +10,30 @@ declare class CommonInstance {
|
|
|
10
10
|
projectPath: string;
|
|
11
11
|
sdkHome: string;
|
|
12
12
|
avdHome: string;
|
|
13
|
-
adbPort: number;
|
|
14
|
-
debugPort: number;
|
|
15
13
|
velaAvdCls: VelaAvdCls;
|
|
16
14
|
goldfishProcess: ChildProcess | undefined;
|
|
17
15
|
isFirstStart: boolean;
|
|
18
16
|
startOptions: IStartOptions | undefined;
|
|
19
17
|
projectInfo: IManifest;
|
|
20
18
|
isRpk: boolean;
|
|
19
|
+
sn?: string;
|
|
21
20
|
constructor(params: INewGoldfishInstanceParams);
|
|
22
21
|
/** 获取模拟器二进制文件所在位置 */
|
|
23
22
|
getEmulatorBinPath(): string;
|
|
24
23
|
/** 在goldfish模拟器中运行快应用 */
|
|
25
24
|
start(options: IStartOptions): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
connectGoldfish(): Promise<
|
|
32
|
-
/** 将打包后的文件推到挂载的快应用目录 */
|
|
33
|
-
pushRpk(sourceRoot: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* 通过adb连接模拟器。
|
|
27
|
+
* 时间限制为10s,超时则表示连接失败
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
connectGoldfish(): Promise<unknown>;
|
|
34
31
|
/** 杀死进程 */
|
|
35
32
|
killProcess(currProcess?: ChildProcess): void;
|
|
36
33
|
/** 停止模拟器并释放相关资源 */
|
|
37
34
|
stop(): Promise<void>;
|
|
38
35
|
/** 重启模拟器 */
|
|
39
|
-
restart(): void
|
|
36
|
+
restart(): Promise<void>;
|
|
40
37
|
/** 创建server */
|
|
41
38
|
createWebsockeServer(): Promise<void>;
|
|
42
39
|
}
|
package/lib/instance/common.js
CHANGED
|
@@ -41,7 +41,6 @@ const adbMiwt = __importStar(require("@miwt/adb"));
|
|
|
41
41
|
const child_process_1 = require("child_process");
|
|
42
42
|
const os_1 = __importDefault(require("os"));
|
|
43
43
|
const path_1 = __importDefault(require("path"));
|
|
44
|
-
const portfinder_1 = __importDefault(require("portfinder"));
|
|
45
44
|
const ws_1 = require("ws");
|
|
46
45
|
const avd_1 = __importDefault(require("../avd"));
|
|
47
46
|
const constants_1 = require("../static/constants");
|
|
@@ -51,8 +50,6 @@ const utils_1 = require("../utils");
|
|
|
51
50
|
*/
|
|
52
51
|
class CommonInstance {
|
|
53
52
|
constructor(params) {
|
|
54
|
-
this.adbPort = 5555;
|
|
55
|
-
this.debugPort = 10055;
|
|
56
53
|
this.isFirstStart = true;
|
|
57
54
|
this.projectPath = params.projectPath;
|
|
58
55
|
this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
|
|
@@ -74,154 +71,44 @@ class CommonInstance {
|
|
|
74
71
|
}
|
|
75
72
|
/** 在goldfish模拟器中运行快应用 */
|
|
76
73
|
start(options) {
|
|
77
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
-
this.startOptions = options;
|
|
79
|
-
// 启动模拟器
|
|
80
|
-
yield this.startGoldfish(options);
|
|
81
|
-
const connected = yield this.connectGoldfish();
|
|
82
|
-
if (connected) {
|
|
83
|
-
ColorConsole_1.default.log('### Emulator ### Goldfish emulator connected successfully');
|
|
84
|
-
if (this.isFirstStart && this.startOptions.serverPort) {
|
|
85
|
-
yield this.createWebsockeServer();
|
|
86
|
-
}
|
|
87
|
-
// adb push快应用到模拟器的/data/app目录
|
|
88
|
-
const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
|
|
89
|
-
this.pushRpk(buildedFilesPath);
|
|
90
|
-
// 在模拟器中启动快应用
|
|
91
|
-
this.startupQuickApp(options);
|
|
92
|
-
this.isFirstStart = false;
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
/** 在goldfish中启动快应用 */
|
|
100
|
-
startupQuickApp(options) {
|
|
101
|
-
try {
|
|
102
|
-
let vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp app/${this.projectInfo.package} &`;
|
|
103
|
-
if (options.devtool) {
|
|
104
|
-
vappCmd = `adb -s 127.0.0.1:${this.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${this.projectInfo.package} &`;
|
|
105
|
-
}
|
|
106
|
-
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
107
|
-
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
108
|
-
adbMiwt.execAdbCmdAsync(vappCmd, { stdio: 'ignore', encoding: 'utf-8' });
|
|
109
|
-
}
|
|
110
|
-
catch (e) {
|
|
111
|
-
ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
/** 启动goldfish模拟器 */
|
|
115
|
-
startGoldfish(options) {
|
|
116
|
-
var _a;
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
const { avdName, devtool } = options;
|
|
119
|
-
const emulatorBin = this.getEmulatorBinPath();
|
|
120
|
-
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
121
|
-
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
122
|
-
const { avdArch, avdImagePath } = avdInfo;
|
|
123
|
-
this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
|
|
124
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
125
|
-
if (!avdImagePath) {
|
|
126
|
-
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
127
|
-
}
|
|
128
|
-
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
129
|
-
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
130
|
-
// 端口映射
|
|
131
|
-
const adbPortMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
|
|
132
|
-
let debugPortMappingStr = '';
|
|
133
|
-
if (devtool) {
|
|
134
|
-
debugPortMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
135
|
-
}
|
|
136
|
-
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
137
|
-
const systemImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/system.img');
|
|
138
|
-
const dataImageBin = path_1.default.resolve(this.sdkHome, 'tools/image/data.img');
|
|
139
|
-
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
|
|
140
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
141
|
-
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
|
|
142
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
143
|
-
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
144
|
-
// vnc配置
|
|
145
|
-
let windowStr = '';
|
|
146
|
-
let vncStr = '';
|
|
147
|
-
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
|
|
148
|
-
windowStr = '-no-window';
|
|
149
|
-
const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
|
|
150
|
-
vncStr = `-vnc :${portSuffix}`;
|
|
151
|
-
}
|
|
152
|
-
const stdioType = options.disableNSH ? 'pipe' : 'inherit';
|
|
153
|
-
// 启动goldfish的命令和参数
|
|
154
|
-
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${adbPortMappingStr} ${debugPortMappingStr} -qemu ${windowStr} ${vncStr} ${imageMountStr}`;
|
|
155
|
-
const spawnArgs = cmd.split(' ');
|
|
156
|
-
const spawnBin = spawnArgs.shift();
|
|
157
|
-
ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
|
|
158
|
-
return new Promise((resolve) => {
|
|
159
|
-
var _a, _b;
|
|
160
|
-
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
|
|
161
|
-
if (options.disableNSH) {
|
|
162
|
-
(_a = this.goldfishProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
163
|
-
console.log(data.toString());
|
|
164
|
-
if (data.toString().includes('(NSH)')) {
|
|
165
|
-
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
166
|
-
resolve();
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
(_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
170
|
-
console.log(data.toString());
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
setTimeout(() => {
|
|
175
|
-
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
176
|
-
resolve();
|
|
177
|
-
}, 2000);
|
|
178
|
-
}
|
|
179
|
-
this.goldfishProcess.on('exit', (code) => {
|
|
180
|
-
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
});
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () { });
|
|
184
75
|
}
|
|
185
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* 通过adb连接模拟器。
|
|
78
|
+
* 时间限制为10s,超时则表示连接失败
|
|
79
|
+
* @returns
|
|
80
|
+
*/
|
|
186
81
|
connectGoldfish() {
|
|
187
82
|
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
-
let adbConnected = false;
|
|
83
|
+
let adbConnected = false; // adb是否连接成功
|
|
84
|
+
let enableLoop = true; // 是否允许循环,用于终止adb的连接
|
|
189
85
|
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
190
|
-
|
|
191
|
-
while (!adbConnected) {
|
|
86
|
+
while (enableLoop && !adbConnected) {
|
|
192
87
|
const adbKillCmd = `adb kill-server`;
|
|
193
88
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
194
89
|
adbMiwt.execAdbCmdSync(adbKillCmd);
|
|
195
|
-
const adbConnectCmd = `adb connect ${sn}`;
|
|
90
|
+
const adbConnectCmd = `adb connect ${this.sn}`;
|
|
196
91
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
197
92
|
const str = adbMiwt.execAdbCmdSync(adbConnectCmd);
|
|
198
93
|
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
199
94
|
const devices = yield adbMiwt.getAdbDevices();
|
|
200
95
|
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
201
96
|
adbConnected =
|
|
202
|
-
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
97
|
+
devices.filter((item) => item.sn === this.sn && item.status === 'device').length > 0;
|
|
203
98
|
}
|
|
204
|
-
Promise.resolve(adbConnected);
|
|
99
|
+
return Promise.resolve(adbConnected);
|
|
205
100
|
});
|
|
206
|
-
yield Promise.race([
|
|
101
|
+
const res = yield Promise.race([
|
|
207
102
|
connectFn(),
|
|
208
103
|
new Promise((resolve) => {
|
|
209
|
-
setTimeout(() =>
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
enableLoop = false;
|
|
106
|
+
// 超时则认为adb没有连接成功
|
|
107
|
+
resolve(false);
|
|
108
|
+
}, 10 * 1000);
|
|
210
109
|
})
|
|
211
110
|
]);
|
|
212
|
-
return
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
/** 将打包后的文件推到挂载的快应用目录 */
|
|
216
|
-
pushRpk(sourceRoot) {
|
|
217
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
219
|
-
const { package: appPackageName } = UxFileUtils_1.default.getMainfestInfo(this.projectPath);
|
|
220
|
-
const appRunDir = '/data/app';
|
|
221
|
-
ColorConsole_1.default.log(`### Emulator ### Pushing ${appPackageName} to ${appRunDir}`);
|
|
222
|
-
(0, child_process_1.execSync)(`adb -s ${sn} shell mkdir ${appRunDir}/${appPackageName}`, { stdio: 'ignore' });
|
|
223
|
-
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourceRoot}/* ${appRunDir}/${appPackageName}`);
|
|
224
|
-
ColorConsole_1.default.log(`### Emulator ### Push ${appPackageName} to ${appRunDir} successfully`);
|
|
111
|
+
return res;
|
|
225
112
|
});
|
|
226
113
|
}
|
|
227
114
|
/** 杀死进程 */
|
|
@@ -246,7 +133,7 @@ class CommonInstance {
|
|
|
246
133
|
}
|
|
247
134
|
/** 停止模拟器并释放相关资源 */
|
|
248
135
|
stop() {
|
|
249
|
-
var _a;
|
|
136
|
+
var _a, _b;
|
|
250
137
|
return __awaiter(this, void 0, void 0, function* () {
|
|
251
138
|
if (this.goldfishProcess) {
|
|
252
139
|
// Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
|
|
@@ -255,15 +142,20 @@ class CommonInstance {
|
|
|
255
142
|
// process.kill(this.goldfishProcess.pid + 1)
|
|
256
143
|
// }
|
|
257
144
|
this.killProcess(this.goldfishProcess);
|
|
258
|
-
|
|
145
|
+
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.avdName) {
|
|
146
|
+
const emulatorProcessFlag = `-avd ${(_b = this.startOptions) === null || _b === void 0 ? void 0 : _b.avdName} -avd-arch`;
|
|
147
|
+
yield (0, utils_1.killProcessByCmd)(emulatorProcessFlag);
|
|
148
|
+
}
|
|
259
149
|
this.goldfishProcess = undefined;
|
|
260
150
|
}
|
|
261
151
|
});
|
|
262
152
|
}
|
|
263
153
|
/** 重启模拟器 */
|
|
264
154
|
restart() {
|
|
265
|
-
this
|
|
266
|
-
|
|
155
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
156
|
+
yield this.stop();
|
|
157
|
+
this.start(this.startOptions);
|
|
158
|
+
});
|
|
267
159
|
}
|
|
268
160
|
/** 创建server */
|
|
269
161
|
createWebsockeServer() {
|
package/lib/instance/dev.d.ts
CHANGED
|
@@ -3,13 +3,33 @@ import CommonInstance from './common';
|
|
|
3
3
|
declare class GoldfishInstance extends CommonInstance {
|
|
4
4
|
private appRunDir;
|
|
5
5
|
constructor(params: INewGoldfishInstanceParams);
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* 1. 启动模拟器
|
|
8
|
+
* 2. 启动成功后,adb连接模拟器
|
|
9
|
+
* 3. 连接成功后,在模拟器中启动快应用
|
|
10
|
+
*/
|
|
7
11
|
start(options: IStartOptions): Promise<void>;
|
|
8
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* 在模拟器中启动快应用
|
|
14
|
+
* 通过vapp命令启动,调试时需额外配置--jsdebugger参数
|
|
15
|
+
* @param options
|
|
16
|
+
*/
|
|
9
17
|
startupQuickApp(options: IStartOptions): Promise<void>;
|
|
10
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* 启动模拟器
|
|
20
|
+
* 1. 通过options生成模拟器的启动命令
|
|
21
|
+
* 2. 执行启动命令
|
|
22
|
+
* 3. 判断模拟器是否启动成功
|
|
23
|
+
* 3.1 若disableNSH=true,输出流中匹配到(NSH),认为模拟器启动成功了
|
|
24
|
+
* 3.2 若disableNSH=false,认为2s过后模拟器启动成功了
|
|
25
|
+
* @param options
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
11
28
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
12
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* 将目录通过adb push到模拟器中
|
|
31
|
+
* @param sourceRoot
|
|
32
|
+
*/
|
|
13
33
|
pushRpk(sourceRoot: string): Promise<void>;
|
|
14
34
|
}
|
|
15
35
|
export default GoldfishInstance;
|
package/lib/instance/dev.js
CHANGED
|
@@ -39,18 +39,23 @@ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/C
|
|
|
39
39
|
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
40
40
|
const child_process_1 = require("child_process");
|
|
41
41
|
const path_1 = __importDefault(require("path"));
|
|
42
|
-
const portfinder_1 = __importDefault(require("portfinder"));
|
|
43
42
|
const constants_1 = require("../static/constants");
|
|
44
43
|
const common_1 = __importDefault(require("./common"));
|
|
44
|
+
const os_1 = __importDefault(require("os"));
|
|
45
45
|
class GoldfishInstance extends common_1.default {
|
|
46
46
|
constructor(params) {
|
|
47
47
|
super(params);
|
|
48
48
|
this.appRunDir = '/data/app';
|
|
49
49
|
}
|
|
50
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* 1. 启动模拟器
|
|
52
|
+
* 2. 启动成功后,adb连接模拟器
|
|
53
|
+
* 3. 连接成功后,在模拟器中启动快应用
|
|
54
|
+
*/
|
|
51
55
|
start(options) {
|
|
52
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
53
57
|
this.startOptions = options;
|
|
58
|
+
this.sn = `127.0.0.1:${this.startOptions.adbPort}`;
|
|
54
59
|
// 启动模拟器
|
|
55
60
|
yield this.startGoldfish(options);
|
|
56
61
|
const connected = yield this.connectGoldfish();
|
|
@@ -71,14 +76,18 @@ class GoldfishInstance extends common_1.default {
|
|
|
71
76
|
}
|
|
72
77
|
});
|
|
73
78
|
}
|
|
74
|
-
/**
|
|
79
|
+
/**
|
|
80
|
+
* 在模拟器中启动快应用
|
|
81
|
+
* 通过vapp命令启动,调试时需额外配置--jsdebugger参数
|
|
82
|
+
* @param options
|
|
83
|
+
*/
|
|
75
84
|
startupQuickApp(options) {
|
|
76
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
77
86
|
try {
|
|
78
87
|
const { package: packageName } = this.projectInfo;
|
|
79
|
-
let vappCmd = `adb -s 127.0.0.1:${
|
|
88
|
+
let vappCmd = `adb -s 127.0.0.1:${options.adbPort} shell vapp app/${packageName} &`;
|
|
80
89
|
if (options.devtool) {
|
|
81
|
-
vappCmd = `adb -s 127.0.0.1:${
|
|
90
|
+
vappCmd = `adb -s 127.0.0.1:${options.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
|
|
82
91
|
}
|
|
83
92
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
84
93
|
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
@@ -89,7 +98,16 @@ class GoldfishInstance extends common_1.default {
|
|
|
89
98
|
}
|
|
90
99
|
});
|
|
91
100
|
}
|
|
92
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* 启动模拟器
|
|
103
|
+
* 1. 通过options生成模拟器的启动命令
|
|
104
|
+
* 2. 执行启动命令
|
|
105
|
+
* 3. 判断模拟器是否启动成功
|
|
106
|
+
* 3.1 若disableNSH=true,输出流中匹配到(NSH),认为模拟器启动成功了
|
|
107
|
+
* 3.2 若disableNSH=false,认为2s过后模拟器启动成功了
|
|
108
|
+
* @param options
|
|
109
|
+
* @returns
|
|
110
|
+
*/
|
|
93
111
|
startGoldfish(options) {
|
|
94
112
|
var _a;
|
|
95
113
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -98,21 +116,20 @@ class GoldfishInstance extends common_1.default {
|
|
|
98
116
|
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
99
117
|
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
100
118
|
const { avdArch, avdImagePath } = avdInfo;
|
|
101
|
-
|
|
102
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
119
|
+
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
103
120
|
if (!avdImagePath) {
|
|
104
121
|
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
105
122
|
}
|
|
106
123
|
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
107
124
|
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
108
125
|
// 端口映射
|
|
109
|
-
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${
|
|
126
|
+
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${options.adbPort}-10.0.2.15:5555`;
|
|
110
127
|
if (devtool) {
|
|
111
|
-
portMappingStr += `,hostfwd=tcp:127.0.0.1:${
|
|
128
|
+
portMappingStr += `,hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
112
129
|
}
|
|
113
130
|
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
114
|
-
const systemImageBin = path_1.default.resolve(
|
|
115
|
-
const dataImageBin = path_1.default.resolve(
|
|
131
|
+
const systemImageBin = path_1.default.resolve(avdImagePath, 'system.img');
|
|
132
|
+
const dataImageBin = path_1.default.resolve(avdImagePath, 'data.img');
|
|
116
133
|
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
|
|
117
134
|
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
118
135
|
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
|
|
@@ -135,23 +152,26 @@ class GoldfishInstance extends common_1.default {
|
|
|
135
152
|
return new Promise((resolve) => {
|
|
136
153
|
var _a, _b;
|
|
137
154
|
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
|
|
155
|
+
(_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
156
|
+
const stderrCb = options.stderrCallback || console.log;
|
|
157
|
+
stderrCb(data.toString());
|
|
158
|
+
});
|
|
159
|
+
this.goldfishProcess.on('exit', (code) => {
|
|
160
|
+
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
161
|
+
if (options.exitCallback) {
|
|
162
|
+
options.exitCallback(code);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
138
165
|
if (options.disableNSH) {
|
|
139
|
-
(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
else {
|
|
144
|
-
console.log(data.toString());
|
|
145
|
-
}
|
|
166
|
+
(_b = this.goldfishProcess.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
167
|
+
const msg = data.toString();
|
|
168
|
+
const stdoutCb = options.stdoutCallback || console.log;
|
|
169
|
+
stdoutCb(msg);
|
|
146
170
|
if (data.toString().includes('(NSH)')) {
|
|
147
171
|
ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
|
|
148
172
|
resolve();
|
|
149
173
|
}
|
|
150
174
|
});
|
|
151
|
-
(_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
152
|
-
const stderrCb = options.stderrCallback || console.log;
|
|
153
|
-
stderrCb(data.toString());
|
|
154
|
-
});
|
|
155
175
|
}
|
|
156
176
|
else {
|
|
157
177
|
setTimeout(() => {
|
|
@@ -159,25 +179,31 @@ class GoldfishInstance extends common_1.default {
|
|
|
159
179
|
resolve();
|
|
160
180
|
}, 2000);
|
|
161
181
|
}
|
|
162
|
-
this.goldfishProcess.on('exit', (code) => {
|
|
163
|
-
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
164
|
-
if (options.exitCallback) {
|
|
165
|
-
options.exitCallback(code);
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
182
|
});
|
|
169
183
|
});
|
|
170
184
|
}
|
|
171
|
-
/**
|
|
185
|
+
/**
|
|
186
|
+
* 将目录通过adb push到模拟器中
|
|
187
|
+
* @param sourceRoot
|
|
188
|
+
*/
|
|
172
189
|
pushRpk(sourceRoot) {
|
|
173
190
|
return __awaiter(this, void 0, void 0, function* () {
|
|
174
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
191
|
+
const sn = `127.0.0.1:${this.startOptions.adbPort}`;
|
|
175
192
|
const { package: appPackageName } = this.projectInfo;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
// 获取最后一层目录,比如build
|
|
194
|
+
const basename = path_1.default.basename(sourceRoot);
|
|
195
|
+
if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
|
|
196
|
+
// windows系统或者项目路径有空格:1. adb push目录;2. 在模拟器中使用mv命令重命名
|
|
197
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourceRoot} ${this.appRunDir}`);
|
|
198
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mv ${this.appRunDir}/${basename} ${this.appRunDir}/${appPackageName}`);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// 支持通配符处理: 1. 模拟器中mkdir创建目录 2. adb push ./XXXXX/* /XXX
|
|
202
|
+
const sourcePath = path_1.default.resolve(sourceRoot, './*');
|
|
203
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`);
|
|
204
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push "${sourcePath}" ${this.appRunDir}/${appPackageName}`);
|
|
205
|
+
}
|
|
206
|
+
ColorConsole_1.default.info(`### Emulator push to ${this.appRunDir}/${appPackageName} successfully`);
|
|
181
207
|
});
|
|
182
208
|
}
|
|
183
209
|
}
|
package/lib/instance/miwear.d.ts
CHANGED
|
@@ -29,10 +29,12 @@ declare class MiwearInstance extends CommonInstance {
|
|
|
29
29
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
30
30
|
/**
|
|
31
31
|
* 通过adb连接模拟器。
|
|
32
|
-
* 时间限制为
|
|
32
|
+
* 时间限制为2分钟,超时则表示连接失败
|
|
33
|
+
* 注意:两次connect之间不能等待,否则在disableNSH=true且有vncPort的模式下,模拟器启动成功了,但是vnc可能还没连接上
|
|
34
|
+
* 时间限制不能太短,否则模拟器里面的adbd进程还没初始化成功
|
|
33
35
|
* @returns
|
|
34
36
|
*/
|
|
35
|
-
connectGoldfish(): Promise<
|
|
37
|
+
connectGoldfish(): Promise<unknown>;
|
|
36
38
|
/**
|
|
37
39
|
* 在模拟器中启动快应用
|
|
38
40
|
* 1. 检查release目录是否有打包好的rpk
|
|
@@ -62,6 +64,14 @@ declare class MiwearInstance extends CommonInstance {
|
|
|
62
64
|
* 3. 发送Page.reload命令给调试服务,通知更新
|
|
63
65
|
*/
|
|
64
66
|
handleUpdate(): Promise<void>;
|
|
67
|
+
/** 热更新时push目录 */
|
|
68
|
+
pushBuild(): Promise<void>;
|
|
69
|
+
/** 在模拟器中重启快应用(基于am命令,需要保证镜像中已经有am功能)
|
|
70
|
+
* 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
|
|
71
|
+
* 2. nsh中执行am stop命令退出快应用
|
|
72
|
+
* 3. nsh中执行am start命令启动快应用
|
|
73
|
+
*/
|
|
74
|
+
reloadApp(): Promise<void>;
|
|
65
75
|
/**
|
|
66
76
|
* 创建server端,监听打包过程中client端发来的消息
|
|
67
77
|
*/
|
package/lib/instance/miwear.js
CHANGED
|
@@ -41,11 +41,11 @@ const child_process_1 = require("child_process");
|
|
|
41
41
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
42
42
|
const os_1 = __importDefault(require("os"));
|
|
43
43
|
const path_1 = __importDefault(require("path"));
|
|
44
|
-
const portfinder_1 = __importDefault(require("portfinder"));
|
|
45
44
|
const ws_1 = __importStar(require("ws"));
|
|
46
45
|
const constants_1 = require("../static/constants");
|
|
47
46
|
const utils_1 = require("../utils");
|
|
48
47
|
const common_1 = __importDefault(require("./common"));
|
|
48
|
+
const dayjs_1 = __importDefault(require("dayjs"));
|
|
49
49
|
const MAX_RECONNECT_COUNT = 8;
|
|
50
50
|
/**
|
|
51
51
|
* MiwearInstance
|
|
@@ -66,6 +66,7 @@ class MiwearInstance extends common_1.default {
|
|
|
66
66
|
start(options) {
|
|
67
67
|
return __awaiter(this, void 0, void 0, function* () {
|
|
68
68
|
this.startOptions = options;
|
|
69
|
+
this.sn = `127.0.0.1:${this.startOptions.adbPort}`;
|
|
69
70
|
// 启动模拟器
|
|
70
71
|
yield this.startGoldfish(options);
|
|
71
72
|
// adb连接模拟器
|
|
@@ -105,28 +106,41 @@ class MiwearInstance extends common_1.default {
|
|
|
105
106
|
// 获取vela镜像的绝对路径
|
|
106
107
|
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
107
108
|
const { avdArch, avdImagePath } = avdInfo;
|
|
108
|
-
|
|
109
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
109
|
+
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
110
110
|
if (!avdImagePath) {
|
|
111
111
|
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
112
112
|
}
|
|
113
113
|
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
114
114
|
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
115
115
|
// 端口映射,adb端口和debug端口
|
|
116
|
-
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${
|
|
116
|
+
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${options.adbPort}-10.0.2.15:5555`;
|
|
117
117
|
if (devtool) {
|
|
118
|
-
|
|
119
|
-
portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
118
|
+
portMappingStr += `,hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
120
119
|
}
|
|
121
|
-
//
|
|
122
|
-
const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.bin');
|
|
123
|
-
const dataImageBin = path_1.default.resolve(avdImagePath, 'vela_data.bin');
|
|
124
|
-
const coreBin = path_1.default.resolve(avdImagePath, 'coredump.core');
|
|
125
|
-
|
|
120
|
+
// 设备挂载节点
|
|
121
|
+
const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.bin'); // 只读
|
|
122
|
+
const dataImageBin = path_1.default.resolve(avdImagePath, 'vela_data.bin'); // 可读可写
|
|
123
|
+
const coreBin = path_1.default.resolve(avdImagePath, 'coredump.core'); // 只读
|
|
124
|
+
// 复制可写文件到AVD目录下(多模拟器实例时需要)
|
|
125
|
+
const dataImageBinInAvd = path_1.default.join(this.avdHome, `${avdName}.avd`, 'vela_data.bin');
|
|
126
|
+
if (!fs_extra_1.default.existsSync(dataImageBinInAvd)) {
|
|
127
|
+
// vela_data.bin不存在时直接copy
|
|
128
|
+
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// vela_data.bin存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
|
|
132
|
+
const statsInAvd = fs_extra_1.default.statSync(dataImageBinInAvd);
|
|
133
|
+
const stats = fs_extra_1.default.statSync(dataImageBin);
|
|
134
|
+
if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
|
|
135
|
+
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// 挂载节点配置,只读文件加入read-only标识
|
|
139
|
+
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin},read-only \
|
|
126
140
|
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
127
|
-
-drive index=1,id=userdata,if=none,format=raw,file=${
|
|
141
|
+
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBinInAvd} \
|
|
128
142
|
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
129
|
-
-drive index=2,id=vendor,if=none,format=raw,file=${coreBin} \
|
|
143
|
+
-drive index=2,id=vendor,if=none,format=raw,file=${coreBin},read-only \
|
|
130
144
|
-device virtio-blk-device,bus=virtio-mmio-bus.4,drive=vendor \
|
|
131
145
|
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
132
146
|
// vnc配置
|
|
@@ -183,19 +197,21 @@ class MiwearInstance extends common_1.default {
|
|
|
183
197
|
}
|
|
184
198
|
/**
|
|
185
199
|
* 通过adb连接模拟器。
|
|
186
|
-
* 时间限制为
|
|
200
|
+
* 时间限制为2分钟,超时则表示连接失败
|
|
201
|
+
* 注意:两次connect之间不能等待,否则在disableNSH=true且有vncPort的模式下,模拟器启动成功了,但是vnc可能还没连接上
|
|
202
|
+
* 时间限制不能太短,否则模拟器里面的adbd进程还没初始化成功
|
|
187
203
|
* @returns
|
|
188
204
|
*/
|
|
189
205
|
connectGoldfish() {
|
|
190
206
|
return __awaiter(this, void 0, void 0, function* () {
|
|
191
|
-
let adbConnected = false;
|
|
207
|
+
let adbConnected = false; // adb是否连接成功
|
|
208
|
+
let enableLoop = true; // 是否允许循环,用于终止adb的连接
|
|
192
209
|
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
193
|
-
|
|
194
|
-
while (!adbConnected) {
|
|
210
|
+
while (enableLoop && !adbConnected) {
|
|
195
211
|
const adbKillCmd = `adb kill-server`;
|
|
196
212
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
197
213
|
yield adbMiwt.execAdbCmdAsync(adbKillCmd);
|
|
198
|
-
const adbConnectCmd = `adb connect ${sn}`;
|
|
214
|
+
const adbConnectCmd = `adb connect ${this.sn}`;
|
|
199
215
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
200
216
|
const str = yield adbMiwt.execAdbCmdAsync(adbConnectCmd);
|
|
201
217
|
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
@@ -203,17 +219,21 @@ class MiwearInstance extends common_1.default {
|
|
|
203
219
|
const devices = yield adbMiwt.getAdbDevices();
|
|
204
220
|
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
205
221
|
adbConnected =
|
|
206
|
-
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
222
|
+
devices.filter((item) => item.sn === this.sn && item.status === 'device').length > 0;
|
|
207
223
|
}
|
|
208
|
-
Promise.resolve(adbConnected);
|
|
224
|
+
return Promise.resolve(adbConnected);
|
|
209
225
|
});
|
|
210
|
-
yield Promise.race([
|
|
226
|
+
const res = yield Promise.race([
|
|
211
227
|
connectFn(),
|
|
212
228
|
new Promise((resolve) => {
|
|
213
|
-
setTimeout(() =>
|
|
229
|
+
setTimeout(() => {
|
|
230
|
+
enableLoop = false;
|
|
231
|
+
// 超时则认为adb没有连接成功
|
|
232
|
+
resolve(false);
|
|
233
|
+
}, 120 * 1000);
|
|
214
234
|
})
|
|
215
235
|
]);
|
|
216
|
-
return
|
|
236
|
+
return res;
|
|
217
237
|
});
|
|
218
238
|
}
|
|
219
239
|
/**
|
|
@@ -240,13 +260,12 @@ class MiwearInstance extends common_1.default {
|
|
|
240
260
|
}
|
|
241
261
|
const rpkPath = path_1.default.resolve(releaseDir, files[0]);
|
|
242
262
|
// 调试模式需要push一个文件至miwear中
|
|
243
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
244
263
|
if (options.devtool) {
|
|
245
264
|
const debuggerCfgFile = path_1.default.join(__dirname, '../static/debugger_ip.cfg');
|
|
246
|
-
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
|
|
265
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
|
|
247
266
|
}
|
|
248
267
|
else {
|
|
249
|
-
adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell rm /data/debugger_ip.cfg`);
|
|
268
|
+
adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} shell rm /data/debugger_ip.cfg`);
|
|
250
269
|
}
|
|
251
270
|
this.installRpkToAppList(rpkPath, this.appPathInEmulator);
|
|
252
271
|
});
|
|
@@ -261,16 +280,15 @@ class MiwearInstance extends common_1.default {
|
|
|
261
280
|
installRpkToAppList(rpkPath, targetDir) {
|
|
262
281
|
return __awaiter(this, void 0, void 0, function* () {
|
|
263
282
|
try {
|
|
264
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
265
283
|
const { package: packageName } = this.projectInfo;
|
|
266
284
|
// 1. adb push应用的rpk
|
|
267
285
|
const targetPath = `${targetDir}/${packageName}.rpk`;
|
|
268
|
-
const pushCmd = `adb -s ${sn} push "${rpkPath}" ${targetPath}`;
|
|
286
|
+
const pushCmd = `adb -s ${this.sn} push "${rpkPath}" ${targetPath}`;
|
|
269
287
|
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
|
|
270
288
|
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
271
289
|
yield (0, utils_1.sleep)(1000);
|
|
272
290
|
// 2. 安装应用(pm install时如何应用重名会覆盖)
|
|
273
|
-
const installCmd = `adb -s ${sn} shell pm install ${targetPath}`;
|
|
291
|
+
const installCmd = `adb -s ${this.sn} shell pm install ${targetPath}`;
|
|
274
292
|
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
|
|
275
293
|
adbMiwt.execAdbCmdAsync(installCmd);
|
|
276
294
|
}
|
|
@@ -285,10 +303,11 @@ class MiwearInstance extends common_1.default {
|
|
|
285
303
|
*/
|
|
286
304
|
initDebugSocket() {
|
|
287
305
|
return new Promise((resolve, reject) => {
|
|
306
|
+
var _a;
|
|
288
307
|
if (this.debugSocket && this.debugSocket.OPEN) {
|
|
289
308
|
return resolve();
|
|
290
309
|
}
|
|
291
|
-
this.debugSocket = new ws_1.default(`ws://localhost:${this.debugPort}`);
|
|
310
|
+
this.debugSocket = new ws_1.default(`ws://localhost:${(_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.debugPort}`);
|
|
292
311
|
this.debugSocket.onopen = () => {
|
|
293
312
|
ColorConsole_1.default.info(`### Emulator debugSocket connect success`);
|
|
294
313
|
return resolve();
|
|
@@ -327,22 +346,7 @@ class MiwearInstance extends common_1.default {
|
|
|
327
346
|
this.reconnectCount = 0;
|
|
328
347
|
yield this.initDebugSocket();
|
|
329
348
|
// 1. 将整包重新推到miwear中(TODO:增量更新)
|
|
330
|
-
|
|
331
|
-
const { package: appPackageName } = this.projectInfo;
|
|
332
|
-
// windows平台adb push时无法使用通配符,需另外处理;
|
|
333
|
-
// 项目路径包含空格时,无法通过加引号来使用 * 通配符
|
|
334
|
-
if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
|
|
335
|
-
const rmCmd = `adb -s ${sn} shell rm -r ${this.appPathInEmulator}/${appPackageName}`;
|
|
336
|
-
yield adbMiwt.execAdbCmdAsync(rmCmd);
|
|
337
|
-
const sourcePath = path_1.default.resolve(this.projectPath, './build');
|
|
338
|
-
const pushCmd = `adb -s ${sn} push "${sourcePath}" ${this.appPathInEmulator}/${appPackageName}`;
|
|
339
|
-
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
const sourcePath = path_1.default.resolve(this.projectPath, './build/*');
|
|
343
|
-
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appPathInEmulator}/${appPackageName}`);
|
|
344
|
-
}
|
|
345
|
-
ColorConsole_1.default.info(`### Emulator push to ${this.appPathInEmulator}/${appPackageName} successfully`);
|
|
349
|
+
yield this.pushBuild();
|
|
346
350
|
// 2. 下发CDP命令给调试服务告知刷新
|
|
347
351
|
if (((_a = this.debugSocket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.OPEN) {
|
|
348
352
|
(_b = this.debugSocket) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({ id: 10000, method: 'Page.reload', params: {} }));
|
|
@@ -353,6 +357,52 @@ class MiwearInstance extends common_1.default {
|
|
|
353
357
|
}
|
|
354
358
|
});
|
|
355
359
|
}
|
|
360
|
+
/** 热更新时push目录 */
|
|
361
|
+
pushBuild() {
|
|
362
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
363
|
+
const { package: appPackageName } = this.projectInfo;
|
|
364
|
+
// windows平台adb push时无法使用通配符,需另外处理;
|
|
365
|
+
// 项目路径包含空格时,无法通过加引号来使用 * 通配符
|
|
366
|
+
if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
|
|
367
|
+
const rmCmd = `adb -s ${this.sn} shell rm -r ${this.appPathInEmulator}/${appPackageName}`;
|
|
368
|
+
yield adbMiwt.execAdbCmdAsync(rmCmd);
|
|
369
|
+
const sourcePath = path_1.default.resolve(this.projectPath, './build');
|
|
370
|
+
const pushCmd = `adb -s ${this.sn} push "${sourcePath}" ${this.appPathInEmulator}/${appPackageName}`;
|
|
371
|
+
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
const sourcePath = path_1.default.resolve(this.projectPath, './build/*');
|
|
375
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} push ${sourcePath} ${this.appPathInEmulator}/${appPackageName}`);
|
|
376
|
+
}
|
|
377
|
+
ColorConsole_1.default.info(`### Emulator push to ${this.appPathInEmulator}/${appPackageName} successfully`);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/** 在模拟器中重启快应用(基于am命令,需要保证镜像中已经有am功能)
|
|
381
|
+
* 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
|
|
382
|
+
* 2. nsh中执行am stop命令退出快应用
|
|
383
|
+
* 3. nsh中执行am start命令启动快应用
|
|
384
|
+
*/
|
|
385
|
+
reloadApp() {
|
|
386
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
387
|
+
try {
|
|
388
|
+
// 1. 将整包重新推到miwear中(TODO:增量更新)
|
|
389
|
+
const { package: appPackageName } = this.projectInfo;
|
|
390
|
+
yield this.pushBuild();
|
|
391
|
+
// 2. 执行am stop和am start命令
|
|
392
|
+
const stopCmd = `adb -s ${this.sn} shell am stop ${appPackageName}`;
|
|
393
|
+
yield adbMiwt.execAdbCmdAsync(stopCmd);
|
|
394
|
+
ColorConsole_1.default.info(`### Emulator stop ${appPackageName} successfully`);
|
|
395
|
+
// 这里是为了等am stop命令清除资源等
|
|
396
|
+
yield (0, utils_1.sleep)(500);
|
|
397
|
+
const startCmd = `adb -s ${this.sn} shell am start ${appPackageName}`;
|
|
398
|
+
yield adbMiwt.execAdbCmdAsync(startCmd);
|
|
399
|
+
ColorConsole_1.default.info(`### Emulator start ${appPackageName} successfully`);
|
|
400
|
+
}
|
|
401
|
+
catch (e) {
|
|
402
|
+
ColorConsole_1.default.error(`${e}`);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
356
406
|
/**
|
|
357
407
|
* 创建server端,监听打包过程中client端发来的消息
|
|
358
408
|
*/
|
package/lib/instance/preDev.d.ts
CHANGED
|
@@ -40,12 +40,6 @@ declare class OldGoldfishInstance extends CommonInstance {
|
|
|
40
40
|
* @returns
|
|
41
41
|
*/
|
|
42
42
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* 通过adb连接模拟器。
|
|
45
|
-
* 时间限制为10分钟,超时则表示连接失败
|
|
46
|
-
* @returns
|
|
47
|
-
*/
|
|
48
|
-
connectGoldfish(): Promise<boolean>;
|
|
49
43
|
/**
|
|
50
44
|
* 推送文件到本地的${sdkHome}/qa/app/${packageName}目录
|
|
51
45
|
* @param sourceRoot 源目录
|
package/lib/instance/preDev.js
CHANGED
|
@@ -64,9 +64,10 @@ class OldGoldfishInstance extends common_1.default {
|
|
|
64
64
|
*/
|
|
65
65
|
start(options) {
|
|
66
66
|
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
this.startOptions = options;
|
|
68
|
+
this.sn = `127.0.0.1:${this.startOptions.adbPort}`;
|
|
67
69
|
// host启动9p server
|
|
68
70
|
yield this.ensure9pServerRunnning();
|
|
69
|
-
this.startOptions = options;
|
|
70
71
|
// 将rpk推到host的./export/qa/app目录
|
|
71
72
|
const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
|
|
72
73
|
this.pushRpk(buildedFilesPath);
|
|
@@ -99,13 +100,13 @@ class OldGoldfishInstance extends common_1.default {
|
|
|
99
100
|
try {
|
|
100
101
|
const { package: packageName } = this.projectInfo;
|
|
101
102
|
const appMountDir = path_1.default.resolve(this.sdkHome, 'qa');
|
|
102
|
-
const mountCmd = `adb -s 127.0.0.1:${
|
|
103
|
+
const mountCmd = `adb -s 127.0.0.1:${options.adbPort} shell mount -t v9fs -o tag=10.0.2.2,port=${this.host9pPort},aname=${appMountDir} /data`;
|
|
103
104
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${mountCmd}`);
|
|
104
105
|
adbMiwt.execAdbCmdSync(mountCmd);
|
|
105
|
-
let vappCmd = `adb -s 127.0.0.1:${
|
|
106
|
+
let vappCmd = `adb -s 127.0.0.1:${options.adbPort} shell vapp app/${packageName} &`;
|
|
106
107
|
// 调试情况下,需要加--jsdebugger=10.0.2.15:101
|
|
107
108
|
if (options.devtool) {
|
|
108
|
-
vappCmd = `adb -s 127.0.0.1:${
|
|
109
|
+
vappCmd = `adb -s 127.0.0.1:${options.adbPort} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
|
|
109
110
|
}
|
|
110
111
|
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
|
|
111
112
|
// vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
|
|
@@ -176,19 +177,17 @@ class OldGoldfishInstance extends common_1.default {
|
|
|
176
177
|
// 获取vela镜像的绝对路径
|
|
177
178
|
const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
|
|
178
179
|
const { avdArch, avdImagePath } = avdInfo;
|
|
179
|
-
|
|
180
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
180
|
+
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
181
181
|
if (!avdImagePath) {
|
|
182
182
|
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
183
183
|
}
|
|
184
184
|
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
185
185
|
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
186
186
|
// 端口映射,adb端口和debug端口
|
|
187
|
-
let portMappingStr = `user,id=u1,hostfwd=tcp:127.0.0.1:${
|
|
187
|
+
let portMappingStr = `user,id=u1,hostfwd=tcp:127.0.0.1:${options.adbPort}-10.0.2.15:5555`;
|
|
188
188
|
if (devtool) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
189
|
+
ColorConsole_1.default.log(`### Emulator ### debug port: ${options.debugPort}`);
|
|
190
|
+
portMappingStr += `,hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
192
191
|
}
|
|
193
192
|
ColorConsole_1.default.log(`### Emulator ### Start qemu with TCP: ${portMappingStr}`);
|
|
194
193
|
// vnc配置
|
|
@@ -256,40 +255,6 @@ class OldGoldfishInstance extends common_1.default {
|
|
|
256
255
|
});
|
|
257
256
|
});
|
|
258
257
|
}
|
|
259
|
-
/**
|
|
260
|
-
* 通过adb连接模拟器。
|
|
261
|
-
* 时间限制为10分钟,超时则表示连接失败
|
|
262
|
-
* @returns
|
|
263
|
-
*/
|
|
264
|
-
connectGoldfish() {
|
|
265
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
266
|
-
let adbConnected = false;
|
|
267
|
-
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
268
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
269
|
-
while (!adbConnected) {
|
|
270
|
-
const adbKillCmd = `adb kill-server`;
|
|
271
|
-
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
272
|
-
adbMiwt.execAdbCmdSync(adbKillCmd);
|
|
273
|
-
const adbConnectCmd = `adb connect ${sn}`;
|
|
274
|
-
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
275
|
-
const str = adbMiwt.execAdbCmdSync(adbConnectCmd);
|
|
276
|
-
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
277
|
-
const devices = yield adbMiwt.getAdbDevices();
|
|
278
|
-
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
279
|
-
adbConnected =
|
|
280
|
-
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
281
|
-
}
|
|
282
|
-
Promise.resolve(adbConnected);
|
|
283
|
-
});
|
|
284
|
-
yield Promise.race([
|
|
285
|
-
connectFn(),
|
|
286
|
-
new Promise((resolve) => {
|
|
287
|
-
setTimeout(() => resolve(false), 600 * 1000);
|
|
288
|
-
})
|
|
289
|
-
]);
|
|
290
|
-
return adbConnected;
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
258
|
/**
|
|
294
259
|
* 推送文件到本地的${sdkHome}/qa/app/${packageName}目录
|
|
295
260
|
* @param sourceRoot 源目录
|
|
@@ -6,6 +6,8 @@ export declare const defaultSkinHome: string;
|
|
|
6
6
|
export declare const defaultQuickappHome: string;
|
|
7
7
|
export declare const defaultToolsHome: string;
|
|
8
8
|
export declare const defaultVncPort = 5900;
|
|
9
|
+
export declare const defaultAdbPort = 5555;
|
|
10
|
+
export declare const defaultDebugPort = 10055;
|
|
9
11
|
export declare const VelaImageVersionList: {
|
|
10
12
|
label: string;
|
|
11
13
|
value: string;
|
package/lib/static/constants.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.EmulatorEnvVersion = exports.VelaImageVersionList = exports.defaultVncPort = exports.defaultToolsHome = exports.defaultQuickappHome = exports.defaultSkinHome = exports.defaultEmulatorHome = exports.defaultImageHome = exports.defaultAvdHome = exports.defaultSDKHome = void 0;
|
|
6
|
+
exports.EmulatorEnvVersion = exports.VelaImageVersionList = exports.defaultDebugPort = exports.defaultAdbPort = exports.defaultVncPort = exports.defaultToolsHome = exports.defaultQuickappHome = exports.defaultSkinHome = exports.defaultEmulatorHome = exports.defaultImageHome = exports.defaultAvdHome = exports.defaultSDKHome = void 0;
|
|
7
7
|
const os_1 = __importDefault(require("os"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
exports.defaultSDKHome = path_1.default.resolve(os_1.default.homedir(), '.export');
|
|
@@ -14,6 +14,8 @@ exports.defaultSkinHome = path_1.default.resolve(exports.defaultSDKHome, 'skins'
|
|
|
14
14
|
exports.defaultQuickappHome = path_1.default.resolve(exports.defaultSDKHome, 'qa');
|
|
15
15
|
exports.defaultToolsHome = path_1.default.resolve(exports.defaultSDKHome, 'tools');
|
|
16
16
|
exports.defaultVncPort = 5900;
|
|
17
|
+
exports.defaultAdbPort = 5555;
|
|
18
|
+
exports.defaultDebugPort = 10055;
|
|
17
19
|
exports.VelaImageVersionList = [
|
|
18
20
|
{
|
|
19
21
|
label: 'vela正式版(4.0)',
|
package/lib/typing/Instance.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface IStartOptions {
|
|
|
12
12
|
disableNSH?: boolean;
|
|
13
13
|
serverPort?: number;
|
|
14
14
|
vncPort?: number;
|
|
15
|
+
adbPort: number;
|
|
16
|
+
debugPort?: number;
|
|
15
17
|
stdoutCallback?: (buffer: Buffer) => void;
|
|
16
18
|
stderrCallback?: (buffer: Buffer) => void;
|
|
17
19
|
exitCallback?: (code: number | null) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/emulator",
|
|
3
|
-
"version": "2.0.2-beta.
|
|
3
|
+
"version": "2.0.2-beta.7",
|
|
4
4
|
"description": "vela emulator tool.",
|
|
5
5
|
"homepage": "",
|
|
6
6
|
"license": "ISC",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"emulator"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@aiot-toolkit/aiotpack": "2.0.2-beta.
|
|
39
|
-
"@aiot-toolkit/shared-utils": "2.0.2-beta.
|
|
38
|
+
"@aiot-toolkit/aiotpack": "2.0.2-beta.7",
|
|
39
|
+
"@aiot-toolkit/shared-utils": "2.0.2-beta.7",
|
|
40
40
|
"find-process": "^1.4.7",
|
|
41
41
|
"portfinder": "^1.0.32"
|
|
42
42
|
},
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@types/fs-extra": "^11.0.4",
|
|
45
45
|
"fs-extra": "^11.2.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "dc37f9f6fbef3895d17b54ad41274c66f154f670"
|
|
48
48
|
}
|