CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web-ext

A command line tool to help build, run, and test web extensions

Pending
Overview
Eval results
Files

android-development.mddocs/

Android Development

ADB integration for developing and testing extensions on Firefox for Android devices. Provides device management, file transfer, APK handling, and remote debugging capabilities.

Capabilities

ADB Utilities Class

Comprehensive Android Debug Bridge integration for Firefox extension development on mobile devices.

class ADBUtils {
  constructor(params: ADBParams);
  /** Discover connected Android devices */
  discoverDevices(): Promise<string[]>;
  /** Get current user ID on device */
  getCurrentUser(deviceId: string): Promise<string>;
  /** Execute shell command on device */
  runShellCommand(deviceId: string, cmd: string): Promise<string>;
  /** Find installed Firefox APKs on device */
  discoverInstalledFirefoxAPKs(deviceId: string, firefoxApk?: string): Promise<string[]>;
  /** Force stop an APK on device */
  amForceStopAPK(deviceId: string, apk: string): Promise<void>;
  /** Create or get artifacts directory on device */
  getOrCreateArtifactsDir(deviceId: string): Promise<string>;
  /** Detect or remove old artifacts from device */
  detectOrRemoveOldArtifacts(deviceId: string, removeArtifactDirs?: boolean): Promise<string[]>;
  /** Clear artifacts directory on device */
  clearArtifactsDir(deviceId: string): Promise<void>;
  /** Upload file from computer to device */
  pushFile(deviceId: string, localPath: string, devicePath: string): Promise<void>;
  /** Launch Firefox APK with extension */
  startFirefoxAPK(deviceId: string, apk: string, apkComponent?: string, deviceProfileDir?: string): Promise<void>;
  /** Control discovery abort mechanism */
  setUserAbortDiscovery(value: boolean): void;
  /** Discover remote debugging Unix socket */
  discoverRDPUnixSocket(deviceId: string, apk: string, options?: DiscoveryOptions): Promise<string>;
  /** Set up ADB port forwarding */
  setupForward(deviceId: string, remote: string, local: string): Promise<void>;
}

interface ADBParams {
  /** Path to adb binary */
  adbBin?: string;
  /** ADB host to connect to */
  adbHost?: string;
  /** ADB port number */
  adbPort?: string;
  /** Target device ID */
  adbDevice?: string;
  /** Discovery timeout in milliseconds */
  adbDiscoveryTimeout?: number;
  /** Enable verbose logging */
  verbose?: boolean;
}

interface DiscoveryOptions {
  /** Maximum retry attempts */
  maxTries?: number;
  /** Retry delay in milliseconds */
  retryInterval?: number;
}

Usage Examples:

import { ADBUtils } from "web-ext/util/adb";

// Initialize ADB utilities
const adb = new ADBUtils({
  adbBin: '/usr/local/bin/adb',
  adbDevice: 'emulator-5554',
  adbDiscoveryTimeout: 30000
});

// Discover and connect to devices
const devices = await adb.discoverDevices();
console.log('Found devices:', devices);

// Upload extension to device
await adb.pushFile('emulator-5554', './extension.xpi', '/data/local/tmp/extension.xpi');

// Start Firefox with extension
await adb.startFirefoxAPK('emulator-5554', 'org.mozilla.fenix');

Device Discovery Functions

Standalone functions for device and APK discovery without class instantiation.

/**
 * List all connected ADB devices
 * @param adbBin - Path to adb binary
 * @returns Promise resolving to array of device IDs
 */
function listADBDevices(adbBin?: string): Promise<string[]>;

/**
 * List Firefox APKs installed on a device
 * @param deviceId - Target device identifier
 * @param adbBin - Path to adb binary
 * @returns Promise resolving to array of APK package names
 */
function listADBFirefoxAPKs(deviceId: string, adbBin?: string): Promise<string[]>;

Usage Examples:

import { listADBDevices, listADBFirefoxAPKs } from "web-ext/util/adb";

// Quick device discovery
const devices = await listADBDevices();
if (devices.length === 0) {
  console.log('No Android devices found');
  return;
}

// Find Firefox installations
const firefoxApks = await listADBFirefoxAPKs(devices[0]);
console.log('Firefox APKs:', firefoxApks);
// Output: ['org.mozilla.firefox', 'org.mozilla.fenix', 'org.mozilla.firefox_beta']

Device Path Management

Constants and utilities for managing file paths on Android devices.

/** Base directory for temporary files on Android device */
const DEVICE_DIR_BASE: string = "/data/local/tmp/";

/** Prefix for web-ext artifact directories */
const ARTIFACTS_DIR_PREFIX: string = "web-ext-artifacts-";

Remote Debugging Integration

Set up remote debugging connections for Firefox Android extensions.

/**
 * Discover and connect to Firefox remote debugging socket
 * @param deviceId - Target Android device
 * @param apk - Firefox APK package name
 * @param options - Discovery configuration
 * @returns Promise resolving to Unix socket path
 */
async function discoverRDPUnixSocket(
  deviceId: string, 
  apk: string, 
  options?: DiscoveryOptions
): Promise<string>;

/**
 * Set up port forwarding for remote debugging
 * @param deviceId - Target device
 * @param remote - Remote socket/port on device
 * @param local - Local port on development machine
 * @returns Promise that resolves when forwarding is established
 */
async function setupForward(
  deviceId: string, 
  remote: string, 
  local: string
): Promise<void>;

Usage Example:

