@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.
- package/lib/instance/common.d.ts +4 -2
- package/lib/instance/common.js +57 -16
- package/lib/instance/dev.js +25 -21
- package/lib/instance/miwear.d.ts +4 -10
- package/lib/instance/miwear.js +60 -70
- package/lib/instance/preDev.d.ts +1 -1
- package/lib/instance/preDev.js +21 -22
- package/lib/typing/Instance.d.ts +4 -2
- package/package.json +4 -4
package/lib/instance/common.d.ts
CHANGED
|
@@ -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
|
-
* 时间限制为
|
|
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;
|
package/lib/instance/common.js
CHANGED
|
@@ -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
|
-
* 时间限制为
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const str =
|
|
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
|
-
|
|
97
|
-
|
|
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
|
-
|
|
117
|
+
if (!adbConnected) {
|
|
118
|
+
enableLoop = false;
|
|
119
|
+
}
|
|
106
120
|
// 超时则认为adb没有连接成功
|
|
107
121
|
resolve(false);
|
|
108
|
-
},
|
|
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;
|
package/lib/instance/dev.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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
|
-
}
|
|
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
|
|
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
|
});
|
package/lib/instance/miwear.d.ts
CHANGED
|
@@ -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端发来的消息
|
package/lib/instance/miwear.js
CHANGED
|
@@ -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
|
-
|
|
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, {
|
|
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
|
-
(
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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 }
|
package/lib/instance/preDev.d.ts
CHANGED
package/lib/instance/preDev.js
CHANGED
|
@@ -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
|
|
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:
|
|
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)'
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
}
|
package/lib/typing/Instance.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import IJavascriptCompileOption from
|
|
3
|
-
import { IAvdResourcePaths } from
|
|
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.
|
|
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.
|
|
39
|
-
"@aiot-toolkit/shared-utils": "2.0.2-beta.
|
|
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": "
|
|
47
|
+
"gitHead": "19f19b20ca63800f2403cc89d9a8edb6a102a765"
|
|
48
48
|
}
|