@aiot-toolkit/emulator 2.0.2-beta.7 → 2.0.2-beta.9

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.
@@ -16,6 +16,7 @@ declare class CommonInstance {
16
16
  startOptions: IStartOptions | undefined;
17
17
  projectInfo: IManifest;
18
18
  isRpk: boolean;
19
+ isDistributedApp: boolean;
19
20
  sn?: string;
20
21
  constructor(params: INewGoldfishInstanceParams);
21
22
  /** 获取模拟器二进制文件所在位置 */
@@ -24,10 +25,10 @@ declare class CommonInstance {
24
25
  start(options: IStartOptions): Promise<void>;
25
26
  /**
26
27
  * 通过adb连接模拟器。
27
- * 时间限制为10s,超时则表示连接失败
28
+ * 时间限制为 @param timeout 秒,超时则表示连接失败
28
29
  * @returns
29
30
  */
30
- connectGoldfish(): Promise<unknown>;
31
+ connectGoldfish(timeout?: number): Promise<unknown>;
31
32
  /** 杀死进程 */
32
33
  killProcess(currProcess?: ChildProcess): void;
33
34
  /** 停止模拟器并释放相关资源 */
@@ -36,5 +37,6 @@ declare class CommonInstance {
36
37
  restart(): Promise<void>;
37
38
  /** 创建server */
38
39
  createWebsockeServer(): Promise<void>;
40
+ connectDevice(): Promise<string | void>;
39
41
  }
40
42
  export default CommonInstance;
@@ -45,16 +45,24 @@ const ws_1 = require("ws");
45
45
  const avd_1 = __importDefault(require("../avd"));
46
46
  const constants_1 = require("../static/constants");
47
47
  const utils_1 = require("../utils");
48
+ const fs_extra_1 = __importDefault(require("fs-extra"));
48
49
  /**
49
50
  * CommonInstance
50
51
  */
51
52
  class CommonInstance {
52
53
  constructor(params) {
53
54
  this.isFirstStart = true;
55
+ this.isDistributedApp = false;
54
56
  this.projectPath = params.projectPath;
55
57
  this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
56
58
  this.avdHome = params.avdHome || constants_1.defaultAvdHome;
57
59
  this.isRpk = params.sourceRoot === './';
60
+ const projectJsonFile = path_1.default.resolve(this.projectPath, '.project.json');
61
+ const projectJsonExist = fs_extra_1.default.existsSync(projectJsonFile);
62
+ if (projectJsonExist) {
63
+ const projectJsonInfo = fs_extra_1.default.readJSONSync(projectJsonFile);
64
+ this.isDistributedApp = projectJsonInfo.projectType === 'distributed';
65
+ }
58
66
  this.velaAvdCls = new avd_1.default({
59
67
  sdkHome: this.sdkHome,
60
68
  avdHome: this.avdHome
@@ -75,26 +83,30 @@ class CommonInstance {
75
83
  }
76
84
  /**
77
85
  * 通过adb连接模拟器。
78
- * 时间限制为10s,超时则表示连接失败
86
+ * 时间限制为 @param timeout 秒,超时则表示连接失败
79
87
  * @returns
80
88
  */
81
- connectGoldfish() {
89
+ connectGoldfish(timeout = 10) {
82
90
  return __awaiter(this, void 0, void 0, function* () {
83
91
  let adbConnected = false; // adb是否连接成功
84
92
  let enableLoop = true; // 是否允许循环,用于终止adb的连接
93
+ let needKill = false;
85
94
  const connectFn = () => __awaiter(this, void 0, void 0, function* () {
86
95
  while (enableLoop && !adbConnected) {
87
- const adbKillCmd = `adb kill-server`;
88
- ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
89
- adbMiwt.execAdbCmdSync(adbKillCmd);
90
- const adbConnectCmd = `adb connect ${this.sn}`;
91
- ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
92
- const str = adbMiwt.execAdbCmdSync(adbConnectCmd);
96
+ if (needKill) {
97
+ const adbKillCmd = `adb kill-server`;
98
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
99
+ yield adbMiwt.execAdbCmdAsync(adbKillCmd);
100
+ }
101
+ const str = yield this.connectDevice();
93
102
  ColorConsole_1.default.log(`### Emulator ### ${str}`);
103
+ // 查询模拟器的状态是否为“device”
94
104
  const devices = yield adbMiwt.getAdbDevices();
95
105
  ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
96
- adbConnected =
97
- devices.filter((item) => item.sn === this.sn && item.status === 'device').length > 0;
106
+ const curDev = devices.find((t) => t.sn === this.sn);
107
+ if ((curDev === null || curDev === void 0 ? void 0 : curDev.status) === 'offline')
108
+ needKill = true;
109
+ adbConnected = devices.some((item) => item.sn === this.sn && item.status === 'device');
98
110
  }
99
111
  return Promise.resolve(adbConnected);
100
112
  });
@@ -102,10 +114,12 @@ class CommonInstance {
102
114
  connectFn(),
103
115
  new Promise((resolve) => {
104
116
  setTimeout(() => {
105
- enableLoop = false;
117
+ if (!adbConnected) {
118
+ enableLoop = false;
119
+ }
106
120
  // 超时则认为adb没有连接成功
107
121
  resolve(false);
108
- }, 10 * 1000);
122
+ }, timeout * 1000);
109
123
  })
110
124
  ]);
111
125
  return res;
@@ -162,14 +176,14 @@ class CommonInstance {
162
176
  var _a;
163
177
  return __awaiter(this, void 0, void 0, function* () {
164
178
  const wsServer = new ws_1.WebSocketServer({
165
- port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort,
179
+ port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort
166
180
  });
167
- wsServer.on('connection', socket => {
181
+ wsServer.on('connection', (socket) => {
168
182
  ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
169
- socket.on('error', err => {
183
+ socket.on('error', (err) => {
170
184
  ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
171
185
  });
172
- socket.on('message', data => {
186
+ socket.on('message', (data) => {
173
187
  const message = JSON.parse(data.toString());
174
188
  ColorConsole_1.default.log(`### App Socket server ### Websocket server get data: ${data}`);
175
189
  if (message.type === 'restart') {
@@ -182,5 +196,32 @@ class CommonInstance {
182
196
  });
183
197
  });
184
198
  }
199
+ connectDevice() {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ const adbConnectCmd = `adb connect ${this.sn}`;
202
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
203
+ let pending = true;
204
+ const p1 = adbMiwt.execAdbCmdAsync(adbConnectCmd);
205
+ let timer;
206
+ // 超过一定时间还没有连接成功,则 kill-server 后再试
207
+ // 用于处理 adb connect 一直 pending 的情况
208
+ const p2 = new Promise((resolve, reject) => {
209
+ timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
210
+ if (pending) {
211
+ const adbKillCmd = `adb kill-server`;
212
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
213
+ yield adbMiwt.execAdbCmdAsync(adbKillCmd);
214
+ }
215
+ resolve();
216
+ }), 10 * 1000);
217
+ });
218
+ p1.then((r) => {
219
+ pending = false;
220
+ clearTimeout(timer);
221
+ console.log(r);
222
+ });
223
+ return Promise.race([p1, p2]);
224
+ });
225
+ }
185
226
  }
186
227
  exports.default = CommonInstance;
@@ -58,21 +58,28 @@ class GoldfishInstance extends common_1.default {
58
58
  this.sn = `127.0.0.1:${this.startOptions.adbPort}`;
59
59
  // 启动模拟器
60
60
  yield this.startGoldfish(options);
61
- const connected = yield this.connectGoldfish();
61
+ const connected = yield this.connectGoldfish(120);
62
62
  if (connected) {
63
63
  ColorConsole_1.default.log('### Emulator ### Goldfish emulator connected successfully');
64
64
  if (this.isFirstStart && this.startOptions.serverPort) {
65
65
  yield this.createWebsockeServer();
66
66
  }
67
67
  // adb push快应用到模拟器的/data/app目录
68
- const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
68
+ // aspect应用后续要考虑各种形状表盘的推包
69
+ const buildedFilesPath = this.isRpk
70
+ ? this.projectPath
71
+ : this.isDistributedApp
72
+ ? path_1.default.resolve(this.projectPath, './build', `${this.projectInfo.package}.watch`)
73
+ : path_1.default.resolve(this.projectPath, './build');
69
74
  yield this.pushRpk(buildedFilesPath);
70
75
  // 在模拟器中启动快应用
71
76
  this.startupQuickApp(options);
72
77
  this.isFirstStart = false;
73
78
  }
74
79
  else {
75
- ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
80
+ const msg = '### Emulator ### Failed to connect emulator, please check whether the adb is normal';
81
+ ColorConsole_1.default.throw(msg);
82
+ throw new Error(msg);
76
83
  }
77
84
  });
78
85
  }
@@ -111,7 +118,7 @@ class GoldfishInstance extends common_1.default {
111
118
  startGoldfish(options) {
112
119
  var _a;
113
120
  return __awaiter(this, void 0, void 0, function* () {
114
- const { avdName, devtool } = options;
121
+ const { avdName, devtool, origin = 'terminal' } = options;
115
122
  const emulatorBin = this.getEmulatorBinPath();
116
123
  ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
117
124
  const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
@@ -143,42 +150,39 @@ class GoldfishInstance extends common_1.default {
143
150
  const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
144
151
  vncStr = `-vnc :${portSuffix}`;
145
152
  }
146
- const stdioType = options.disableNSH ? 'pipe' : 'inherit';
147
153
  // 启动goldfish的命令和参数
148
154
  const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
149
155
  const spawnArgs = cmd.split(' ');
150
156
  const spawnBin = spawnArgs.shift();
151
157
  ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
152
158
  return new Promise((resolve) => {
153
- var _a, _b;
154
- this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
159
+ var _a, _b, _c;
160
+ this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: 'pipe', shell: true });
155
161
  (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
156
162
  const stderrCb = options.stderrCallback || console.log;
157
163
  stderrCb(data.toString());
158
164
  });
165
+ if (origin === 'terminal') {
166
+ process.stdout.pipe(this.goldfishProcess.stdin);
167
+ (_b = this.goldfishProcess.stdout) === null || _b === void 0 ? void 0 : _b.pipe(process.stdout);
168
+ }
159
169
  this.goldfishProcess.on('exit', (code) => {
160
170
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
161
171
  if (options.exitCallback) {
162
172
  options.exitCallback(code);
163
173
  }
164
174
  });
165
- if (options.disableNSH) {
166
- (_b = this.goldfishProcess.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
167
- const msg = data.toString();
175
+ (_c = this.goldfishProcess.stdout) === null || _c === void 0 ? void 0 : _c.on('data', (data) => {
176
+ const msg = data.toString();
177
+ if (origin === 'ide') {
168
178
  const stdoutCb = options.stdoutCallback || console.log;
169
179
  stdoutCb(msg);
170
- if (data.toString().includes('(NSH)')) {
171
- ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
172
- resolve();
173
- }
174
- });
175
- }
176
- else {
177
- setTimeout(() => {
180
+ }
181
+ if (msg.includes('(NSH)')) {
178
182
  ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
179
183
  resolve();
180
- }, 2000);
181
- }
184
+ }
185
+ });
182
186
  });
183
187
  });
184
188
  }
@@ -201,7 +205,7 @@ class GoldfishInstance extends common_1.default {
201
205
  // 支持通配符处理: 1. 模拟器中mkdir创建目录 2. adb push ./XXXXX/* /XXX
202
206
  const sourcePath = path_1.default.resolve(sourceRoot, './*');
203
207
  yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`);
204
- yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push "${sourcePath}" ${this.appRunDir}/${appPackageName}`);
208
+ yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appRunDir}/${appPackageName}`);
205
209
  }
206
210
  ColorConsole_1.default.info(`### Emulator push to ${this.appRunDir}/${appPackageName} successfully`);
207
211
  });
@@ -27,14 +27,6 @@ declare class MiwearInstance extends CommonInstance {
27
27
  * @returns
28
28
  */
29
29
  startGoldfish(options: IStartOptions): Promise<void>;
30
- /**
31
- * 通过adb连接模拟器。
32
- * 时间限制为2分钟,超时则表示连接失败
33
- * 注意:两次connect之间不能等待,否则在disableNSH=true且有vncPort的模式下,模拟器启动成功了,但是vnc可能还没连接上
34
- * 时间限制不能太短,否则模拟器里面的adbd进程还没初始化成功
35
- * @returns
36
- */
37
- connectGoldfish(): Promise<unknown>;
38
30
  /**
39
31
  * 在模拟器中启动快应用
40
32
  * 1. 检查release目录是否有打包好的rpk
@@ -53,6 +45,8 @@ declare class MiwearInstance extends CommonInstance {
53
45
  * @param targetDir 要将rpk放到模拟器的哪个目录下
54
46
  */
55
47
  installRpkToAppList(rpkPath: string, targetDir: string): Promise<void>;
48
+ /** 使用am start启动快应用 */
49
+ launchQuickapp(): Promise<void>;
56
50
  /** 连接模拟器中的调试服务,创建debugSocket
57
51
  * 主要用于热更新时,通过debugSocket通知调试服务更新页面
58
52
  * 设置了重连机制,会重复连接8次
@@ -62,7 +56,7 @@ declare class MiwearInstance extends CommonInstance {
62
56
  * 1. 确保已经成功连接模拟器中的调试服务
63
57
  * 2. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
64
58
  * 3. 发送Page.reload命令给调试服务,通知更新
65
- */
59
+ */
66
60
  handleUpdate(): Promise<void>;
67
61
  /** 热更新时push目录 */
68
62
  pushBuild(): Promise<void>;
@@ -70,7 +64,7 @@ declare class MiwearInstance extends CommonInstance {
70
64
  * 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
71
65
  * 2. nsh中执行am stop命令退出快应用
72
66
  * 3. nsh中执行am start命令启动快应用
73
- */
67
+ */
74
68
  reloadApp(): Promise<void>;
75
69
  /**
76
70
  * 创建server端,监听打包过程中client端发来的消息
@@ -70,7 +70,7 @@ class MiwearInstance extends common_1.default {
70
70
  // 启动模拟器
71
71
  yield this.startGoldfish(options);
72
72
  // adb连接模拟器
73
- const connected = yield this.connectGoldfish();
73
+ const connected = yield this.connectGoldfish(120);
74
74
  if (connected) {
75
75
  ColorConsole_1.default.info('### Emulator ### Goldfish emulator connected successfully');
76
76
  // 如果是首次启动,创建server端监听事件
@@ -82,7 +82,9 @@ class MiwearInstance extends common_1.default {
82
82
  this.isFirstStart = false;
83
83
  }
84
84
  else {
85
- ColorConsole_1.default.throw('### Emulator ### Failed to connect emulator, please check whether the adb is normal');
85
+ const msg = '### Emulator ### Failed to connect emulator, please check whether the adb is normal';
86
+ ColorConsole_1.default.throw(msg);
87
+ throw new Error(msg);
86
88
  }
87
89
  });
88
90
  }
@@ -99,7 +101,7 @@ class MiwearInstance extends common_1.default {
99
101
  startGoldfish(options) {
100
102
  var _a;
101
103
  return __awaiter(this, void 0, void 0, function* () {
102
- const { avdName, devtool } = options;
104
+ const { avdName, devtool, origin = 'terminal' } = options;
103
105
  // 获取emulator bin的绝对路径
104
106
  const emulatorBin = this.getEmulatorBinPath();
105
107
  ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
@@ -151,18 +153,24 @@ class MiwearInstance extends common_1.default {
151
153
  const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
152
154
  vncStr = `-vnc :${portSuffix}`;
153
155
  }
154
- // 根据disableNSH参数配置stdio
155
- const stdioType = options.disableNSH ? 'pipe' : 'inherit';
156
156
  // 启动模拟器的命令和参数
157
157
  const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
158
158
  const spawnArgs = cmd.split(' ');
159
159
  const spawnBin = spawnArgs.shift();
160
160
  ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
161
161
  return new Promise((resolve) => {
162
- var _a, _b, _c;
163
- this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true, cwd: this.sdkHome });
162
+ var _a, _b, _c, _d;
163
+ this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, {
164
+ stdio: 'pipe',
165
+ shell: true,
166
+ cwd: this.sdkHome
167
+ });
168
+ if (origin === 'terminal') {
169
+ process.stdout.pipe(this.goldfishProcess.stdin);
170
+ (_a = this.goldfishProcess.stdout) === null || _a === void 0 ? void 0 : _a.pipe(process.stdout);
171
+ }
164
172
  // 监听错误流
165
- (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
173
+ (_b = this.goldfishProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
166
174
  const stderrCb = options.stderrCallback || console.log;
167
175
  stderrCb(data.toString());
168
176
  });
@@ -173,67 +181,23 @@ class MiwearInstance extends common_1.default {
173
181
  options.exitCallback(code);
174
182
  }
175
183
  });
176
- // disableNSH=false时,输出流会直接定向到终端,可在终端输入「回车」进入模拟器的终端,这种情况下无法拿到stdout中的数据
177
- if (options.disableNSH) {
178
- (_c = (_b = this.goldfishProcess) === null || _b === void 0 ? void 0 : _b.stdout) === null || _c === void 0 ? void 0 : _c.on('data', (data) => {
179
- const msg = data.toString();
184
+ (_d = (_c = this.goldfishProcess) === null || _c === void 0 ? void 0 : _c.stdout) === null || _d === void 0 ? void 0 : _d.on('data', (data) => {
185
+ const msg = data.toString();
186
+ if (origin === 'ide') {
180
187
  const stdoutCb = options.stdoutCallback || console.log;
181
188
  stdoutCb(msg);
182
189
  if (msg.match(/quickapp_rpk_installer_init|rpk installer init done/)) {
183
190
  ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
184
191
  resolve();
185
192
  }
186
- });
187
- }
188
- else {
189
- // disableNSH=true时,默认8s后模拟器启动成功
190
- setTimeout(() => {
191
- ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
192
- resolve();
193
- }, 8000);
194
- }
195
- });
196
- });
197
- }
198
- /**
199
- * 通过adb连接模拟器。
200
- * 时间限制为2分钟,超时则表示连接失败
201
- * 注意:两次connect之间不能等待,否则在disableNSH=true且有vncPort的模式下,模拟器启动成功了,但是vnc可能还没连接上
202
- * 时间限制不能太短,否则模拟器里面的adbd进程还没初始化成功
203
- * @returns
204
- */
205
- connectGoldfish() {
206
- return __awaiter(this, void 0, void 0, function* () {
207
- let adbConnected = false; // adb是否连接成功
208
- let enableLoop = true; // 是否允许循环,用于终止adb的连接
209
- const connectFn = () => __awaiter(this, void 0, void 0, function* () {
210
- while (enableLoop && !adbConnected) {
211
- const adbKillCmd = `adb kill-server`;
212
- ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
213
- yield adbMiwt.execAdbCmdAsync(adbKillCmd);
214
- const adbConnectCmd = `adb connect ${this.sn}`;
215
- ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
216
- const str = yield adbMiwt.execAdbCmdAsync(adbConnectCmd);
217
- ColorConsole_1.default.log(`### Emulator ### ${str}`);
218
- // 查询模拟器的状态是否为“device”
219
- const devices = yield adbMiwt.getAdbDevices();
220
- ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
221
- adbConnected =
222
- devices.filter((item) => item.sn === this.sn && item.status === 'device').length > 0;
223
- }
224
- return Promise.resolve(adbConnected);
193
+ // 应用安装成功,则启动它
194
+ // if (msg.match(/InstallState_Finished|install finished/)) {
195
+ // ColorConsole.info(`### Emulator ### Install quickapp successfully`)
196
+ // this.launchQuickapp()
197
+ // }
198
+ }
199
+ });
225
200
  });
226
- const res = yield Promise.race([
227
- connectFn(),
228
- new Promise((resolve) => {
229
- setTimeout(() => {
230
- enableLoop = false;
231
- // 超时则认为adb没有连接成功
232
- resolve(false);
233
- }, 120 * 1000);
234
- })
235
- ]);
236
- return res;
237
201
  });
238
202
  }
239
203
  /**
@@ -254,7 +218,7 @@ class MiwearInstance extends common_1.default {
254
218
  : path_1.default.resolve(this.projectPath, ((_a = this.params.compilerOption) === null || _a === void 0 ? void 0 : _a.releasePath) || 'dist');
255
219
  const files = fs_extra_1.default
256
220
  .readdirSync(releaseDir)
257
- .filter(item => item.includes(appPackageName) && item.endsWith('.rpk'));
221
+ .filter((item) => item.includes(appPackageName) && item.endsWith('.rpk'));
258
222
  if (files.length === 0) {
259
223
  ColorConsole_1.default.error(`### Emulator the rpk does not exist`);
260
224
  }
@@ -290,13 +254,39 @@ class MiwearInstance extends common_1.default {
290
254
  // 2. 安装应用(pm install时如何应用重名会覆盖)
291
255
  const installCmd = `adb -s ${this.sn} shell pm install ${targetPath}`;
292
256
  ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
293
- adbMiwt.execAdbCmdAsync(installCmd);
257
+ yield adbMiwt.execAdbCmdAsync(installCmd);
258
+ // 3. 应用安装成功后,启动应用
259
+ const lsCmd = `adb -s ${this.sn} shell ls ${this.appPathInEmulator}`;
260
+ let installed = false;
261
+ let currCount = 0;
262
+ while (!installed && currCount < 10) {
263
+ yield (0, utils_1.sleep)(1000);
264
+ const res = yield adbMiwt.execAdbCmdAsync(lsCmd);
265
+ // 如果没有上传的rpk了,则表示安装成功
266
+ installed = !res.includes(`${packageName}.rpk`);
267
+ currCount++;
268
+ }
269
+ if (installed) {
270
+ this.launchQuickapp();
271
+ }
272
+ else {
273
+ ColorConsole_1.default.error(`### Emulator ### install ${packageName} failed`);
274
+ }
294
275
  }
295
276
  catch (e) {
296
277
  ColorConsole_1.default.error(`### Emulator ### ${e.message}`);
297
278
  }
298
279
  });
299
280
  }
281
+ /** 使用am start启动快应用 */
282
+ launchQuickapp() {
283
+ return __awaiter(this, void 0, void 0, function* () {
284
+ const { package: packageName } = this.projectInfo;
285
+ const startCmd = `adb -s ${this.sn} shell am start ${packageName}`;
286
+ ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${startCmd}`);
287
+ adbMiwt.execAdbCmdAsync(startCmd);
288
+ });
289
+ }
300
290
  /** 连接模拟器中的调试服务,创建debugSocket
301
291
  * 主要用于热更新时,通过debugSocket通知调试服务更新页面
302
292
  * 设置了重连机制,会重复连接8次
@@ -338,7 +328,7 @@ class MiwearInstance extends common_1.default {
338
328
  * 1. 确保已经成功连接模拟器中的调试服务
339
329
  * 2. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
340
330
  * 3. 发送Page.reload命令给调试服务,通知更新
341
- */
331
+ */
342
332
  handleUpdate() {
343
333
  var _a, _b;
344
334
  return __awaiter(this, void 0, void 0, function* () {
@@ -361,7 +351,7 @@ class MiwearInstance extends common_1.default {
361
351
  pushBuild() {
362
352
  return __awaiter(this, void 0, void 0, function* () {
363
353
  const { package: appPackageName } = this.projectInfo;
364
- // windows平台adb push时无法使用通配符,需另外处理;
354
+ // windows平台adb push时无法使用通配符,需另外处理;
365
355
  // 项目路径包含空格时,无法通过加引号来使用 * 通配符
366
356
  if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
367
357
  const rmCmd = `adb -s ${this.sn} shell rm -r ${this.appPathInEmulator}/${appPackageName}`;
@@ -381,7 +371,7 @@ class MiwearInstance extends common_1.default {
381
371
  * 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
382
372
  * 2. nsh中执行am stop命令退出快应用
383
373
  * 3. nsh中执行am start命令启动快应用
384
- */
374
+ */
385
375
  reloadApp() {
386
376
  return __awaiter(this, void 0, void 0, function* () {
387
377
  try {
@@ -410,11 +400,11 @@ class MiwearInstance extends common_1.default {
410
400
  var _a;
411
401
  return __awaiter(this, void 0, void 0, function* () {
412
402
  const wsServer = new ws_1.WebSocketServer({
413
- port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort,
403
+ port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort
414
404
  });
415
- wsServer.on('connection', socket => {
405
+ wsServer.on('connection', (socket) => {
416
406
  ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
417
- socket.on('error', err => {
407
+ socket.on('error', (err) => {
418
408
  ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
419
409
  });
420
410
  // data的格式:{ type: string, data: any }
@@ -27,7 +27,7 @@ declare class OldGoldfishInstance extends CommonInstance {
27
27
  startupQuickApp(options: IStartOptions): void;
28
28
  /** host启动9pServer
29
29
  * 作用是将本地的quickappMountDir目录挂载到模拟器的/data目录
30
- */
30
+ */
31
31
  ensure9pServerRunnning(): Promise<void>;
32
32
  /**
33
33
  * 启动模拟器
@@ -69,7 +69,9 @@ class OldGoldfishInstance extends common_1.default {
69
69
  // host启动9p server
70
70
  yield this.ensure9pServerRunnning();
71
71
  // 将rpk推到host的./export/qa/app目录
72
- const buildedFilesPath = this.isRpk ? this.projectPath : path_1.default.resolve(this.projectPath, './build');
72
+ const buildedFilesPath = this.isRpk
73
+ ? this.projectPath
74
+ : path_1.default.resolve(this.projectPath, './build');
73
75
  this.pushRpk(buildedFilesPath);
74
76
  // 启动模拟器
75
77
  yield this.startGoldfish(options);
@@ -118,7 +120,7 @@ class OldGoldfishInstance extends common_1.default {
118
120
  }
119
121
  /** host启动9pServer
120
122
  * 作用是将本地的quickappMountDir目录挂载到模拟器的/data目录
121
- */
123
+ */
122
124
  ensure9pServerRunnning() {
123
125
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
124
126
  var _a;
@@ -170,7 +172,7 @@ class OldGoldfishInstance extends common_1.default {
170
172
  */
171
173
  startGoldfish(options) {
172
174
  return __awaiter(this, void 0, void 0, function* () {
173
- const { avdName, devtool } = options;
175
+ const { avdName, devtool, origin = 'terminal' } = options;
174
176
  // 获取emulator bin的绝对路径
175
177
  const emulatorBin = this.getEmulatorBinPath();
176
178
  ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
@@ -198,8 +200,6 @@ class OldGoldfishInstance extends common_1.default {
198
200
  const portSuffix = options.vncPort - constants_1.defaultVncPort;
199
201
  vncStr = `-vnc :${portSuffix}`;
200
202
  }
201
- // 根据disableNSH参数配置stdio
202
- const stdioType = options.disableNSH ? 'pipe' : 'inherit';
203
203
  // 启动goldfish的命令和参数
204
204
  const spawnBin = emulatorBin;
205
205
  const spawnArgs = [
@@ -221,13 +221,17 @@ class OldGoldfishInstance extends common_1.default {
221
221
  ];
222
222
  ColorConsole_1.default.log(`### Emulator ### Start CMD: ${spawnBin} ${spawnArgs.join(' ')}`);
223
223
  return new Promise((resolve) => {
224
- var _a;
225
- this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: stdioType, shell: true });
224
+ var _a, _b, _c, _d;
225
+ this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: 'pipe', shell: true });
226
226
  // 监听错误流
227
227
  (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
228
228
  const stderrCb = options.stderrCallback || console.log;
229
229
  stderrCb(data.toString());
230
230
  });
231
+ if (origin === 'terminal') {
232
+ process.stdout.pipe(this.goldfishProcess.stdin);
233
+ (_b = this.goldfishProcess.stdout) === null || _b === void 0 ? void 0 : _b.pipe(process.stdout);
234
+ }
231
235
  // 监听模拟器的退出事件
232
236
  this.goldfishProcess.on('exit', (code) => {
233
237
  ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
@@ -235,23 +239,18 @@ class OldGoldfishInstance extends common_1.default {
235
239
  options.exitCallback(code);
236
240
  }
237
241
  });
238
- // 监听输出流。输出了'(NSH)'标识或者2s后则认为模拟器启动成功
239
- const p1 = new Promise((resolve) => {
240
- var _a, _b;
241
- (_b = (_a = this.goldfishProcess) === null || _a === void 0 ? void 0 : _a.stdout) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
242
+ // 监听输出流。输出了'(NSH)'标识后则认为模拟器启动成功
243
+ (_d = (_c = this.goldfishProcess) === null || _c === void 0 ? void 0 : _c.stdout) === null || _d === void 0 ? void 0 : _d.on('data', (data) => {
244
+ const msg = data.toString();
245
+ if (origin === 'ide') {
242
246
  const stdoutCb = options.stdoutCallback || console.log;
243
- stdoutCb(data.toString());
244
- if (data.toString().includes('(NSH)')) {
245
- ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
246
- resolve();
247
- }
248
- });
247
+ stdoutCb(msg);
248
+ }
249
+ if (msg.includes('(NSH)')) {
250
+ ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
251
+ resolve();
252
+ }
249
253
  });
250
- const p2 = setTimeout(() => {
251
- ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
252
- resolve();
253
- }, 2000);
254
- return Promise.race([p1, p2]);
255
254
  });
