feat:iOS run on simulator

This commit is contained in:
pengfeizhou 2021-02-26 17:44:48 +08:00 committed by osborn
parent 0ffc1261a1
commit 130461769a
2 changed files with 203 additions and 74 deletions

View File

@ -24,13 +24,12 @@
}, },
"homepage": "https://github.com/penfeizhou/doric#readme", "homepage": "https://github.com/penfeizhou/doric#readme",
"dependencies": { "dependencies": {
"@types/glob": "^7.1.3",
"@types/node": "^14.14.25",
"child_process": "^1.0.2", "child_process": "^1.0.2",
"chokidar": "^3.4.1", "chokidar": "^3.4.1",
"colors": "^1.4.0", "colors": "^1.4.0",
"commander": "^6.0.0", "commander": "^6.0.0",
"glob": "^7.1.6", "glob": "^7.1.6",
"inquirer": "^8.0.0",
"keypress": "^0.2.1", "keypress": "^0.2.1",
"qrcode-terminal": "^0.12.0", "qrcode-terminal": "^0.12.0",
"rollup": "^2.23.0", "rollup": "^2.23.0",
@ -44,6 +43,9 @@
"registry": "https://registry.npmjs.org" "registry": "https://registry.npmjs.org"
}, },
"devDependencies": { "devDependencies": {
"@types/glob": "^7.1.3",
"@types/inquirer": "^7.3.1",
"@types/node": "^14.14.25",
"@types/ws": "^7.4.0" "@types/ws": "^7.4.0"
} }
} }

View File

