Overview
APK Extractor provides powerful application extraction capabilities, displaying real application names (not just package names), detecting APK formats, calculating exact file sizes, and enabling filtering and searching across all installed apps.
Real Application Names
Instead of showing cryptic package names like com.whatsapp, APK Extractor displays the actual app name like WhatsApp .
The system uses multiple fallback methods to extract the real app name:
// Method 1: Check nonLocalizedLabel
let appName = null ;
const m = dump . match ( /nonLocalizedLabel= ( [ ^ \s\n\r ] + ) / );
if ( m && m [ 1 ] && m [ 1 ] !== 'null' ) appName = m [ 1 ]. replace ( /"/ g , '' );
// Method 2: Check label field
if ( ! appName ) {
const lm = dump . match ( /label=" ( [ ^ " ] + ) "/ );
if ( lm ) appName = lm [ 1 ];
}
// Method 3: Fallback to formatted package name
if ( ! appName ) {
const seg = pkg . split ( '.' ). pop () || pkg ;
appName = seg . charAt ( 0 ). toUpperCase () + seg . slice ( 1 ). replace ( / ( [ A-Z ] ) / g , ' $1' ). trim ();
}
The system queries dumpsys package for each app to extract the application label defined in its manifest.
APK Extractor automatically detects whether an app is a single APK or a Split APK (multiple files):
const pathOut = await tryRunAdb ( `shell pm path ${ pkg } ` , serial );
const paths = pathOut . split ( ' \n ' ). map ( l => l . replace ( 'package:' , '' ). trim ()). filter ( Boolean );
const isSplit = paths . length > 1 ;
const format = paths . length === 0 ? 'N/A' : isSplit ? 'Split APK' : 'APK' ;
APK Types
Format Description File Count Extraction Method APK Single file application 1 Direct download Split APK Multi-file application 2+ Compile to XAPK
Split APKs contain separate files for different CPU architectures, screen densities, and language resources. They must be compiled into XAPK format for installation.
Size Calculation
APK Extractor calculates exact file sizes in bytes using ADB’s stat command:
const sizes = await Promise . all ( paths . map ( async ( p ) => {
try {
const szOut = await runAdb ( `shell stat -c "%s" " ${ p } "` , serial , 5000 );
const sz = parseInt ( szOut . trim (), 10 );
return isNaN ( sz ) ? 0 : sz ;
} catch { return 0 ; }
}));
totalSizeBytes = sizes . reduce (( a , b ) => a + b , 0 );
const sizeMB = totalSizeBytes > 0 ? ( totalSizeBytes / 1048576 ). toFixed ( 1 ) + ' MB' : 'N/A' ;
Why stat Instead of du?
Precision : stat -c "%s" returns exact byte count
Speed : Faster than du -b for individual files
Reliability : Works on all Android versions
For Split APKs with multiple files, sizes are calculated in parallel and summed for total app size.
Filtering by Type
Filter apps by installation type:
const { type = 'user' } = req . query ;
const flag = type === 'user' ? '-3' : type === 'system' ? '-s' : '' ;
const out = await runAdb ( `shell pm list packages ${ flag } ` , serial , 30000 );
Filter Options
User Apps (-3): Apps installed by the user
System Apps (-s): Pre-installed system applications
All Apps : Both user and system apps
User Apps Only
System Apps Only
All Apps
adb shell pm list packages -3
Search Functionality
The web interface provides instant search across:
Application names (e.g., “WhatsApp”)
Package names (e.g., “com.whatsapp”)
Partial matches (e.g., “what” matches “WhatsApp”)
Search is client-side for instant results without server round-trips.
Batch Info Processing
To display app lists quickly, APK Extractor uses parallel batch processing:
app . post ( '/api/devices/:serial/apps/batch-info' , async ( req , res ) => {
const { serial } = req . params ;
const { packages } = req . body ;
// Process all packages in parallel
const entries = await Promise . all ( packages . map ( async ( pkg ) => {
try {
const [ pathOut , dump ] = await Promise . all ([
tryRunAdb ( `shell pm path ${ pkg } ` , serial ),
tryRunAdb ( `shell dumpsys package ${ pkg } ` , serial ),
]);
// Extract format, size, and name
// ...
return [ pkg , { format , isSplit , sizeMB , appName }];
} catch {
// Fallback for errors
}
}));
const results = Object . fromEntries ( entries );
res . json ({ results });
});
Batch Processing Benefits
100% Parallel : All packages processed simultaneously
No Blocking : Uses async/await throughout
Fast Display : Shows results as they arrive
Progress Tracking : UI displays “X / Y apps” during loading
Processing 100 apps takes approximately the same time as processing 10 apps due to parallel execution.
Direct Download to Browser
APK files stream directly to the browser without server-side storage:
app . post ( '/api/devices/:serial/apps/:package/extract' , async ( req , res ) => {
const { serial , package : pkg } = req . params ;
// Get APK path from device
const pathOut = await tryRunAdb ( `shell pm path ${ pkg } ` , serial );
const paths = pathOut . split ( ' \n ' ). map ( l => l . replace ( 'package:' , '' ). trim ()). filter ( Boolean );
// Only single APKs can be extracted directly
if ( paths . length > 1 ) {
return res . status ( 400 ). json ({
error: 'Split APK / XAPK detectado' ,
detail: `Esta app tiene ${ paths . length } archivos APK separados.` ,
isSplit: true
});
}
const devicePath = paths [ 0 ];
const outDir = path . join ( os . tmpdir (), 'apk-extractor' );
const outFile = path . join ( outDir , ` ${ pkg } .apk` );
// Pull APK from device
await runAdb ( `pull " ${ devicePath } " " ${ outFile } "` , serial , 60000 );
// Stream to browser
res . setHeader ( 'Content-Disposition' , `attachment; filename=" ${ pkg } .apk"` );
res . setHeader ( 'Content-Type' , 'application/vnd.android.package-archive' );
const stream = fs . createReadStream ( outFile );
stream . pipe ( res );
// Clean up after download
stream . on ( 'close' , () => { fs . unlinkSync ( outFile ); });
});
Download Security
Files saved to temp directory (os.tmpdir())
Automatically deleted after download completes
No permanent server-side storage
Direct browser download with proper MIME type
Application Info API
Get detailed information about any installed app:
GET / api / devices / : serial / apps / : package / info
Response:
{
"pkg" : "com.whatsapp" ,
"appName" : "WhatsApp" ,
"versionName" : "2.23.5.76" ,
"versionCode" : "223576" ,
"firstInstall" : "2023-01-15 10:30:45" ,
"lastUpdate" : "2023-03-20 14:22:10" ,
"installer" : "com.android.vending" ,
"apkPaths" : [ "/data/app/com.whatsapp-xyz/base.apk" ],
"isSplit" : false ,
"format" : "APK" ,
"sizeMB" : "58.3 MB" ,
"sizeBytes" : 61145088
}
Caching
Package list cached after first load
Batch info cached per device
Switching filters (user/system) shows instant cached results
Async Operations
Zero blocking operations
All ADB calls use async/await
Parallel processing for multiple apps
Responsive UI during long operations
Error Handling
try {
// Attempt extraction
} catch {
// Graceful fallback
const seg = pkg . split ( '.' ). pop () || pkg ;
return [ pkg , {
format: 'N/A' ,
isSplit: false ,
sizeMB: 'N/A' ,
appName: seg . charAt ( 0 ). toUpperCase () + seg . slice ( 1 ),
}];
}
If any app info extraction fails, the system provides sensible defaults to keep the list functioning.