256
255
  });
257
256
  }
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
- import IJavascriptCompileOption from "@aiot-toolkit/aiotpack/lib/compiler/javascript/interface/IJavascriptCompileOption";
3
- import { IAvdResourcePaths } from "./Avd";
2
+ import IJavascriptCompileOption from '@aiot-toolkit/aiotpack/lib/compiler/javascript/interface/IJavascriptCompileOption';
3
+ import { IAvdResourcePaths } from './Avd';
4
4
  export interface INewGoldfishInstanceParams extends IAvdResourcePaths {
5
5
  projectPath: string;
6
6
  sourceRoot?: string;
@@ -9,7 +9,9 @@ export interface INewGoldfishInstanceParams extends IAvdResourcePaths {
9
9
  export interface IStartOptions {
10
10
  avdName: string;
11
11
  devtool?: string;
12
+ /** @deprecated */
12
13
  disableNSH?: boolean;
14
+ origin?: 'ide' | 'terminal';
13
15
  serverPort?: number;
14
16
  vncPort?: number;
15
17
  adbPort: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiot-toolkit/emulator",
3
- "version": "2.0.2-beta.7",
3
+ "version": "2.0.2-beta.9",
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.7",
39
- "@aiot-toolkit/shared-utils": "2.0.2-beta.7",
38
+ "@aiot-toolkit/aiotpack": "2.0.2-beta.9",
39
+ "@aiot-toolkit/shared-utils": "2.0.2-beta.9",
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": "dc37f9f6fbef3895d17b54ad41274c66f154f670"
47
+ "gitHead": "19f19b20ca63800f2403cc89d9a8edb6a102a765"
48
48
  }