Skip to content

Resources

Resource table parser for resolving string, drawable, and other resource values.

Overview

The Resources class parses the resources.arsc file and provides resource resolution with locale support.

typescript
import { Apk } from "node-apk";

const apk = new Apk("app.apk");
const resources = await apk.getResources();

Methods

resolve()

typescript
resolve(id: number): Resource[]

Resolves a resource ID to its values across all configurations.

Parameters

ParameterTypeDescription
idnumberAndroid resource ID

Returns

Resource[] - Array of resources with values and locales.

Example

typescript
const resources = await apk.getResources();

// Resolve a string resource
const labelId = 0x7f040001;
const resolved = resources.resolve(labelId);

for (const res of resolved) {
  console.log(`Value: ${res.value}`);
  if (res.locale) {
    console.log(`  Language: ${res.locale.language}`);
    console.log(`  Country: ${res.locale.country}`);
  }
}

Resource Class

Represents a single resolved resource value.

Properties

typescript
class Resource {
  readonly value: ResourceValue;
  readonly locale?: Locale;
}

ResourceValue

typescript
type ResourceValue = number | string | boolean | null;

Locale Class

typescript
class Locale {
  readonly language?: string;  // Two-letter language code (e.g., "en")
  readonly country?: string;   // Two-letter country code (e.g., "US")
}

Example

typescript
const resources = await apk.getResources();
const resolved = resources.resolve(0x7f040001);

for (const res of resolved) {
  // Access the value
  console.log(`Value: ${res.value}`);
  
  // Check type
  if (typeof res.value === "string") {
    console.log(`String: ${res.value.toUpperCase()}`);
  }
  
  // Access locale
  if (res.locale) {
    const lang = res.locale.language ?? "unknown";
    const country = res.locale.country ?? "";
    console.log(`Locale: ${lang}${country ? `-${country}` : ""}`);
  }
}

Resource ID Format

Android resource IDs are 32-bit integers with this format:

0xPPTTIIII
│ │ └───── Index (16 bits) - Resource index within type
│ └─────── Type (8 bits) - Resource type (string, drawable, etc.)
└───────── Package (8 bits) - Package ID (0x7f for app resources)

Common Type IDs

TypeIDDescription
anim0x01Animation resources
color0x02Color values
drawable0x03Drawables
layout0x04Layout files
string0x05String resources
style0x06Style resources

Examples

Resolve App Label

typescript
const apk = new Apk("app.apk");
const manifest = await apk.getManifestInfo();
const resources = await apk.getResources();

const labelId = manifest.applicationLabel;

if (typeof labelId === "number") {
  const resolved = resources.resolve(labelId);
  
  // Get default value
  const defaultLabel = resolved[0]?.value;
  console.log(`App Name: ${defaultLabel}`);
  
  // Get specific locale
  const frenchLabel = resolved.find(r => r.locale?.language === "fr");
  if (frenchLabel) {
    console.log(`French: ${frenchLabel.value}`);
  }
}

Find All Localized Strings

typescript
function getLocalizedString(
  resources: Resources, 
  id: number, 
  locale: string
): string | undefined {
  const resolved = resources.resolve(id);
  
  // Try exact match (language + country)
  const exact = resolved.find(r => 
    r.locale?.language === locale.split("-")[0] &&
    r.locale?.country === locale.split("-")[1]
  );
  if (exact?.value) return String(exact.value);
  
  // Try language only
  const langOnly = resolved.find(r => 
    r.locale?.language === locale.split("-")[0]
  );
  if (langOnly?.value) return String(langOnly.value);
  
  // Fallback to default
  return resolved[0]?.value ? String(resolved[0].value) : undefined;
}

// Usage
const label = getLocalizedString(resources, labelId, "fr-FR");

Extract All Icon Variants

typescript
const manifest = await apk.getManifestInfo();
const resources = await apk.getResources();

const iconId = manifest.applicationIcon;
const iconResources = resources.resolve(iconId);

console.log("Available icon variants:");
for (const res of iconResources) {
  if (typeof res.value === "number") {
    // Further resolution needed
    console.log(`  Resource ID: 0x${res.value.toString(16)}`);
  } else if (typeof res.value === "string") {
    // File path
    console.log(`  Path: ${res.value}`);
  }
}

Build Locale Map

typescript
function buildLocaleMap(
  resources: Resources, 
  id: number
): Map<string, string> {
  const resolved = resources.resolve(id);
  const map = new Map<string, string>();
  
  for (const res of resolved) {
    if (typeof res.value === "string") {
      const locale = res.locale?.language ?? "default";
      map.set(locale, res.value);
    }
  }
  
  return map;
}

// Usage
const labels = buildLocaleMap(resources, labelId);
console.log("English:", labels.get("en"));
console.log("French:", labels.get("fr"));
console.log("German:", labels.get("de"));

Released under the MIT License.