// Set up remote debugging
const socket = await adb.discoverRDPUnixSocket('emulator-5554', 'org.mozilla.fenix', {
  maxTries: 10,
  retryInterval: 1000
});

// Forward remote debugging port
await adb.setupForward('emulator-5554', socket, '6000');
console.log('Remote debugging available at localhost:6000');

File Transfer Operations

Manage files and directories on Android devices.

/**
 * Upload file from local system to Android device
 * @param deviceId - Target device
 * @param localPath - Source file path on computer
 * @param devicePath - Destination path on device
 * @returns Promise that resolves when transfer completes
 */
async function pushFile(
  deviceId: string, 
  localPath: string, 
  devicePath: string
): Promise<void>;

/**
 * Create artifacts directory on device
 * @param deviceId - Target device
 * @returns Promise resolving to created directory path
 */
async function getOrCreateArtifactsDir(deviceId: string): Promise<string>;

/**
 * Clean up old artifact directories
 * @param deviceId - Target device
 * @param removeArtifactDirs - Whether to remove old directories
 * @returns Promise resolving to list of old directories
 */
async function detectOrRemoveOldArtifacts(
  deviceId: string, 
  removeArtifactDirs?: boolean
): Promise<string[]>;

APK Management

Handle Firefox APK operations on Android devices.

/**
 * Force stop a running APK
 * @param deviceId - Target device
 * @param apk - APK package name to stop
 * @returns Promise that resolves when APK is stopped
 */
async function amForceStopAPK(deviceId: string, apk: string): Promise<void>;

/**
 * Launch Firefox APK with optional extension
 * @param deviceId - Target device
 * @param apk - Firefox APK package name
 * @param apkComponent - Specific APK component (optional)
 * @param deviceProfileDir - Profile directory on device (optional)
 * @returns Promise that resolves when APK is started
 */
async function startFirefoxAPK(
  deviceId: string, 
  apk: string, 
  apkComponent?: string, 
  deviceProfileDir?: string
): Promise<void>;

Firefox APK Examples:

  • org.mozilla.firefox - Firefox Release
  • org.mozilla.firefox_beta - Firefox Beta
  • org.mozilla.fenix - Firefox Nightly
  • org.mozilla.fenix.nightly - Firefox Nightly (alternative)
  • org.mozilla.fennec_aurora - Firefox Developer Edition (legacy)

Shell Command Execution

Execute arbitrary shell commands on Android devices.

/**
 * Execute shell command on Android device
 * @param deviceId - Target device identifier
 * @param cmd - Shell command to execute
 * @returns Promise resolving to command output
 */
async function runShellCommand(deviceId: string, cmd: string): Promise<string>;

/**
 * Get current user ID on Android device
 * @param deviceId - Target device
 * @returns Promise resolving to user ID string
 */
async function getCurrentUser(deviceId: string): Promise<string>;

Usage Examples:

// Check device storage
const storage = await adb.runShellCommand('emulator-5554', 'df -h');
console.log('Device storage:', storage);

// Get device info
const userInfo = await adb.getCurrentUser('emulator-5554');
console.log('Current user:', userInfo);

// Check running processes
const processes = await adb.runShellCommand('emulator-5554', 'ps | grep firefox');
console.log('Firefox processes:', processes);

Error Handling and Troubleshooting

Common error scenarios and solutions:

interface ADBError extends Error {
  /** ADB-specific error code */
  code: string;
  /** Device ID where error occurred */
  deviceId?: string;
  /** ADB command that failed */
  command?: string;
}

Common Error Codes:

  • DEVICE_NOT_FOUND - Device not connected or not recognized
  • ADB_NOT_FOUND - ADB binary not found in PATH
  • PERMISSION_DENIED - Insufficient permissions for device access
  • TIMEOUT - Operation timed out
  • APK_NOT_FOUND - Firefox APK not installed on device
  • CONNECTION_FAILED - Cannot establish ADB connection

Usage Example with Error Handling:

try {
  const adb = new ADBUtils({
    adbDevice: 'emulator-5554',
    adbDiscoveryTimeout: 30000
  });
  
  const devices = await adb.discoverDevices();
  if (devices.length === 0) {
    throw new Error('No Android devices found. Please connect a device or start an emulator.');
  }
  
  await adb.startFirefoxAPK(devices[0], 'org.mozilla.fenix');
  console.log('Firefox started successfully on device');
  
} catch (error) {
  if (error.code === 'DEVICE_NOT_FOUND') {
    console.error('Device not found. Check USB debugging is enabled.');
  } else if (error.code === 'APK_NOT_FOUND') {
    console.error('Firefox not installed. Install Firefox from Play Store or APK.');
  } else {
    console.error('ADB operation failed:', error.message);
  }
}

Integration with Extension Runners

ADB utilities integrate seamlessly with web-ext's extension runner system:

// Android-specific run parameters
await cmd.run({
  sourceDir: './extension',
  target: ['firefox-android'],
  adbDevice: 'emulator-5554',
  firefoxApk: 'org.mozilla.fenix',
  adbRemoveOldArtifacts: true
});

This automatically uses ADBUtils internally to:

  1. Discover the specified device
  2. Install the extension
  3. Start Firefox with the extension loaded
  4. Set up remote debugging connection
  5. Enable hot reloading for development

Install with Tessl CLI

npx tessl i tessl/npm-web-ext

docs

android-development.md

build-system.md

extension-runners.md

index.md

linting-system.md

logging-system.md

main-api.md

signing-publishing.md

tile.json