This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Doric/doric-cli/src/run.ts
2021-02-26 18:54:13 +08:00

229 lines
6.9 KiB
TypeScript

import { Shell } from "./shell";
import fs from "fs";
import { glob } from "./util";
import path from "path";
import xml2js, { Element } from "xml-js";
import inquirer from "inquirer";
export async function run(platform: string) {
switch (platform.toLowerCase()) {
case "android":
await runAndroid();
break;
case "ios":
await runiOS();
break;
default:
throw new Error("Do not 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),
});
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,
...selectedDevice.isSimulator ? ["-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(
`**/*${selectedDevice.isSimulator ? "iphonesimulator" : "iphoneos"}/*.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("====================");
console.log("Installing APP to".green, selectedDevice.name.blue);
if (selectedDevice.isSimulator) {
const pxjFile = path.resolve(iOSDir, (await glob("**/project.pbxproj", { cwd: iOSDir }))[0]);
const pxjContent = await fs.promises.readFile(pxjFile, "utf-8");
const bundleId = /PRODUCT_BUNDLE_IDENTIFIER\s=\s(\S*?);/g.exec(pxjContent)?.[1];
await Shell.exec("xcrun", ["instruments", "-w", selectedDevice.deviceId])
await Shell.exec("xcrun", ["simctl", "install", selectedDevice.deviceId, iOSAPP]);
await Shell.exec("xcrun", ["simctl", "launch", selectedDevice.deviceId, bundleId || `pub.doric.ios.${scheme.toLowerCase()}`]);
} else {
const iosDeploy = path.resolve("node_modules", ".bin", "ios-deploy")
await Shell.exec(
iosDeploy,
[
"--id", selectedDevice.deviceId,
"--justlaunch",
"--debug",
"--bundle", iOSAPP
])
}
}