Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
Add a command to build and run on Android (#3239)
Browse files Browse the repository at this point in the history
  • Loading branch information
fson authored Mar 15, 2021
1 parent cac8bdf commit aebbacf
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/expo-cli/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const COMMANDS = [
require('./publish-modify'),
require('./push-creds'),
require('./register'),
require('./run'),
require('./send'),
require('./start'),
require('./upgrade'),
Expand Down
73 changes: 73 additions & 0 deletions packages/expo-cli/src/commands/run/buildAndroidClientAsync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { AndroidConfig } from '@expo/config-plugins';
import spawnAsync from '@expo/spawn-async';
import { Android } from '@expo/xdl';
import ora from 'ora';
import path from 'path';

import Log from '../../log';
import { prebuildAsync } from '../eject/prebuildAsync';

type Options = {
buildVariant: string;
};

function capitalize(name: string) {
return name.charAt(0).toUpperCase() + name.slice(1);
}

function getGradleTask(buildVariant: string): string {
return `install${capitalize(buildVariant)}`;
}

export default async function buildAndroidClientAsync(
projectRoot: string,
options: Options
): Promise<void> {
const devices = await Android.getAllAvailableDevicesAsync();
const device = devices.length > 1 ? await Android.promptForDeviceAsync(devices) : devices[0];
if (!device) {
return;
}
const bootedDevice = await Android.attemptToStartEmulatorOrAssertAsync(device);
if (!bootedDevice) {
return;
}

Log.log('Building app...');

let androidProjectPath;
try {
androidProjectPath = await AndroidConfig.Paths.getProjectPathOrThrowAsync(projectRoot);
} catch {
// If the project doesn't have native code, prebuild it...
await prebuildAsync(projectRoot, {
install: true,
platforms: ['android'],
});
androidProjectPath = await AndroidConfig.Paths.getProjectPathOrThrowAsync(projectRoot);
}

const gradlew = path.join(
androidProjectPath,
process.platform === 'win32' ? 'gradlew.bat' : 'gradlew'
);

await spawnAsync(gradlew, [getGradleTask(options.buildVariant)], {
cwd: androidProjectPath,
stdio: 'inherit',
});

const spinner = ora('Starting the development client...').start();
try {
await Android.openProjectAsync({
projectRoot,
shouldPrompt: false,
devClient: true,
});
} catch (error) {
spinner.fail();
throw error;
}

spinner.succeed();
}
27 changes: 27 additions & 0 deletions packages/expo-cli/src/commands/run/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Command } from 'commander';

import CommandError from '../../CommandError';
import buildAndroidClientAsync from './buildAndroidClientAsync';

type Options = {
platform?: string;
buildVariant?: string;
};

async function runAndroidAsync(projectRoot: string, options: Options) {
if (typeof options.buildVariant !== 'string') {
throw new CommandError('--build-variant must be a string');
}
await buildAndroidClientAsync(projectRoot, {
buildVariant: options.buildVariant,
});
}

export default function (program: Command) {
program
.command('run:android [path]')
.helpGroup('experimental')
.description('Build a development client and run it in on a device.')
.option('--build-variant [name]', '(Android) build variant', 'release')
.asyncActionProjectDir(runAndroidAsync);
}
4 changes: 2 additions & 2 deletions packages/xdl/src/Android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ async function _openUrlAsync({
return openProject;
}

async function attemptToStartEmulatorOrAssertAsync(device: Device): Promise<Device | null> {
export async function attemptToStartEmulatorOrAssertAsync(device: Device): Promise<Device | null> {
// TODO: Add a light-weight method for checking since a device could disconnect.

if (!(await isDeviceBootedAsync(device))) {
Expand Down Expand Up @@ -995,7 +995,7 @@ function nameStyleForDevice(device: Device) {
return (text: string) => chalk.bold(chalk.gray(text));
}

async function promptForDeviceAsync(devices: Device[]): Promise<Device | null> {
export async function promptForDeviceAsync(devices: Device[]): Promise<Device | null> {
// TODO: provide an option to add or download more simulators

// Pause interactions on the TerminalUI
Expand Down

0 comments on commit aebbacf

Please sign in to comment.