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",
"dependencies": {
"@types/glob": "^7.1.3",
"@types/node": "^14.14.25",
"child_process": "^1.0.2",
"chokidar": "^3.4.1",
"colors": "^1.4.0",
"commander": "^6.0.0",
"glob": "^7.1.6",
"inquirer": "^8.0.0",
"keypress": "^0.2.1",
"qrcode-terminal": "^0.12.0",
"rollup": "^2.23.0",
@ -44,6 +43,9 @@
"registry": "https://registry.npmjs.org"
},
"devDependencies": {
"@types/glob": "^7.1.3",
"@types/inquirer": "^7.3.1",
"@types/node": "^14.14.25",
"@types/ws": "^7.4.0"
}
}

View File

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