@aiot-toolkit/emulator 2.0.2-dev.8 → 2.0.2
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/README.md +14 -1
- package/lib/avd/index.d.ts +16 -0
- package/lib/avd/index.js +52 -28
- package/lib/emulatorutil/EmulatorCmd.d.ts +9 -0
- package/lib/emulatorutil/EmulatorCmd.js +226 -0
- package/lib/emulatorutil/EmulatorLog.d.ts +11 -0
- package/lib/emulatorutil/EmulatorLog.js +21 -0
- package/lib/emulatorutil/constants.d.ts +31 -0
- package/lib/emulatorutil/constants.js +63 -0
- package/lib/emulatorutil/index.d.ts +3 -0
- package/lib/emulatorutil/index.js +10 -0
- package/lib/index.d.ts +3 -1
- package/lib/index.js +4 -1
- package/lib/instance/common.d.ts +15 -12
- package/lib/instance/common.js +93 -144
- package/lib/instance/dev.d.ts +42 -6
- package/lib/instance/dev.js +137 -83
- package/lib/instance/index.d.ts +10 -2
- package/lib/instance/index.js +14 -2
- package/lib/instance/miwear.d.ts +66 -12
- package/lib/instance/miwear.js +220 -182
- package/lib/instance/pre.d.ts +11 -0
- package/lib/instance/pre.js +100 -0
- package/lib/instance/preDev.d.ts +37 -7
- package/lib/instance/preDev.js +80 -106
- package/lib/static/advancedFeatures.ini +1 -0
- package/lib/static/avdConfigIni.json +4 -4
- package/lib/typing/Avd.d.ts +1 -0
- package/lib/typing/Instance.d.ts +16 -3
- package/lib/typing/Instance.js +6 -0
- package/lib/utils/index.d.ts +21 -0
- package/lib/utils/index.js +67 -10
- package/package.json +15 -5
- package/lib/static/constants.d.ts +0 -19
- package/lib/static/constants.js +0 -27
package/lib/instance/miwear.js
CHANGED
|
@@ -35,267 +35,243 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
const JavascriptDefaultCompileOption_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/JavascriptDefaultCompileOption"));
|
|
39
38
|
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
40
39
|
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
41
40
|
const child_process_1 = require("child_process");
|
|
41
|
+
const readline_1 = __importDefault(require("readline"));
|
|
42
42
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
43
43
|
const os_1 = __importDefault(require("os"));
|
|
44
44
|
const path_1 = __importDefault(require("path"));
|
|
45
|
-
const portfinder_1 = __importDefault(require("portfinder"));
|
|
46
45
|
const ws_1 = __importStar(require("ws"));
|
|
47
|
-
const
|
|
46
|
+
const Instance_1 = require("../typing/Instance");
|
|
48
47
|
const utils_1 = require("../utils");
|
|
48
|
+
const emulatorutil_1 = require("../emulatorutil");
|
|
49
49
|
const common_1 = __importDefault(require("./common"));
|
|
50
50
|
const MAX_RECONNECT_COUNT = 8;
|
|
51
51
|
/**
|
|
52
52
|
* MiwearInstance
|
|
53
|
-
* 针对
|
|
53
|
+
* 针对 Vela正式版(4.0)的镜像
|
|
54
54
|
*/
|
|
55
55
|
class MiwearInstance extends common_1.default {
|
|
56
56
|
constructor(params) {
|
|
57
57
|
super(params);
|
|
58
|
-
this.
|
|
58
|
+
this.params = params;
|
|
59
|
+
this.appDir = '/data/quickapp/app';
|
|
59
60
|
this.reconnectCount = 0;
|
|
60
61
|
}
|
|
61
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* 1. 启动模拟器
|
|
64
|
+
* 2. 启动成功后,adb连接模拟器
|
|
65
|
+
* 3. 连接成功后,在模拟器中启动快应用
|
|
66
|
+
*/
|
|
62
67
|
start(options) {
|
|
63
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
64
69
|
this.startOptions = options;
|
|
70
|
+
this.sn = `emulator-${this.startOptions.adbPort}`;
|
|
65
71
|
// 启动模拟器
|
|
66
72
|
yield this.startGoldfish(options);
|
|
67
73
|
// adb连接模拟器
|
|
68
|
-
const connected = yield this.
|
|
74
|
+
const connected = yield this.isConnected();
|
|
69
75
|
if (connected) {
|
|
70
76
|
ColorConsole_1.default.info('### Emulator ### Goldfish emulator connected successfully');
|
|
77
|
+
// 如果是首次启动,创建server端监听事件
|
|
71
78
|
if (this.isFirstStart && this.startOptions.serverPort) {
|
|
72
79
|
yield this.createWebsockeServer();
|
|
73
80
|
}
|
|
81
|
+
// 在模拟器中启动快应用
|
|
74
82
|
this.startupQuickApp(options);
|
|
75
83
|
this.isFirstStart = false;
|
|
76
84
|
}
|
|
77
85
|
else {
|
|
78
|
-
|
|
86
|
+
const msg = '### Emulator ### Failed to connect emulator, please check whether the adb is normal';
|
|
87
|
+
ColorConsole_1.default.throw(msg);
|
|
88
|
+
throw new Error(msg);
|
|
79
89
|
}
|
|
80
90
|
});
|
|
81
91
|
}
|
|
82
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* 启动模拟器
|
|
94
|
+
* 1. 通过options生成模拟器的启动命令
|
|
95
|
+
* 2. 执行启动命令
|
|
96
|
+
* 3. 判断模拟器是否启动成功
|
|
97
|
+
* 3.1 若disableNSH=true,输出流中匹配到/quickapp_rpk_installer_init|rpk installer init done/,认为模拟器启动成功了
|
|
98
|
+
* 3.2 若disableNSH=false,认为8s过后模拟器启动成功了
|
|
99
|
+
* @param options
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
83
102
|
startGoldfish(options) {
|
|
84
|
-
var _a;
|
|
85
103
|
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
-
const {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.adbPort = yield portfinder_1.default.getPortPromise({ port: this.adbPort });
|
|
92
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${this.adbPort}`);
|
|
93
|
-
if (!avdImagePath) {
|
|
94
|
-
return ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
95
|
-
}
|
|
96
|
-
const nuttxBinPath = path_1.default.resolve(avdImagePath, 'nuttx');
|
|
97
|
-
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
98
|
-
// 端口映射
|
|
99
|
-
let portMappingStr = `-network-user-mode-options hostfwd=tcp:127.0.0.1:${this.adbPort}-10.0.2.15:5555`;
|
|
100
|
-
if (devtool) {
|
|
101
|
-
this.debugPort = yield portfinder_1.default.getPortPromise({ port: this.debugPort });
|
|
102
|
-
portMappingStr += `,hostfwd=tcp:127.0.0.1:${this.debugPort}-10.0.2.15:101`;
|
|
103
|
-
}
|
|
104
|
-
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
105
|
-
const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.img');
|
|
106
|
-
const dataImageBin = path_1.default.resolve(avdImagePath, 'data.img');
|
|
107
|
-
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin} \
|
|
108
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
109
|
-
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBin} \
|
|
110
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
111
|
-
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
112
|
-
// vnc配置
|
|
113
|
-
let windowStr = '';
|
|
114
|
-
let vncStr = '';
|
|
115
|
-
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.vncPort) {
|
|
116
|
-
windowStr = '-no-window';
|
|
117
|
-
const portSuffix = this.startOptions.vncPort - constants_1.defaultVncPort;
|
|
118
|
-
vncStr = `-vnc :${portSuffix}`;
|
|
119
|
-
}
|
|
120
|
-
const stdioType = options.disableNSH ? 'pipe' : 'inherit';
|
|
121
|
-
// 启动goldfish的命令和参数
|
|
122
|
-
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} -qemu ${vncStr} ${imageMountStr}`;
|
|
104
|
+
const { origin = Instance_1.IStartOrigin.Terminal } = options;
|
|
105
|
+
// 启动模拟器的命令和参数
|
|
106
|
+
const cmd = emulatorutil_1.EmulatorCmd.createMiwerCmd(options, this.sdkHome, this.avdHome);
|
|
107
|
+
if (!cmd)
|
|
108
|
+
return;
|
|
123
109
|
const spawnArgs = cmd.split(' ');
|
|
124
110
|
const spawnBin = spawnArgs.shift();
|
|
125
|
-
ColorConsole_1.default.log(`### Emulator ### Start CMD: ${cmd}`);
|
|
111
|
+
ColorConsole_1.default.log(`### Emulator ### Start CMD miwear: ${cmd}`);
|
|
112
|
+
const func = this instanceof MiwearInstance ? emulatorutil_1.EmulatorLog.rpkIsStart : emulatorutil_1.EmulatorLog.devIsStart;
|
|
126
113
|
return new Promise((resolve) => {
|
|
127
|
-
var _a, _b
|
|
128
|
-
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
114
|
+
var _a, _b;
|
|
115
|
+
this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, {
|
|
116
|
+
stdio: 'pipe',
|
|
117
|
+
shell: true,
|
|
118
|
+
cwd: this.sdkHome
|
|
132
119
|
});
|
|
120
|
+
if (origin === Instance_1.IStartOrigin.Terminal) {
|
|
121
|
+
process.stdin.pipe(this.goldfishProcess.stdin);
|
|
122
|
+
}
|
|
123
|
+
// 利用 readline 接口可解决子进程日志换行的问题
|
|
124
|
+
this.stdoutReadline = readline_1.default.createInterface({
|
|
125
|
+
input: this.goldfishProcess.stdout
|
|
126
|
+
});
|
|
127
|
+
this.stderrReadline = readline_1.default.createInterface({
|
|
128
|
+
input: this.goldfishProcess.stderr
|
|
129
|
+
});
|
|
130
|
+
// 监听模拟器的退出事件
|
|
133
131
|
this.goldfishProcess.on('exit', (code) => {
|
|
134
132
|
ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
|
|
135
133
|
if (options.exitCallback) {
|
|
136
134
|
options.exitCallback(code);
|
|
137
135
|
}
|
|
138
136
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
137
|
+
// 监听错误流
|
|
138
|
+
(_a = this.stderrReadline) === null || _a === void 0 ? void 0 : _a.on('line', (data) => {
|
|
139
|
+
const stderrCb = options.stderrCallback || console.log;
|
|
140
|
+
stderrCb(data.toString());
|
|
141
|
+
});
|
|
142
|
+
// 监听输出流
|
|
143
|
+
(_b = this.stdoutReadline) === null || _b === void 0 ? void 0 : _b.on('line', (data) => {
|
|
144
|
+
const msg = data.toString();
|
|
145
|
+
const stdoutCb = options.stdoutCallback || console.log;
|
|
146
|
+
stdoutCb(msg);
|
|
147
|
+
// 应用安装成功,则启动它
|
|
148
|
+
if (emulatorutil_1.EmulatorLog.inStallIsFinshe(msg)) {
|
|
149
|
+
ColorConsole_1.default.info(`### Emulator ### Install quickapp successfully`);
|
|
150
|
+
this.launchQuickapp();
|
|
151
|
+
}
|
|
152
|
+
// 匹配到,则认为模拟器启动成功
|
|
153
|
+
if (func(msg)) {
|
|
152
154
|
ColorConsole_1.default.info(`### Emulator ### Goldfish emulator starts successfully`);
|
|
153
155
|
resolve();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
resolve();
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
/** 通过adb连接模拟器 */
|
|
162
|
-
connectGoldfish() {
|
|
163
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
164
|
-
let adbConnected = false;
|
|
165
|
-
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
167
|
-
while (!adbConnected) {
|
|
168
|
-
const adbKillCmd = `adb kill-server`;
|
|
169
|
-
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
170
|
-
yield adbMiwt.execAdbCmdAsync(adbKillCmd);
|
|
171
|
-
const adbConnectCmd = `adb connect ${sn}`;
|
|
172
|
-
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
173
|
-
const str = yield adbMiwt.execAdbCmdAsync(adbConnectCmd);
|
|
174
|
-
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
175
|
-
const devices = yield adbMiwt.getAdbDevices();
|
|
176
|
-
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
177
|
-
adbConnected =
|
|
178
|
-
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
179
|
-
}
|
|
180
|
-
Promise.resolve(adbConnected);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
181
158
|
});
|
|
182
|
-
yield Promise.race([
|
|
183
|
-
connectFn(),
|
|
184
|
-
new Promise((resolve) => {
|
|
185
|
-
setTimeout(() => resolve(false), 600 * 1000);
|
|
186
|
-
})
|
|
187
|
-
]);
|
|
188
|
-
return adbConnected;
|
|
189
159
|
});
|
|
190
160
|
}
|
|
191
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* 在模拟器中启动快应用
|
|
163
|
+
* 1. 检查release目录是否有打包好的rpk
|
|
164
|
+
* 2. 检查当前是否为调试模式.
|
|
165
|
+
* 若是,将debugger_ip.cfg推到模拟器的/data/目录下
|
|
166
|
+
* 若否,则要删除模拟器中已有的data/debugger_ip.cfg
|
|
167
|
+
* 3. 调用installRpkToAppList将当前快应用安装到模拟器的应用列表中
|
|
168
|
+
* @param options
|
|
169
|
+
*/
|
|
192
170
|
startupQuickApp(options) {
|
|
193
171
|
return __awaiter(this, void 0, void 0, function* () {
|
|
172
|
+
var _a;
|
|
194
173
|
const { package: appPackageName } = this.projectInfo;
|
|
195
|
-
const releaseDir =
|
|
174
|
+
const releaseDir = this.isRpk
|
|
175
|
+
? path_1.default.resolve(this.projectPath, '../')
|
|
176
|
+
: path_1.default.resolve(this.projectPath, ((_a = this.params.compilerOption) === null || _a === void 0 ? void 0 : _a.releasePath) || 'dist');
|
|
196
177
|
const files = fs_extra_1.default
|
|
197
178
|
.readdirSync(releaseDir)
|
|
198
|
-
.filter(item => item.includes(appPackageName) && item.endsWith('.rpk'));
|
|
199
|
-
if (files.length
|
|
179
|
+
.filter((item) => item.includes(appPackageName) && item.endsWith('.rpk'));
|
|
180
|
+
if (files.length === 0) {
|
|
200
181
|
ColorConsole_1.default.error(`### Emulator the rpk does not exist`);
|
|
201
182
|
}
|
|
202
183
|
const rpkPath = path_1.default.resolve(releaseDir, files[0]);
|
|
203
184
|
// 调试模式需要push一个文件至miwear中
|
|
204
|
-
const sn = `127.0.0.1:${this.adbPort}`;
|
|
205
185
|
if (options.devtool) {
|
|
206
186
|
const debuggerCfgFile = path_1.default.join(__dirname, '../static/debugger_ip.cfg');
|
|
207
|
-
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
|
|
187
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} push ${debuggerCfgFile} /data/debugger_ip.cfg`);
|
|
208
188
|
}
|
|
209
189
|
else {
|
|
210
|
-
adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell rm /data/debugger_ip.cfg`);
|
|
190
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} shell rm /data/debugger_ip.cfg`);
|
|
211
191
|
}
|
|
212
|
-
this.
|
|
192
|
+
this.pushAndInstall(rpkPath, this.appDir);
|
|
193
|
+
// this.launchQuickapp()
|
|
213
194
|
});
|
|
214
195
|
}
|
|
215
|
-
/**
|
|
216
|
-
|
|
196
|
+
/**
|
|
197
|
+
* 将快应用安装到模拟器的应用列表
|
|
198
|
+
* 1. 使用adb push将打包好的rpk推到模拟器的/data/quickapp/app/
|
|
199
|
+
* 2. nsh中调用pm install命令安装应用
|
|
200
|
+
* @param rpkPath rpk的绝对目录
|
|
201
|
+
* @param targetDir 要将rpk放到模拟器的哪个目录下
|
|
202
|
+
*/
|
|
203
|
+
pushAndInstall(rpkPath, targetDir) {
|
|
217
204
|
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
237
|
-
yield (0, utils_1.sleep)(100);
|
|
238
|
-
// 3. 安装应用
|
|
239
|
-
const installCmd = `adb -s ${sn} shell pm install ${targetPath}`;
|
|
240
|
-
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
|
|
241
|
-
adbMiwt.execAdbCmdAsync(installCmd);
|
|
242
|
-
}
|
|
243
|
-
catch (e) { }
|
|
205
|
+
const { package: packageName } = this.projectInfo;
|
|
206
|
+
// 1. adb push应用的rpk
|
|
207
|
+
const targetPath = `${targetDir}/${packageName}.rpk`;
|
|
208
|
+
const pushCmd = `adb -s ${this.sn} push "${rpkPath}" ${targetPath}`;
|
|
209
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
|
|
210
|
+
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
211
|
+
const installCmd = `adb -s ${this.sn} shell pm install ${targetPath}`;
|
|
212
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${installCmd}`);
|
|
213
|
+
yield adbMiwt.execAdbCmdAsync(installCmd);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/** 使用am start启动快应用 */
|
|
217
|
+
launchQuickapp() {
|
|
218
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
219
|
+
const { package: packageName } = this.projectInfo;
|
|
220
|
+
const startCmd = `adb -s ${this.sn} shell am start ${packageName}`;
|
|
221
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${startCmd}`);
|
|
222
|
+
adbMiwt.execAdbCmdAsync(startCmd);
|
|
244
223
|
});
|
|
245
224
|
}
|
|
225
|
+
/** 连接模拟器中的调试服务,创建debugSocket
|
|
226
|
+
* 主要用于热更新时,通过debugSocket通知调试服务更新页面
|
|
227
|
+
* 设置了重连机制,会重复连接8次
|
|
228
|
+
*/
|
|
246
229
|
initDebugSocket() {
|
|
247
|
-
|
|
248
|
-
return Promise.resolve();
|
|
249
|
-
}
|
|
250
|
-
this.debugSocket = new ws_1.default(`ws://localhost:${this.debugPort}`);
|
|
251
|
-
this.debugSocket.onopen = () => {
|
|
252
|
-
ColorConsole_1.default.info(`### Emulator debugSocket connect success`);
|
|
253
|
-
return Promise.resolve();
|
|
254
|
-
};
|
|
255
|
-
this.debugSocket.onerror = (e) => {
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
256
231
|
var _a;
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (this.reconnectCount < MAX_RECONNECT_COUNT) {
|
|
260
|
-
ColorConsole_1.default.info(`### Emulator the ${this.reconnectCount + 1}th time to reconnect debug server`);
|
|
261
|
-
this.reconnectCount++;
|
|
262
|
-
setTimeout(() => this.initDebugSocket(), 2000);
|
|
232
|
+
if (this.debugSocket && this.debugSocket.OPEN) {
|
|
233
|
+
return resolve();
|
|
263
234
|
}
|
|
264
|
-
|
|
235
|
+
this.debugSocket = new ws_1.default(`ws://localhost:${(_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.debugPort}`);
|
|
236
|
+
this.debugSocket.onopen = () => {
|
|
237
|
+
ColorConsole_1.default.info(`### Emulator debugSocket connect success`);
|
|
238
|
+
return resolve();
|
|
239
|
+
};
|
|
240
|
+
this.debugSocket.onerror = (errorEvent) => {
|
|
241
|
+
var _a;
|
|
242
|
+
// 重连机制
|
|
243
|
+
(_a = this.debugSocket) === null || _a === void 0 ? void 0 : _a.terminate();
|
|
244
|
+
if (this.reconnectCount < MAX_RECONNECT_COUNT) {
|
|
245
|
+
ColorConsole_1.default.info(`### Emulator the ${this.reconnectCount + 1}th time to reconnect debug server`);
|
|
246
|
+
this.reconnectCount++;
|
|
247
|
+
setTimeout(() => this.initDebugSocket(), 2000);
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
this.debugSocket = undefined;
|
|
251
|
+
this.reconnectCount = 0;
|
|
252
|
+
return reject(`### Emulator debugSocket connect failed, ${errorEvent.message}`);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
this.debugSocket.onclose = (closeEvent) => {
|
|
265
256
|
this.debugSocket = undefined;
|
|
266
257
|
this.reconnectCount = 0;
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
};
|
|
270
|
-
this.debugSocket.onclose = (e) => {
|
|
271
|
-
this.debugSocket = undefined;
|
|
272
|
-
this.reconnectCount = 0;
|
|
273
|
-
ColorConsole_1.default.log(`### Emulator debugSocket connect close: ${e.data}`);
|
|
274
|
-
};
|
|
258
|
+
ColorConsole_1.default.log(`### Emulator debugSocket connect close: ${closeEvent.reason}`);
|
|
259
|
+
};
|
|
260
|
+
});
|
|
275
261
|
}
|
|
276
|
-
/** 通知模拟器更新
|
|
262
|
+
/** 通知模拟器更新
|
|
263
|
+
* 1. 确保已经成功连接模拟器中的调试服务
|
|
264
|
+
* 2. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
|
|
265
|
+
* 3. 发送Page.reload命令给调试服务,通知更新
|
|
266
|
+
*/
|
|
277
267
|
handleUpdate() {
|
|
278
|
-
var _a, _b;
|
|
279
268
|
return __awaiter(this, void 0, void 0, function* () {
|
|
269
|
+
var _a, _b;
|
|
280
270
|
try {
|
|
281
271
|
this.reconnectCount = 0;
|
|
282
272
|
yield this.initDebugSocket();
|
|
283
273
|
// 1. 将整包重新推到miwear中(TODO:增量更新)
|
|
284
|
-
|
|
285
|
-
const { package: appPackageName } = this.projectInfo;
|
|
286
|
-
// windows平台adb push时无法使用通配符,需另外处理
|
|
287
|
-
if (os_1.default.platform() === 'win32') {
|
|
288
|
-
const rmCmd = `adb -s ${sn} shell rm -r ${this.appPathInEmulator}/${appPackageName}`;
|
|
289
|
-
yield adbMiwt.execAdbCmdAsync(rmCmd);
|
|
290
|
-
const sourcePath = path_1.default.resolve(this.projectPath, './build');
|
|
291
|
-
const pushCmd = `adb -s ${sn} push ${sourcePath} ${this.appPathInEmulator}/${appPackageName}`;
|
|
292
|
-
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
const sourcePath = path_1.default.resolve(this.projectPath, './build/*');
|
|
296
|
-
yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourcePath} ${this.appPathInEmulator}/${appPackageName}`);
|
|
297
|
-
}
|
|
298
|
-
ColorConsole_1.default.info(`### Emulator push to ${this.appPathInEmulator}/${appPackageName} successfully`);
|
|
274
|
+
yield this.pushBuild();
|
|
299
275
|
// 2. 下发CDP命令给调试服务告知刷新
|
|
300
276
|
if (((_a = this.debugSocket) === null || _a === void 0 ? void 0 : _a.readyState) === ws_1.default.OPEN) {
|
|
301
277
|
(_b = this.debugSocket) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({ id: 10000, method: 'Page.reload', params: {} }));
|
|
@@ -306,18 +282,80 @@ class MiwearInstance extends common_1.default {
|
|
|
306
282
|
}
|
|
307
283
|
});
|
|
308
284
|
}
|
|
309
|
-
/**
|
|
285
|
+
/** 热更新时push目录 */
|
|
286
|
+
pushBuild() {
|
|
287
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
const { package: appPackageName } = this.projectInfo;
|
|
289
|
+
// windows平台adb push时无法使用通配符,需另外处理;
|
|
290
|
+
// 项目路径包含空格时,无法通过加引号来使用 * 通配符
|
|
291
|
+
if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
|
|
292
|
+
const rmCmd = `adb -s ${this.sn} shell rm -r ${this.appDir}/${appPackageName}`;
|
|
293
|
+
yield adbMiwt.execAdbCmdAsync(rmCmd);
|
|
294
|
+
const sourcePath = path_1.default.resolve(this.projectPath, './build');
|
|
295
|
+
const pushCmd = `adb -s ${this.sn} push "${sourcePath}" ${this.appDir}/${appPackageName}`;
|
|
296
|
+
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
const sourcePath = path_1.default.resolve(this.projectPath, './build/*');
|
|
300
|
+
yield adbMiwt.execAdbCmdAsync(`adb -s ${this.sn} push ${sourcePath} ${this.appDir}/${appPackageName}`);
|
|
301
|
+
}
|
|
302
|
+
ColorConsole_1.default.info(`### Emulator push to ${this.appDir}/${appPackageName} successfully`);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
/** 通过命令行启动时,在watich模式下监听websocket消息,
|
|
306
|
+
* 在文件发生变动时,重新启动应用
|
|
307
|
+
*/
|
|
308
|
+
restart() {
|
|
309
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
+
this.pushAndReloadApp();
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/** 在模拟器中重启快应用(基于am命令,需要保证镜像中已经有am功能)
|
|
314
|
+
* 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
|
|
315
|
+
* 2. nsh中执行am stop命令退出快应用
|
|
316
|
+
* 3. nsh中执行am start命令启动快应用
|
|
317
|
+
*/
|
|
318
|
+
pushAndReloadApp() {
|
|
319
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
320
|
+
// 1. 将整包重新推到miwear中(TODO:增量更新)
|
|
321
|
+
yield this.pushBuild();
|
|
322
|
+
yield this.reloadApp();
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
reloadApp() {
|
|
326
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
327
|
+
try {
|
|
328
|
+
const { package: appPackageName } = this.projectInfo;
|
|
329
|
+
// 2. 执行am stop和am start命令
|
|
330
|
+
const stopCmd = `adb -s ${this.sn} shell am stop ${appPackageName}`;
|
|
331
|
+
yield adbMiwt.execAdbCmdAsync(stopCmd);
|
|
332
|
+
ColorConsole_1.default.info(`### Emulator stop ${appPackageName} successfully`);
|
|
333
|
+
// 这里是为了等am stop命令清除资源等
|
|
334
|
+
yield (0, utils_1.sleep)(500);
|
|
335
|
+
const startCmd = `adb -s ${this.sn} shell am start ${appPackageName}`;
|
|
336
|
+
yield adbMiwt.execAdbCmdAsync(startCmd);
|
|
337
|
+
ColorConsole_1.default.info(`### Emulator start ${appPackageName} successfully`);
|
|
338
|
+
}
|
|
339
|
+
catch (e) {
|
|
340
|
+
ColorConsole_1.default.error(`${e}`);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* 创建server端,监听打包过程中client端发来的消息
|
|
346
|
+
*/
|
|
310
347
|
createWebsockeServer() {
|
|
311
|
-
var _a;
|
|
312
348
|
return __awaiter(this, void 0, void 0, function* () {
|
|
349
|
+
var _a;
|
|
313
350
|
const wsServer = new ws_1.WebSocketServer({
|
|
314
|
-
port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort
|
|
351
|
+
port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort
|
|
315
352
|
});
|
|
316
|
-
wsServer.on('connection', socket => {
|
|
353
|
+
wsServer.on('connection', (socket) => {
|
|
317
354
|
ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
|
|
318
|
-
socket.on('error', err => {
|
|
355
|
+
socket.on('error', (err) => {
|
|
319
356
|
ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
|
|
320
357
|
});
|
|
358
|
+
// data的格式:{ type: string, data: any }
|
|
321
359
|
socket.on('message', (data) => __awaiter(this, void 0, void 0, function* () {
|
|
322
360
|
var _a;
|
|
323
361
|
const message = JSON.parse(data.toString());
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import GoldfishInstance from './dev';
|
|
2
|
+
/**
|
|
3
|
+
* 不带 miwear 的 4.0 镜像
|
|
4
|
+
*/
|
|
5
|
+
declare class PreInstance extends GoldfishInstance {
|
|
6
|
+
appDir: string;
|
|
7
|
+
pushRpk(rpkPath?: string): Promise<string>;
|
|
8
|
+
installApp(rpkPath?: string): Promise<void>;
|
|
9
|
+
pushAndInstall(rpkPath?: string): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export default PreInstance;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
const path_1 = __importDefault(require("path"));
|
|
39
|
+
const fs_1 = __importDefault(require("fs"));
|
|
40
|
+
const dev_1 = __importDefault(require("./dev"));
|
|
41
|
+
const miwear_1 = __importDefault(require("./miwear"));
|
|
42
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
43
|
+
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
44
|
+
/**
|
|
45
|
+
* 不带 miwear 的 4.0 镜像
|
|
46
|
+
*/
|
|
47
|
+
class PreInstance extends dev_1.default {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(...arguments);
|
|
50
|
+
this.appDir = '/data/quickapp/app';
|
|
51
|
+
}
|
|
52
|
+
pushRpk(rpkPath) {
|
|
53
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
54
|
+
const { package: appPackageName } = this.projectInfo;
|
|
55
|
+
const releaseDir = this.isRpk
|
|
56
|
+
? path_1.default.resolve(this.projectPath, '../')
|
|
57
|
+
: path_1.default.resolve(this.projectPath, 'dist');
|
|
58
|
+
let srouceRpk = rpkPath;
|
|
59
|
+
if (!srouceRpk) {
|
|
60
|
+
const files = fs_1.default
|
|
61
|
+
.readdirSync(releaseDir)
|
|
62
|
+
.filter((item) => item.includes(appPackageName) && item.endsWith('.rpk'));
|
|
63
|
+
if (files.length === 0) {
|
|
64
|
+
ColorConsole_1.default.error(`### Emulator the rpk does not exist`);
|
|
65
|
+
}
|
|
66
|
+
srouceRpk = path_1.default.resolve(releaseDir, files[0]);
|
|
67
|
+
}
|
|
68
|
+
// 1. adb push应用的rpk
|
|
69
|
+
const targetPath = `${this.appDir}/${appPackageName}.rpk`;
|
|
70
|
+
const pushCmd = `adb -s ${this.sn} push "${srouceRpk}" ${targetPath}`;
|
|
71
|
+
ColorConsole_1.default.info(`### Emulator ### Excuting cmd: ${pushCmd}`);
|
|
72
|
+
yield adbMiwt.execAdbCmdAsync(pushCmd);
|
|
73
|
+
ColorConsole_1.default.info(`### Emulator push to ${this.appDir}/${appPackageName} successfully`);
|
|
74
|
+
return targetPath;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
installApp(rpkPath) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
const { package: appPackageName } = this.projectInfo;
|
|
80
|
+
// 基于 vapp 启动的应用只需要将 rpk 解压到指定的目录下
|
|
81
|
+
rpkPath = rpkPath || `${this.appDir}/${appPackageName}.rpk`;
|
|
82
|
+
const targetPath = `${this.appDir}/${appPackageName}`;
|
|
83
|
+
const mkdirCmd = `adb -s ${this.sn} shell mkdir ${targetPath}`;
|
|
84
|
+
ColorConsole_1.default.info(`### Emulator mkdir cmd ${mkdirCmd}`);
|
|
85
|
+
yield adbMiwt.execAdbCmdAsync(mkdirCmd);
|
|
86
|
+
const unzipCmd = `adb -s ${this.sn} shell unzip -o ${rpkPath} -d ${targetPath}`;
|
|
87
|
+
ColorConsole_1.default.info(`### Emulator unzip cmd ${unzipCmd}`);
|
|
88
|
+
yield adbMiwt.execAdbCmdAsync(unzipCmd);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
pushAndInstall(rpkPath) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
const target = yield this.pushRpk(rpkPath);
|
|
94
|
+
yield this.installApp(target);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// pre 镜像的 启动 方式与 MiwearInstance 一致
|
|
99
|
+
PreInstance.prototype.startGoldfish = miwear_1.default.prototype.startGoldfish;
|
|
100
|
+
exports.default = PreInstance;
|