GET /api/devices/:serial/apps
List installed applications on a device. Supports filtering by app type.
Path Parameters
Query Parameters
Filter apps by type:
user - User-installed apps only (default)
system - System apps only
all - All apps
Response
Array of package names (e.g., com.example.app), sorted alphabetically
Total number of packages returned
Example Request
curl "http://localhost:3000/api/devices/ABC123/apps?type=user"
const serial = 'ABC123' ;
const type = 'user' ;
const response = await fetch (
`http://localhost:3000/api/devices/ ${ serial } /apps?type= ${ type } `
);
const data = await response . json ();
Example Response
{
"packages" : [
"com.android.chrome" ,
"com.example.myapp" ,
"com.spotify.music"
],
"total" : 3
}
POST /api/devices/:serial/apps/batch-info
Get lightweight information for multiple apps in a single request. All packages are processed in parallel for optimal performance.
Path Parameters
Request Body
Array of package names to fetch info for
Response
Object mapping package names to app info objects App format: "APK", "Split APK", or "N/A"
Whether this is a split APK (requires XAPK compilation)
Total size in MB (e.g., "15.3 MB") or "N/A"
Example Request
curl -X POST http://localhost:3000/api/devices/ABC123/apps/batch-info \
-H "Content-Type: application/json" \
-d '{"packages": ["com.android.chrome", "com.spotify.music"]}'
const response = await fetch (
'http://localhost:3000/api/devices/ABC123/apps/batch-info' ,
{
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
packages: [ 'com.android.chrome' , 'com.spotify.music' ]
})
}
);
const data = await response . json ();
Example Response
{
"results" : {
"com.android.chrome" : {
"format" : "APK" ,
"isSplit" : false ,
"sizeMB" : "125.4 MB" ,
"appName" : "Chrome"
},
"com.spotify.music" : {
"format" : "Split APK" ,
"isSplit" : true ,
"sizeMB" : "87.2 MB" ,
"appName" : "Spotify"
}
}
}
GET /api/devices/:serial/apps/:package/info
Get detailed information about a specific app including version, install dates, and file paths.
Path Parameters
Package name (e.g., com.example.app)
Response
Version name (e.g., "1.2.3")
Installer package name (e.g., "com.android.vending" for Play Store)
Array of APK file paths on the device
Whether this is a split APK
"APK", "Split APK", or "N/A"
Example Request
curl http://localhost:3000/api/devices/ABC123/apps/com.android.chrome/info
const serial = 'ABC123' ;
const pkg = 'com.android.chrome' ;
const response = await fetch (
`http://localhost:3000/api/devices/ ${ serial } /apps/ ${ pkg } /info`
);
const data = await response . json ();
Example Response
{
"pkg" : "com.android.chrome" ,
"appName" : "Chrome" ,
"versionName" : "120.0.6099.144" ,
"versionCode" : "609914400" ,
"firstInstall" : "2024-01-15 10:23:45" ,
"lastUpdate" : "2024-02-20 14:30:12" ,
"installer" : "com.android.vending" ,
"apkPaths" : [
"/data/app/~~abc123==/com.android.chrome-xyz456==/base.apk"
],
"isSplit" : false ,
"format" : "APK" ,
"sizeMB" : "125.4 MB" ,
"sizeBytes" : 131534848
}
Extract a single APK file from the device. This endpoint returns the APK file directly for download.
This endpoint only works for standard APK files. Split APKs will return an error - use the XAPK compilation endpoints instead.
Path Parameters
Response
On success, returns the APK file with:
Content-Type: application/vnd.android.package-archive
Content-Disposition: attachment; filename="{package}.apk"
Binary APK file data
Error Response (Split APK)
Returns 400 if the app is a split APK:
{
"error" : "Split APK / XAPK detectado" ,
"detail" : "Esta app tiene 5 archivos APK separados y no puede exportarse como un único .apk." ,
"paths" : [
"/data/app/.../base.apk" ,
"/data/app/.../split_config.arm64_v8a.apk" ,
"/data/app/.../split_config.en.apk"
],
"isSplit" : true
}
Example Request
curl -O -J http://localhost:3000/api/devices/ABC123/apps/com.example.app/extract
const serial = 'ABC123' ;
const pkg = 'com.example.app' ;
const response = await fetch (
`http://localhost:3000/api/devices/ ${ serial } /apps/ ${ pkg } /extract` ,
{ method: 'POST' }
);
if ( response . ok ) {
const blob = await response . blob ();
const url = window . URL . createObjectURL ( blob );
const a = document . createElement ( 'a' );
a . href = url ;
a . download = ` ${ pkg } .apk` ;
a . click ();
}
GET /api/devices/:serial/apps/:package/compile-xapk
Compile a split APK into an XAPK file with real-time progress updates via Server-Sent Events.
Use this endpoint for apps with multiple APK files (Split APKs). Standard APKs should use the extract endpoint instead.
Path Parameters
Server-Sent Events stream with Content-Type: text/event-stream.
Progress percentage (0-100)
Whether compilation is complete
Success status (only when done: true)
Whether the XAPK file is ready for download
File size in bytes (only when fileReady: true)
Error message if compilation failed
Progress Steps
5% - Getting APK paths from device
10% - Extracting APK files in parallel
10-60% - Pulling individual APK files
65% - Getting package information
70% - Creating manifest.json
80% - Packaging XAPK
95% - XAPK ready for download
Example Request
const serial = 'ABC123' ;
const pkg = 'com.spotify.music' ;
const eventSource = new EventSource (
`http://localhost:3000/api/devices/ ${ serial } /apps/ ${ pkg } /compile-xapk`
);
eventSource . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
console . log ( ` ${ data . progress } %: ${ data . msg } ` );
if ( data . done ) {
eventSource . close ();
if ( data . ok && data . fileReady ) {
// XAPK is ready - download it
window . location . href =
`http://localhost:3000/api/devices/ ${ serial } /apps/ ${ pkg } /download-xapk` ;
} else {
console . error ( 'Compilation failed:' , data . err );
}
}
};
Example Response Stream
data: {"msg":"Obteniendo rutas del APK en el dispositivo...","progress":5}
data: {"msg":"Encontrados 5 archivos APK. Extrayendo en paralelo...","progress":10}
data: {"msg":"Extraído 1/5: base.apk","progress":20}
data: {"msg":"Extraído 5/5: split_config.xxhdpi.apk","progress":60}
data: {"msg":"Obteniendo información del paquete...","progress":65}
data: {"msg":"Creando manifest.json...","progress":70}
data: {"msg":"Empaquetando XAPK...","progress":80}
data: {"msg":"XAPK listo. Descargando...","progress":95}
data: {"done":true,"ok":true,"fileReady":true,"size":91234567}
Error Response
If the app is not a split APK:
data: {"done":true,"ok":false,"xapkPath":null,"err":"Esta app no es un Split APK. Usa 'Extraer APK' en su lugar."}
GET /api/devices/:serial/apps/:package/download-xapk
Download the compiled XAPK file. Must be called after successful compilation via /compile-xapk.
Path Parameters
Response
On success, returns the XAPK file with:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="{package}.xapk"
Binary XAPK file data
The XAPK file is automatically deleted from the server after download.
Error Response
Returns 404 if the XAPK file doesn’t exist:
{
"error" : "XAPK no encontrado. Vuelve a compilar."
}
Example Request
curl -O -J http://localhost:3000/api/devices/ABC123/apps/com.spotify.music/download-xapk
const serial = 'ABC123' ;
const pkg = 'com.spotify.music' ;
// After compilation is complete
const response = await fetch (
`http://localhost:3000/api/devices/ ${ serial } /apps/ ${ pkg } /download-xapk`
);
if ( response . ok ) {
const blob = await response . blob ();
const url = window . URL . createObjectURL ( blob );
const a = document . createElement ( 'a' );
a . href = url ;
a . download = ` ${ pkg } .xapk` ;
a . click ();
}
The XAPK file is a ZIP archive containing:
manifest.json - Package metadata (version, SDK levels, etc.)
base.apk - Base APK file
split_*.apk - Split APK files (architecture, language, DPI configs)
Example manifest.json:
{
"xapk_version" : 2 ,
"package_name" : "com.spotify.music" ,
"name" : "com.spotify.music" ,
"version_code" : "87201233" ,
"version_name" : "8.7.20.1233" ,
"min_sdk_version" : "21" ,
"target_sdk_version" : "34" ,
"split_apks" : [
{ "file" : "base.apk" , "id" : "base" },
{ "file" : "split_config.arm64_v8a.apk" , "id" : "split_config.arm64_v8a" },
{ "file" : "split_config.en.apk" , "id" : "split_config.en" }
],
"expansions" : []
}