@aiot-toolkit/emulator 2.0.1-alpha.8 → 2.0.2-beta.1
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/avd/index.js +39 -36
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -5
- package/lib/instance/{goldfish.d.ts → common.d.ts} +22 -14
- package/lib/instance/common.js +294 -0
- package/lib/instance/dev.d.ts +15 -0
- package/lib/instance/dev.js +184 -0
- package/lib/instance/index.d.ts +7 -0
- package/lib/instance/index.js +32 -0
- package/lib/instance/miwear.d.ts +28 -0
- package/lib/instance/miwear.js +341 -0
- package/lib/instance/preDev.d.ts +23 -0
- package/lib/instance/{goldfish.js → preDev.js} +106 -143
- package/lib/static/constants.d.ts +12 -0
- package/lib/static/constants.js +13 -3
- package/lib/static/debugger_ip.cfg +1 -0
- package/lib/typing/Avd.js +0 -2
- package/lib/typing/Instance.d.ts +6 -0
- package/lib/typing/Instance.js +0 -2
- package/lib/utils/index.d.ts +12 -0
- package/lib/utils/index.js +87 -0
- package/package.json +4 -4
- package/lib/avd/index.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/instance/goldfish.js.map +0 -1
- package/lib/static/constants.js.map +0 -1
- package/lib/typing/Avd.js.map +0 -1
- package/lib/typing/Instance.js.map +0 -1
package/lib/avd/index.js
CHANGED
|
@@ -3,6 +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
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
6
7
|
const fs_1 = __importDefault(require("fs"));
|
|
7
8
|
const path_1 = __importDefault(require("path"));
|
|
8
9
|
const constants_1 = require("../static/constants");
|
|
@@ -20,6 +21,9 @@ class VelaAvdCls {
|
|
|
20
21
|
const { avdHome, sdkHome } = avdResourcePaths;
|
|
21
22
|
this.avdHome = avdHome || constants_1.defaultAvdHome;
|
|
22
23
|
this.sdkHome = sdkHome || constants_1.defaultSDKHome;
|
|
24
|
+
if (!fs_1.default.existsSync(this.avdHome)) {
|
|
25
|
+
fs_1.default.mkdirSync(this.avdHome, { recursive: true });
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
createVelaAvd(avdParams) {
|
|
25
29
|
const { avdName, avdArch, avdWidth, avdHeight, avdSkin, avdImagePath = constants_1.defaultImageHome } = avdParams;
|
|
@@ -62,7 +66,7 @@ class VelaAvdCls {
|
|
|
62
66
|
return true;
|
|
63
67
|
}
|
|
64
68
|
catch (e) {
|
|
65
|
-
|
|
69
|
+
throw (`createVelaAvd: ${e.message}`);
|
|
66
70
|
}
|
|
67
71
|
}
|
|
68
72
|
getVelaAvdInfo(avdName) {
|
|
@@ -76,24 +80,30 @@ class VelaAvdCls {
|
|
|
76
80
|
};
|
|
77
81
|
const currAvdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
78
82
|
const configIni = path_1.default.resolve(currAvdDir, 'config.ini');
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
83
|
+
try {
|
|
84
|
+
const contents = fs_1.default.readFileSync(configIni, 'utf-8');
|
|
85
|
+
// 这里需要使用惰性匹配
|
|
86
|
+
const archRegex = /hw.cpu.arch = ([\d\D]+?)\n/;
|
|
87
|
+
const archMatcher = contents.match(archRegex);
|
|
88
|
+
const heightRegex = /hw.lcd.height = ([\d\D]+?)\n/;
|
|
89
|
+
const heightMatcher = contents.match(heightRegex);
|
|
90
|
+
const widthRegex = /hw.lcd.width = ([\d\D]+?)\n/;
|
|
91
|
+
const widthMatcher = contents.match(widthRegex);
|
|
92
|
+
const skinRegex = /skin.name = ([\d\D]+?)\n/;
|
|
93
|
+
const skinMatcher = contents.match(skinRegex);
|
|
94
|
+
const imagePathRegex = /image.sysdir.1 = ([\d\D]+?)\n/;
|
|
95
|
+
const imagePathMather = contents.match(imagePathRegex);
|
|
96
|
+
archMatcher && (avdInfo.avdArch = archMatcher[1]);
|
|
97
|
+
heightMatcher && (avdInfo.avdHeight = heightMatcher[1]);
|
|
98
|
+
widthMatcher && (avdInfo.avdWidth = widthMatcher[1]);
|
|
99
|
+
skinMatcher && (avdInfo.avdSkin = skinMatcher[1]);
|
|
100
|
+
imagePathMather && (avdInfo.avdImagePath = imagePathMather[1]);
|
|
101
|
+
return avdInfo;
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
ColorConsole_1.default.log(`getVelaAvdInfo: ${err.message}`);
|
|
105
|
+
return avdInfo;
|
|
106
|
+
}
|
|
97
107
|
}
|
|
98
108
|
deleteVelaAvd(avdName) {
|
|
99
109
|
const avdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
@@ -108,23 +118,18 @@ class VelaAvdCls {
|
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
getVelaAvdList() {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
avdList.push(avdInfo);
|
|
121
|
-
}
|
|
121
|
+
const avdList = [];
|
|
122
|
+
const files = fs_1.default.readdirSync(this.avdHome);
|
|
123
|
+
const regex = /^(Vela[\d\D]*)\.avd$/;
|
|
124
|
+
for (const fileName of files) {
|
|
125
|
+
const matcher = fileName.match(regex);
|
|
126
|
+
if (matcher) {
|
|
127
|
+
const avdName = matcher[1];
|
|
128
|
+
const avdInfo = this.getVelaAvdInfo(avdName);
|
|
129
|
+
avdList.push(avdInfo);
|
|
122
130
|
}
|
|
123
|
-
return avdList;
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
return [];
|
|
127
131
|
}
|
|
132
|
+
return avdList;
|
|
128
133
|
}
|
|
129
134
|
getVelaSkinList() {
|
|
130
135
|
try {
|
|
@@ -142,5 +147,3 @@ class VelaAvdCls {
|
|
|
142
147
|
}
|
|
143
148
|
}
|
|
144
149
|
exports.default = VelaAvdCls;
|
|
145
|
-
|
|
146
|
-
//# sourceMappingURL=index.js.map
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as VelaAvdCls } from './avd';
|
|
2
|
-
|
|
2
|
+
export * from './instance';
|
|
3
3
|
export * from './typing/Avd';
|
|
4
4
|
export * from './typing/Instance';
|
|
5
|
-
export {
|
|
5
|
+
export { VelaAvdCls };
|
package/lib/index.js
CHANGED
|
@@ -17,12 +17,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
17
17
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
18
|
};
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.VelaAvdCls =
|
|
20
|
+
exports.VelaAvdCls = void 0;
|
|
21
21
|
const avd_1 = __importDefault(require("./avd"));
|
|
22
22
|
Object.defineProperty(exports, "VelaAvdCls", { enumerable: true, get: function () { return avd_1.default; } });
|
|
23
|
-
|
|
24
|
-
Object.defineProperty(exports, "GoldfishInstance", { enumerable: true, get: function () { return goldfish_1.default; } });
|
|
23
|
+
__exportStar(require("./instance"), exports);
|
|
25
24
|
__exportStar(require("./typing/Avd"), exports);
|
|
26
25
|
__exportStar(require("./typing/Instance"), exports);
|
|
27
|
-
|
|
28
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import IManifest from '@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/interface/IManifest';
|
|
2
3
|
import { ChildProcess } from 'child_process';
|
|
4
|
+
import VelaAvdCls from '../avd';
|
|
3
5
|
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* CommonInstance
|
|
8
|
+
*/
|
|
9
|
+
declare class CommonInstance {
|
|
10
|
+
projectPath: string;
|
|
11
|
+
sdkHome: string;
|
|
12
|
+
avdHome: string;
|
|
13
|
+
adbPort: number;
|
|
9
14
|
debugPort: number;
|
|
10
|
-
|
|
11
|
-
private velaAvdCls;
|
|
12
|
-
private packageName;
|
|
15
|
+
velaAvdCls: VelaAvdCls;
|
|
13
16
|
goldfishProcess: ChildProcess | undefined;
|
|
14
|
-
|
|
17
|
+
isFirstStart: boolean;
|
|
18
|
+
startOptions: IStartOptions | undefined;
|
|
19
|
+
projectInfo: IManifest;
|
|
20
|
+
isRpk: boolean;
|
|
15
21
|
constructor(params: INewGoldfishInstanceParams);
|
|
16
22
|
/** 获取模拟器二进制文件所在位置 */
|
|
17
23
|
getEmulatorBinPath(): string;
|
|
@@ -19,17 +25,19 @@ declare class GoldfishInstance {
|
|
|
19
25
|
start(options: IStartOptions): Promise<void>;
|
|
20
26
|
/** 在goldfish中启动快应用 */
|
|
21
27
|
startupQuickApp(options: IStartOptions): void;
|
|
22
|
-
/** host启动9pServer */
|
|
23
|
-
ensure9pServerRunnning(): Promise<void>;
|
|
24
28
|
/** 启动goldfish模拟器 */
|
|
25
29
|
startGoldfish(options: IStartOptions): Promise<void>;
|
|
26
30
|
/** 通过adb连接模拟器 */
|
|
27
31
|
connectGoldfish(): Promise<boolean>;
|
|
28
32
|
/** 将打包后的文件推到挂载的快应用目录 */
|
|
29
|
-
pushRpk(): void
|
|
33
|
+
pushRpk(sourceRoot: string): Promise<void>;
|
|
30
34
|
/** 杀死进程 */
|
|
31
35
|
killProcess(currProcess?: ChildProcess): void;
|
|
32
36
|
/** 停止模拟器并释放相关资源 */
|
|
33
|
-
stop(): void
|
|
37
|
+
stop(): Promise<void>;
|
|
38
|
+
/** 重启模拟器 */
|
|
39
|
+
restart(): void;
|
|
40
|
+
/** 创建server */
|
|
41
|
+
createWebsockeServer(): Promise<void>;
|
|
34
42
|
}
|
|
35
|
-
export default
|
|
43
|
+
export default CommonInstance;
|
|
@@ -0,0 +1,294 @@
|
|
|
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 UxFileUtils_1 = __importDefault(require("@aiot-toolkit/aiotpack/lib/utils/ux/UxFileUtils"));
|
|
39
|
+
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
40
|
+
const adbMiwt = __importStar(require("@miwt/adb"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const os_1 = __importDefault(require("os"));
|
|
43
|
+
const path_1 = __importDefault(require("path"));
|
|
44
|
+
const portfinder_1 = __importDefault(require("portfinder"));
|
|
45
|
+
const ws_1 = require("ws");
|
|
46
|
+
const avd_1 = __importDefault(require("../avd"));
|
|
47
|
+
const constants_1 = require("../static/constants");
|
|
48
|
+
const utils_1 = require("../utils");
|
|
49
|
+
/**
|
|
50
|
+
* CommonInstance
|
|
51
|
+
*/
|
|
52
|
+
class CommonInstance {
|
|
53
|
+
constructor(params) {
|
|
54
|
+
this.adbPort = 5555;
|
|
55
|
+
this.debugPort = 10055;
|
|
56
|
+
this.isFirstStart = true;
|
|
57
|
+
this.projectPath = params.projectPath;
|
|
58
|
+
this.sdkHome = params.sdkHome || constants_1.defaultSDKHome;
|
|
59
|
+
this.avdHome = params.avdHome || constants_1.defaultAvdHome;
|
|
60
|
+
this.isRpk = params.sourceRoot === './';
|
|
61
|
+
this.velaAvdCls = new avd_1.default({
|
|
62
|
+
sdkHome: this.sdkHome,
|
|
63
|
+
avdHome: this.avdHome
|
|
64
|
+
});
|
|
65
|
+
this.projectInfo = UxFileUtils_1.default.getMainfestInfo(this.projectPath, params.sourceRoot);
|
|
66
|
+
}
|
|
67
|
+
/** 获取模拟器二进制文件所在位置 */
|
|
68
|
+
getEmulatorBinPath() {
|
|
69
|
+
const osPlatform = os_1.default.platform();
|
|
70
|
+
const arch = (0, utils_1.getSystemArch)();
|
|
71
|
+
const platform = osPlatform === 'win32' ? 'windows' : osPlatform;
|
|
72
|
+
const emulatorHome = path_1.default.resolve(this.sdkHome, 'emulator');
|
|
73
|
+
return path_1.default.resolve(emulatorHome, `${platform}-${arch}`, 'emulator');
|
|
74
|
+
}
|
|
75
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
76
|
+
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
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/** 通过adb连接模拟器 */
|
|
186
|
+
connectGoldfish() {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
let adbConnected = false;
|
|
189
|
+
const connectFn = () => __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
const sn = `127.0.0.1:${this.adbPort}`;
|
|
191
|
+
while (!adbConnected) {
|
|
192
|
+
const adbKillCmd = `adb kill-server`;
|
|
193
|
+
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbKillCmd}`);
|
|
194
|
+
adbMiwt.execAdbCmdSync(adbKillCmd);
|
|
195
|
+
const adbConnectCmd = `adb connect ${sn}`;
|
|
196
|
+
ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${adbConnectCmd}`);
|
|
197
|
+
const str = adbMiwt.execAdbCmdSync(adbConnectCmd);
|
|
198
|
+
ColorConsole_1.default.log(`### Emulator ### ${str}`);
|
|
199
|
+
const devices = yield adbMiwt.getAdbDevices();
|
|
200
|
+
ColorConsole_1.default.log(`### Emulator ### adb devices: ${JSON.stringify(devices)}`);
|
|
201
|
+
adbConnected =
|
|
202
|
+
devices.filter((item) => item.sn === sn && item.status === 'device').length > 0;
|
|
203
|
+
}
|
|
204
|
+
Promise.resolve(adbConnected);
|
|
205
|
+
});
|
|
206
|
+
yield Promise.race([
|
|
207
|
+
connectFn(),
|
|
208
|
+
new Promise((resolve) => {
|
|
209
|
+
setTimeout(() => resolve(false), 600 * 1000);
|
|
210
|
+
})
|
|
211
|
+
]);
|
|
212
|
+
return adbConnected;
|
|
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`);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/** 杀死进程 */
|
|
228
|
+
killProcess(currProcess) {
|
|
229
|
+
if (currProcess && currProcess.pid && currProcess.exitCode === null) {
|
|
230
|
+
console.log('process pid:', currProcess.pid);
|
|
231
|
+
try {
|
|
232
|
+
if (os_1.default.platform() === 'win32') {
|
|
233
|
+
(0, child_process_1.execSync)(`taskkill /pid ${currProcess.pid} /T /F`);
|
|
234
|
+
}
|
|
235
|
+
else if (os_1.default.platform() === 'darwin') {
|
|
236
|
+
process.kill(currProcess.pid);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
currProcess.kill();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
ColorConsole_1.default.log(`### Emulator ### kill process get error :\n${err.stack}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** 停止模拟器并释放相关资源 */
|
|
248
|
+
stop() {
|
|
249
|
+
var _a;
|
|
250
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
251
|
+
if (this.goldfishProcess) {
|
|
252
|
+
// Linux删除goldfishProcess后,子进程仍存在,导致模拟器窗口未关闭
|
|
253
|
+
// 这里的作用是手动删除创建出来的子进程
|
|
254
|
+
// if (os.platform() === 'linux' && this.goldfishProcess.pid) {
|
|
255
|
+
// process.kill(this.goldfishProcess.pid + 1)
|
|
256
|
+
// }
|
|
257
|
+
this.killProcess(this.goldfishProcess);
|
|
258
|
+
yield (0, utils_1.killProcessByCmd)((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.avdName);
|
|
259
|
+
this.goldfishProcess = undefined;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/** 重启模拟器 */
|
|
264
|
+
restart() {
|
|
265
|
+
this.stop();
|
|
266
|
+
this.start(this.startOptions);
|
|
267
|
+
}
|
|
268
|
+
/** 创建server */
|
|
269
|
+
createWebsockeServer() {
|
|
270
|
+
var _a;
|
|
271
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
272
|
+
const wsServer = new ws_1.WebSocketServer({
|
|
273
|
+
port: (_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.serverPort,
|
|
274
|
+
});
|
|
275
|
+
wsServer.on('connection', socket => {
|
|
276
|
+
ColorConsole_1.default.success(`### App Socket server ### Websocket connects to websocket server`);
|
|
277
|
+
socket.on('error', err => {
|
|
278
|
+
ColorConsole_1.default.error(`### App Socket server ### Websocket server error: ${err.message}`);
|
|
279
|
+
});
|
|
280
|
+
socket.on('message', data => {
|
|
281
|
+
const message = JSON.parse(data.toString());
|
|
282
|
+
ColorConsole_1.default.log(`### App Socket server ### Websocket server get data: ${data}`);
|
|
283
|
+
if (message.type === 'restart') {
|
|
284
|
+
this.restart();
|
|
285
|
+
}
|
|
286
|
+
else if (message.type === 'stop') {
|
|
287
|
+
this.stop();
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
exports.default = CommonInstance;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
2
|
+
import CommonInstance from './common';
|
|
3
|
+
declare class GoldfishInstance extends CommonInstance {
|
|
4
|
+
private appRunDir;
|
|
5
|
+
constructor(params: INewGoldfishInstanceParams);
|
|
6
|
+
/** 在goldfish模拟器中运行快应用 */
|
|
7
|
+
start(options: IStartOptions): Promise<void>;
|
|
8
|
+
/** 在goldfish中启动快应用 */
|
|
9
|
+
startupQuickApp(options: IStartOptions): Promise<void>;
|
|
10
|
+
/** 启动goldfish模拟器 */
|
|
11
|
+
startGoldfish(options: IStartOptions): Promise<void>;
|
|
12
|
+
/** 将打包后的文件推到挂载的快应用目录 */
|
|
13
|
+
pushRpk(sourceRoot: string): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export default GoldfishInstance;
|