@expo/cli
Version:
327 lines (326 loc) • 13.1 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
DeviceABI: ()=>DeviceABI,
getServer: ()=>getServer,
logUnauthorized: ()=>logUnauthorized,
isPackageInstalledAsync: ()=>isPackageInstalledAsync,
launchActivityAsync: ()=>launchActivityAsync,
openAppIdAsync: ()=>openAppIdAsync,
openUrlAsync: ()=>openUrlAsync,
uninstallAsync: ()=>uninstallAsync,
getPackageInfoAsync: ()=>getPackageInfoAsync,
installAsync: ()=>installAsync,
adbArgs: ()=>adbArgs,
getAttachedDevicesAsync: ()=>getAttachedDevicesAsync,
getAdbNameForDeviceIdAsync: ()=>getAdbNameForDeviceIdAsync,
isDeviceBootedAsync: ()=>isDeviceBootedAsync,
isBootAnimationCompleteAsync: ()=>isBootAnimationCompleteAsync,
getDeviceABIsAsync: ()=>getDeviceABIsAsync,
getPropertyDataForDeviceAsync: ()=>getPropertyDataForDeviceAsync,
sanitizeAdbDeviceName: ()=>sanitizeAdbDeviceName
});
function _chalk() {
const data = /*#__PURE__*/ _interopRequireDefault(require("chalk"));
_chalk = function() {
return data;
};
return data;
}
function _os() {
const data = /*#__PURE__*/ _interopRequireDefault(require("os"));
_os = function() {
return data;
};
return data;
}
const _adbserver = require("./ADBServer");
const _log = /*#__PURE__*/ _interopRequireWildcard(require("../../../log"));
const _env = require("../../../utils/env");
const _errors = require("../../../utils/errors");
const _link = require("../../../utils/link");
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interopRequireWildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const debug = require("debug")("expo:start:platforms:android:adb");
var DeviceABI;
(function(DeviceABI) {
DeviceABI[// The arch specific android target platforms are soft-deprecated.
// Instead of using TargetPlatform as a combination arch + platform
// the code will be updated to carry arch information in [DarwinArch]
// and [AndroidArch].
"arm"] = "arm";
DeviceABI["arm64"] = "arm64";
DeviceABI["x64"] = "x64";
DeviceABI["x86"] = "x86";
DeviceABI["x8664"] = "x86_64";
DeviceABI["arm64v8a"] = "arm64-v8a";
DeviceABI["armeabiV7a"] = "armeabi-v7a";
DeviceABI["armeabi"] = "armeabi";
DeviceABI["universal"] = "universal";
})(DeviceABI || (DeviceABI = {}));
const CANT_START_ACTIVITY_ERROR = "Activity not started, unable to resolve Intent";
// http://developer.android.com/ndk/guides/abis.html
const PROP_CPU_NAME = "ro.product.cpu.abi";
const PROP_CPU_ABI_LIST_NAME = "ro.product.cpu.abilist";
// Can sometimes be null
// http://developer.android.com/ndk/guides/abis.html
const PROP_BOOT_ANIMATION_STATE = "init.svc.bootanim";
let _server;
function getServer() {
_server != null ? _server : _server = new _adbserver.ADBServer();
return _server;
}
function logUnauthorized(device) {
_log.warn(`\nThis computer is not authorized for developing on ${_chalk().default.bold(device.name)}. ${_chalk().default.dim((0, _link.learnMore)("https://expo.fyi/authorize-android-device"))}`);
}
async function isPackageInstalledAsync(device, androidPackage) {
const packages = await getServer().runAsync(adbArgs(device.pid, "shell", "pm", "list", "packages", "--user", _env.env.EXPO_ADB_USER, androidPackage));
const lines = packages.split(/\r?\n/);
for(let i = 0; i < lines.length; i++){
const line = lines[i].trim();
if (line === `package:${androidPackage}`) {
return true;
}
}
return false;
}
async function launchActivityAsync(device, { launchActivity }) {
return openAsync(adbArgs(device.pid, "shell", "am", "start", // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.
"-f", "0x20000000", // Activity to open first: com.bacon.app/.MainActivity
"-n", launchActivity));
}
async function openAppIdAsync(device, { applicationId }) {
return openAsync(adbArgs(device.pid, "shell", "monkey", "-p", applicationId, "-c", "android.intent.category.LAUNCHER", "1"));
}
async function openUrlAsync(device, { url }) {
return openAsync(adbArgs(device.pid, "shell", "am", "start", "-a", "android.intent.action.VIEW", "-d", // ADB requires ampersands to be escaped.
url.replace(/&/g, String.raw`\&`)));
}
/** Runs a generic command watches for common errors in order to throw with an expected code. */ async function openAsync(args) {
const results = await getServer().runAsync(args);
if (results.includes(CANT_START_ACTIVITY_ERROR) || results.match(/Error: Activity class .* does not exist\./g)) {
throw new _errors.CommandError("APP_NOT_INSTALLED", results.substring(results.indexOf("Error: ")));
}
return results;
}
async function uninstallAsync(device, { appId }) {
return await getServer().runAsync(adbArgs(device.pid, "uninstall", "--user", _env.env.EXPO_ADB_USER, appId));
}
async function getPackageInfoAsync(device, { appId }) {
return await getServer().runAsync(adbArgs(device.pid, "shell", "dumpsys", "package", appId));
}
async function installAsync(device, { filePath }) {
// TODO: Handle the `INSTALL_FAILED_INSUFFICIENT_STORAGE` error.
return await getServer().runAsync(adbArgs(device.pid, "install", "-r", "-d", "--user", _env.env.EXPO_ADB_USER, filePath));
}
function adbArgs(pid, ...options) {
const args = [];
if (pid) {
args.push("-s", pid);
}
return args.concat(options);
}
async function getAttachedDevicesAsync() {
const output = await getServer().runAsync([
"devices",
"-l"
]);
const splitItems = output.trim().replace(/\n$/, "").split(_os().default.EOL)// Filter ADB trace logs from the output, e.g.
// adb D 03-06 15:25:53 63677 4018815 adb_client.cpp:393] adb_query: host:devices-l
// 03-04 12:29:44.557 16415 16415 D adb : commandline.cpp:1646 Using server socket: tcp:172.27.192.1:5037
// 03-04 12:29:44.557 16415 16415 D adb : adb_client.cpp:160 _adb_connect: host:version
.filter((line)=>!line.match(/\.cpp:[0-9]+/));
// First line is `"List of devices attached"`, remove it
// @ts-ignore: todo
const attachedDevices = splitItems.slice(1, splitItems.length).map((line)=>{
// unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']
// authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']
// emulator: ['emulator-5554', 'offline', 'transport_id:1']
const props = line.split(" ").filter(Boolean);
const type = line.includes("emulator") ? "emulator" : "device";
let connectionType;
if (type === "device" && line.includes("usb:")) {
connectionType = "USB";
} else if (type === "device" && line.includes("_adb-tls-connect.")) {
connectionType = "Network";
}
const isBooted = type === "emulator" || props[1] !== "offline";
const isAuthorized = connectionType === "Network" ? line.includes("model:") // Network connected devices show `model:<name>` when authorized
: props[1] !== "unauthorized";
return {
props,
type,
isAuthorized,
isBooted,
connectionType
};
}).filter(({ props: [pid] })=>!!pid);
const devicePromises = attachedDevices.map(async (props)=>{
const { type , props: [pid, ...deviceInfo] , isAuthorized , isBooted , } = props;
let name = null;
if (type === "device") {
if (isAuthorized) {
// Possibly formatted like `model:Pixel_2`
// Transform to `Pixel_2`
const modelItem = deviceInfo.find((info)=>info.includes("model:"));
if (modelItem) {
name = modelItem.replace("model:", "");
}
}
// unauthorized devices don't have a name available to read
if (!name) {
// Device FA8251A00719
name = `Device ${pid}`;
}
} else {
var ref;
// Given an emulator pid, get the emulator name which can be used to start the emulator later.
name = (ref = await getAdbNameForDeviceIdAsync({
pid
})) != null ? ref : "";
}
return props.connectionType ? {
pid,
name,
type,
isAuthorized,
isBooted,
connectionType: props.connectionType
} : {
pid,
name,
type,
isAuthorized,
isBooted
};
});
return Promise.all(devicePromises);
}
async function getAdbNameForDeviceIdAsync(device) {
const results = await getServer().runAsync(adbArgs(device.pid, "emu", "avd", "name"));
if (results.match(/could not connect to TCP port .*: Connection refused/)) {
// Can also occur when the emulator does not exist.
throw new _errors.CommandError("EMULATOR_NOT_FOUND", results);
}
var ref;
return (ref = sanitizeAdbDeviceName(results)) != null ? ref : null;
}
async function isDeviceBootedAsync({ name } = {}) {
const devices = await getAttachedDevicesAsync();
if (!name) {
var ref;
return (ref = devices[0]) != null ? ref : null;
}
var ref1;
return (ref1 = devices.find((device)=>device.name === name)) != null ? ref1 : null;
}
async function isBootAnimationCompleteAsync(pid) {
try {
const props = await getPropertyDataForDeviceAsync({
pid
}, PROP_BOOT_ANIMATION_STATE);
return !!props[PROP_BOOT_ANIMATION_STATE].match(/stopped/);
} catch {
return false;
}
}
async function getDeviceABIsAsync(device) {
const cpuAbiList = (await getPropertyDataForDeviceAsync(device, PROP_CPU_ABI_LIST_NAME))[PROP_CPU_ABI_LIST_NAME];
if (cpuAbiList) {
return cpuAbiList.trim().split(",");
}
const abi = (await getPropertyDataForDeviceAsync(device, PROP_CPU_NAME))[PROP_CPU_NAME];
return [
abi
];
}
async function getPropertyDataForDeviceAsync(device, prop) {
// @ts-ignore
const propCommand = adbArgs(...[
device.pid,
"shell",
"getprop",
prop
].filter(Boolean));
try {
// Prevent reading as UTF8.
const results = await getServer().getFileOutputAsync(propCommand);
// Like:
// [wifi.direct.interface]: [p2p-dev-wlan0]
// [wifi.interface]: [wlan0]
if (prop) {
debug(`Property data: (device pid: ${device.pid}, prop: ${prop}, data: ${results})`);
return {
[prop]: results
};
}
const props = parseAdbDeviceProperties(results);
debug(`Parsed data:`, props);
return props;
} catch (error) {
// TODO: Ensure error has message and not stderr
throw new _errors.CommandError(`Failed to get properties for device (${device.pid}): ${error.message}`);
}
}
function parseAdbDeviceProperties(devicePropertiesString) {
const properties = {};
const propertyExp = /\[(.*?)\]: \[(.*?)\]/gm;
for (const match of devicePropertiesString.matchAll(propertyExp)){
properties[match[1]] = match[2];
}
return properties;
}
function sanitizeAdbDeviceName(deviceName) {
return deviceName.trim().split(/[\r\n]+/).shift();
}
//# sourceMappingURL=adb.js.map
;