feat:iOS run on simulator
This commit is contained in:
parent
0ffc1261a1
commit
130461769a
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"]);
|
||||||
}
|
}
|
Reference in New Issue
Block a user