@ -3,6 +3,9 @@ import fs from "fs";
import { glob } from "./util"; import { glob } from "./util";
import path from "path"; import path from "path";
import xml2js, { Element } from "xml-js"; import xml2js, { Element } from "xml-js";
import inquirer from "inquirer";
import { constants } from "buffer";
import { blue } from "colors";
export async function run(platform: string) { export async function run(platform: string) {
switch (platform.toLowerCase()) { switch (platform.toLowerCase()) {
@ -21,12 +24,15 @@ async function runAndroid() {
console.log("Running on Android"); console.log("Running on Android");
const androidDir = path.resolve(process.cwd(), "android"); const androidDir = path.resolve(process.cwd(), "android");
if (!fs.existsSync(androidDir)) { if (!fs.existsSync(androidDir)) {
console.log("Cannot find Android Project".red) console.log("Cannot find Android Project".red);
return; return;
} }
const androidSDKHome = process.env["ANDROID_HOME"] || process.env["ANDROID_SDK_ROOT"] const androidSDKHome =
process.env["ANDROID_HOME"] || process.env["ANDROID_SDK_ROOT"];
if (!androidSDKHome) { if (!androidSDKHome) {
console.log("Please set env variable $ANDROID_HOME or $ANDROID_SDK_ROOT".red) console.log(
"Please set env variable $ANDROID_HOME or $ANDROID_SDK_ROOT".red
);
return; return;
} }
const adbPath = path.resolve(androidSDKHome, "platform-tools", "adb"); const adbPath = path.resolve(androidSDKHome, "platform-tools", "adb");
@ -35,53 +41,174 @@ async function runAndroid() {
await Shell.exec("sh", ["gradlew", "assembleDebug"], { await Shell.exec("sh", ["gradlew", "assembleDebug"], {
cwd: androidDir, cwd: androidDir,
env: process.env, env: process.env,
consoleHandler: (info) => console.log(info) consoleHandler: (info) => console.log(info),
}); });
const apkFiles = await glob("**/outputs/apk/debug/*.apk", { const apkFiles = await glob("**/outputs/apk/debug/*.apk", {
cwd: androidDir, cwd: androidDir,
}) });
if (apkFiles == null || apkFiles.length == 0) { if (apkFiles == null || apkFiles.length == 0) {
console.log("Cannot find APK".red) console.log("Cannot find APK".red);
return; return;
} }
const apkFile = path.resolve(androidDir, apkFiles[0]) const apkFile = path.resolve(androidDir, apkFiles[0]);
console.log("Built Android APK".green, apkFile.blue); console.log("Built Android APK".green, apkFile.blue);
console.log("===================="); console.log("====================");
console.log("Installing apk".green) console.log("Installing apk".green);
await Shell.exec(adbPath, ["install", "-t", "-r", apkFile], { await Shell.exec(adbPath, ["install", "-t", "-r", apkFile], {
consoleHandler: (info) => console.log(info) consoleHandler: (info) => console.log(info),
}); });
const apk_analyzer = path.resolve(androidSDKHome, "tools", "bin", "apkanalyzer"); const apk_analyzer = path.resolve(
const ret = await Shell.execOut(apk_analyzer, ["manifest", "print", apkFile]) androidSDKHome,
"tools",
"bin",
"apkanalyzer"
);
const ret = await Shell.execOut(apk_analyzer, ["manifest", "print", apkFile]);
const xlmobj = xml2js.xml2js(ret) as Element; const xlmobj = xml2js.xml2js(ret) as Element;
const element = xlmobj.elements const element = xlmobj.elements
?.find(e => e.name === "manifest")?.elements ?.find((e) => e.name === "manifest")
?.find(e => e.name === "application")?.elements ?.elements?.find((e) => e.name === "application")
?.filter(e => e.name === "activity") ?.elements?.filter((e) => e.name === "activity")
?.filter(e => e.elements ?.filter((e) =>
?.find(e => e.name === "intent-filter" && e.elements e.elements?.find(
?.find(e => e.name === "action")?.attributes?.["android:name"] === "android.intent.action.MAIN")) (e) =>
e.name === "intent-filter" &&
e.elements?.find((e) => e.name === "action")?.attributes?.[
"android:name"
] === "android.intent.action.MAIN"
)
);
if (element && element.length > 0) { if (element && element.length > 0) {
const activityElement = element[0]; const activityElement = element[0];
const mainActivity = activityElement.attributes?.["android:name"] const mainActivity = activityElement.attributes?.["android:name"];
const packageName = xlmobj.elements const packageName = xlmobj.elements?.find((e) => e.name === "manifest")
?.find(e => e.name === "manifest")?.attributes?.["package"]; ?.attributes?.["package"];
await Shell.exec( await Shell.exec(
adbPath, adbPath,
["shell", [
"am", "start", "shell",
"-n", `${packageName}/${mainActivity}`, "am",
"-a", "android.intent.action.MAIN", "start",
"-c", "android.intent.category.LAUNCHER"], "-n",
`${packageName}/${mainActivity}`,
"-a",
"android.intent.action.MAIN",
"-c",
"android.intent.category.LAUNCHER",
],
{ {
consoleHandler: (info) => console.log(info) consoleHandler: (info) => console.log(info),
}); }
);
} else { } else {
console.log("Cannot find activity for launch") console.log("Cannot find activity for launch");
} }
} }
async function runiOS() { async function runiOS() {
console.log("Running on iOS");
const iOSDir = path.resolve(process.cwd(), "iOS");
if (!fs.existsSync(iOSDir)) {
console.log("Cannot find iOS Project".red);
return;
}
const devices: {
name: string,
deviceId: string,
isSimulator: boolean
}[] = [];
const simulators: {
name: string,
deviceId: string,
isSimulator: boolean
}[] = [];
const deviceOut = await Shell.execOut("xcrun", ["xctrace", "list", "devices"]);
let deviceIndex = 0;
let simulatorIndex = Number.MAX_SAFE_INTEGER;
deviceOut.split("\n").filter(e => e?.length > 0).forEach((e, index) => {
if (e.trim() === "== Devices ==") {
deviceIndex = index;
} else if (e.trim() === "== Simulators ==") {
simulatorIndex = index;
} else {
const regRet = /(.*)\((.*?)\)/.exec(e);
if (regRet) {
if (index > deviceIndex && index < simulatorIndex) {
devices.push({
name: regRet[1],
deviceId: regRet[2],
isSimulator: false,
});
} else {
simulators.push({
name: regRet[1],
deviceId: regRet[2],
isSimulator: true,
})
}
}
}
});
const answer = await inquirer.prompt([{
type: 'list',
message: 'Please choose which device you want to install',
name: 'device',
default: [...devices, ...simulators].find(e => e.name.indexOf("iPhone") >= 0)?.name,
choices: [...devices, ...simulators].map(e => e.name),
}]);
const selectedDevice = devices.find(e => e.name === answer["device"])
|| simulators.find(e => e.name === answer["device"])
if (!selectedDevice) {
console.log("Cannot find iOS device".red);
return;
}
console.log("Waiting for building".green);
console.log("====================");
await Shell.exec("pod", ["install"], {
env: process.env,
consoleHandler: (info) => console.log(info),
cwd: iOSDir,
});
const workspaceFiles = await glob("*.xcworkspace", { cwd: iOSDir });
if (workspaceFiles?.length !== 1) {
console.log("Cannot find project".red);
return;
}
const workspace = workspaceFiles[0];
const scheme = workspace.replace(".xcworkspace", "");
const ret = await Shell.exec(
"xcodebuild",
[
"-workspace", workspace,
"-scheme", scheme,
"-sdk", "iphonesimulator",
"-derivedDataPath", "build"
],
{
cwd: iOSDir,
env: process.env,
consoleHandler: (info) => {
console.log(info);
}
});
if (ret !== 0) {
console.log("Compile error".red);
return;
}
const iOSAPPs = await glob("**/*.app", { cwd: path.resolve(iOSDir, "build") });
if (iOSAPPs?.length !== 1) {
console.log("Cannot find built app".red);
return;
}
const iOSAPP = path.resolve(iOSDir, "build", iOSAPPs[0]);
console.log("Built iOS APP".green, iOSAPP.blue);
console.log("====================");
await Shell.exec("xcrun", ["instruments", "-w", selectedDevice.deviceId])
console.log("Installing APP to".green, selectedDevice.name.blue);
await Shell.exec("xcrun", ["simctl", "install", selectedDevice.deviceId, iOSAPP]);
await Shell.exec("xcrun", ["simctl", "launch", selectedDevice.deviceId, "pub.doric.ios.hellodoric"]);
} }