Skip to content

Commit

Permalink
feat: uninstall app
Browse files Browse the repository at this point in the history
  • Loading branch information
itsspriyansh committed Aug 2, 2024
1 parent 290c862 commit e47986a
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 3 deletions.
9 changes: 6 additions & 3 deletions src/commands/android/subcommands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import colors from 'ansi-colors';
import * as dotenv from 'dotenv';
import path from 'path';

import {checkJavaInstallation, getSdkRootFromEnv} from '../utils/common';
import {connect} from './connect';
import {getPlatformName} from '../../../utils';
import Logger from '../../../logger';
import {getPlatformName} from '../../../utils';
import {Options, Platform} from '../interfaces';
import {checkJavaInstallation, getSdkRootFromEnv} from '../utils/common';
import {connect} from './connect';
import {uninstall} from './uninstall';

export class AndroidSubcommand {
sdkRoot: string;
Expand Down Expand Up @@ -56,6 +57,8 @@ export class AndroidSubcommand {
async executeSubcommand(): Promise<boolean> {
if (this.subcommand === 'connect') {
return await connect(this.options, this.sdkRoot, this.platform);
} else if (this.subcommand === 'uninstall') {
return await uninstall(this.options, this.sdkRoot, this.platform);
}

return false;
Expand Down
123 changes: 123 additions & 0 deletions src/commands/android/subcommands/uninstall/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import colors from 'ansi-colors';
import ADB from 'appium-adb';
import inquirer from 'inquirer';

import Logger from '../../../../logger';
import {symbols} from '../../../../utils';
import {Options, Platform} from '../../interfaces';
import {getBinaryLocation} from '../../utils/common';
import {execBinaryAsync, execBinarySync} from '../../utils/sdk';

export async function uninstallApp(options: Options, sdkRoot: string, platform: Platform): Promise<boolean> {
try {
const adbLocation = getBinaryLocation(sdkRoot, platform, 'adb', true);
if (!adbLocation) {
Logger.log(` ${colors.red(symbols().fail)} ${colors.cyan('adb')} binary not found.\n`);
Logger.log(`Run: ${colors.cyan('npx @nightwatch/mobile-helper android --standalone')} to setup missing requirements.`);
Logger.log(`(Remove the ${colors.gray('--standalone')} flag from the above command if setting up for testing.)\n`);

return false;
}

const adb = await ADB.createADB({allowOfflineDevices: true});
const devices = await adb.getConnectedDevices();

if (!devices.length) {
Logger.log(`${colors.red('No device found running.')} Please connect the device to uninstall the APK.\n`);

return true;
} else if (devices.length === 1) {
// if only one device is connected, then set that device's id to options.deviceId
options.deviceId = devices[0].udid;
}

if (options.deviceId && devices.length > 1) {
// If device id is passed and there are multiple devices connected then
// check if the id is valid. If not then prompt user to select a device.
const device = devices.find(device => device.udid === options.deviceId);
if (!device) {
Logger.log(`${colors.yellow('Invalid device Id!')} Please select a valid running device.\n`);

options.deviceId = '';
}
}

if (!options.deviceId) {
// if device id not found, or invalid device id is found, then prompt the user
// to select a device from the list of running devices.
const deviceAnswer = await inquirer.prompt({
type: 'list',
name: 'device',
message: 'Select the device to uninstall the APK:',
choices: devices.map(device => device.udid)
});
options.deviceId = deviceAnswer.device;
}

const appNameAnswer = await inquirer.prompt({
type: 'input',
name: 'appName',
message: 'Enter the name of the App to uninstall:'
});

const packageNames = execBinarySync(adbLocation, 'adb', platform, `-s ${options.deviceId} shell pm list packages '${appNameAnswer.appName}'`);
if (!packageNames) {
Logger.log();
Logger.log(`${colors.red('App not found!')} Please try again.\n`);

return false;
}

const packagesList: string[] = [];
// Name of a package is in the format 'package:com.example.app'
packageNames.split('\n').forEach(line => {
if (line.includes('package:')) {
packagesList.push(line.split(':')[1].trim());
}
});

let packageName = packagesList[0];

if (packagesList.length > 1) {
const packageNameAnswer = await inquirer.prompt({
type: 'list',
name: 'packageName',
message: 'Select the package you want to uninstall:',
choices: packagesList
});

packageName = packageNameAnswer.packageName;
}

const UninstallationAnswer = await inquirer.prompt({
type: 'confirm',
name: 'confirm',
message: `Are you sure you want to uninstall ${colors.cyan(packageName)}`
});

Logger.log();

if (!UninstallationAnswer.confirm) {
Logger.log('Uninstallation cancelled.\n');

return false;
}

Logger.log(`Uninstalling ${colors.cyan(packageName)}...\n`);

const uninstallationStatus = await execBinaryAsync(adbLocation, 'adb', platform, `-s ${options.deviceId} uninstall ${packageName}`);
if (uninstallationStatus?.includes('Success')) {
Logger.log(`${colors.green('App uninstalled successfully!')}\n`);

return true;
}

return false;
} catch (error) {
Logger.log(colors.red('Error occured while uninstalling App.'));
console.error(error);

return false;
}
}

10 changes: 10 additions & 0 deletions src/commands/android/subcommands/uninstall/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Options, Platform} from '../../interfaces';
import {uninstallApp} from './app';

export async function uninstall(options: Options, sdkRoot: string, platform: Platform): Promise<boolean> {
if (options.app) {
return await uninstallApp(options, sdkRoot, platform);
}

return false;
}

0 comments on commit e47986a

Please sign in to comment.