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,85 +3,212 @@ 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()) {
case "android": case "android":
await runAndroid(); await runAndroid();
break; break;
case "ios": case "ios":
await runiOS(); await runiOS();
break; break;
default: default:
throw new Error("Donnot support " + platform); throw new Error("Donnot support " + platform);
} }
} }
async function runAndroid() { 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 =
if (!androidSDKHome) { process.env["ANDROID_HOME"] || process.env["ANDROID_SDK_ROOT"];
console.log("Please set env variable $ANDROID_HOME or $ANDROID_SDK_ROOT".red) if (!androidSDKHome) {
return; console.log(
} "Please set env variable $ANDROID_HOME or $ANDROID_SDK_ROOT".red
const adbPath = path.resolve(androidSDKHome, "platform-tools", "adb"); );
console.log("Waiting for building".green); return;
console.log("===================="); }
await Shell.exec("sh", ["gradlew", "assembleDebug"], { const adbPath = path.resolve(androidSDKHome, "platform-tools", "adb");
cwd: androidDir, console.log("Waiting for building".green);
env: process.env, console.log("====================");
consoleHandler: (info) => console.log(info) await Shell.exec("sh", ["gradlew", "assembleDebug"], {
}); cwd: androidDir,
const apkFiles = await glob("**/outputs/apk/debug/*.apk", { env: process.env,
cwd: androidDir, consoleHandler: (info) => console.log(info),
}) });
if (apkFiles == null || apkFiles.length == 0) { const apkFiles = await glob("**/outputs/apk/debug/*.apk", {
console.log("Cannot find APK".red) cwd: androidDir,
return; });
} if (apkFiles == null || apkFiles.length == 0) {
const apkFile = path.resolve(androidDir, apkFiles[0]) console.log("Cannot find APK".red);
console.log("Built Android APK".green, apkFile.blue); return;
console.log("===================="); }
console.log("Installing apk".green) const apkFile = path.resolve(androidDir, apkFiles[0]);
await Shell.exec(adbPath, ["install", "-t", "-r", apkFile], { console.log("Built Android APK".green, apkFile.blue);
consoleHandler: (info) => console.log(info) console.log("====================");
}); console.log("Installing apk".green);
await Shell.exec(adbPath, ["install", "-t", "-r", apkFile], {
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,
const xlmobj = xml2js.xml2js(ret) as Element; "tools",
const element = xlmobj.elements "bin",
?.find(e => e.name === "manifest")?.elements "apkanalyzer"
?.find(e => e.name === "application")?.elements );
?.filter(e => e.name === "activity") const ret = await Shell.execOut(apk_analyzer, ["manifest", "print", apkFile]);
?.filter(e => e.elements const xlmobj = xml2js.xml2js(ret) as Element;
?.find(e => e.name === "intent-filter" && e.elements const element = xlmobj.elements
?.find(e => e.name === "action")?.attributes?.["android:name"] === "android.intent.action.MAIN")) ?.find((e) => e.name === "manifest")
if (element && element.length > 0) { ?.elements?.find((e) => e.name === "application")
const activityElement = element[0]; ?.elements?.filter((e) => e.name === "activity")
const mainActivity = activityElement.attributes?.["android:name"] ?.filter((e) =>
const packageName = xlmobj.elements e.elements?.find(
?.find(e => e.name === "manifest")?.attributes?.["package"]; (e) =>
await Shell.exec( e.name === "intent-filter" &&
adbPath, e.elements?.find((e) => e.name === "action")?.attributes?.[
["shell", "android:name"
"am", "start", ] === "android.intent.action.MAIN"
"-n", `${packageName}/${mainActivity}`, )
"-a", "android.intent.action.MAIN", );
"-c", "android.intent.category.LAUNCHER"], if (element && element.length > 0) {
{ const activityElement = element[0];
consoleHandler: (info) => console.log(info) const mainActivity = activityElement.attributes?.["android:name"];
}); const packageName = xlmobj.elements?.find((e) => e.name === "manifest")
} else { ?.attributes?.["package"];
console.log("Cannot find activity for launch") await Shell.exec(
} adbPath,
[
"shell",
"am",
"start",
"-n",
`${packageName}/${mainActivity}`,
"-a",
"android.intent.action.MAIN",
"-c",
"android.intent.category.LAUNCHER",
],
{
consoleHandler: (info) => console.log(info),
}
);
} else {
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"]);
} }