Formatos y extensiones: qué es este fichero
Antes conviene leer «Anatomía de un APK»
1. El problema
Alguien te pasa un fichero para que mires qué hace una aplicación. Se llama
com.whatsapp.apks. Ni es un APK ni es lo que bundletool llama un APK Set: es un .xapk
de APKCombo al que le cambiaron la extensión, y dentro hay catorce APK distintos de los
cuales solo uno lleva el código.
Esto no es una anécdota. De los dieciséis ficheros con extensión .apks del «muestrario»,
catorce son otra cosa. La «sección 5 · La extensión miente, y está medido» lo mide.
El lío tiene una causa concreta y bastante aburrida. Hasta 2018 una aplicación de Android era
un fichero y ese fichero era un APK. Con el Android App Bundle, Google Play dejó de servir
un fichero y pasó a servir un conjunto —un base.apk más los split que le tocan a ese
teléfono—, pero no publicó ningún formato estándar para meter ese conjunto en algo que se
pueda descargar. Así que cada sitio de descargas se inventó el suyo. APKMirror hizo el
.apkm, APKCombo y APKPure hicieron el .xapk, y la aplicación Split APKs Installer se
limitó a comprimir los APK en un ZIP sin más.
Ninguno de esos tres formatos está especificado en ninguna parte. Los tres son ZIP. Los tres
se llaman de forma distinta según quién los exporte. Y encima conviven con los formatos que
Google sí especifica: el .aab que sube el desarrollador y el .apks que produce
bundletool.
Este documento responde a una sola pregunta —¿qué es este fichero y qué puedo hacer con
él?— y remite al resto para el detalle. Para la estructura interna del AAB, del APK Set y
de la taxonomía de split, ver
«AAB, splits y contenedores»; para el ZIP que hay debajo de
todos ellos, «Contenedor ZIP».
2. Tabla maestra
Todo lo que sigue es un ZIP, sin excepción. Lo que cambia es qué hay dentro y quién lo puso ahí.
| Extensión | Qué es de verdad | Quién lo produce | ¿Se instala tal cual? | Especificado |
|---|---|---|---|---|
.apk |
Una aplicación completa, o un split suelto |
El compilador de Android, Play, cualquiera | Sí, si es completo o si van todos sus split |
Sí, de facto |
.aab |
El material intermedio del que Play deriva los APK. No es instalable |
El desarrollador, con Gradle | No, en ningún caso | Sí, documentado por Google |
.apks |
Un ZIP con todos los APK que Play podría generar, más toc.pb |
bundletool build-apks |
Solo mediante bundletool install-apks |
Sí, vía bundletool |
.xapk |
ZIP plano con el base y sus split, más manifest.json |
APKCombo, APKPure | No. Necesita un instalador de split |
No |
.apkm |
Como el anterior, más info.json y firma propia del ZIP |
APKMirror | No. Necesita su instalador | No |
.zip (SAI) |
ZIP plano, solo APK, sin metadatos |
Split APKs Installer, o cualquiera | No | No |
.obb |
Datos de expansión que viajan fuera del APK. Obsoleto |
El desarrollador, antes de 2021 | No. Es un fichero de datos | Sí, documentado |
Cinco cosas que conviene fijar antes de seguir:
- Ninguna de estas extensiones es obligatoria. Ni siquiera
.apk: Android identifica el paquete por su contenido, no por su nombre. .aabes el único que no contiene ningúnAPK. Es la excepción real de la lista: lo que lleva dentro son.dexsueltos y una tabla de recursos en protobuf, no paquetes..apkses el nombre más sobrecargado del ecosistema. La «sección 3.3 · .apks — cuatro cosas distintas con el mismo nombre» enumera las cuatro cosas distintas que se llaman así.- El
.apkmes el único que lleva su propia firma. Y esa firma es de APKMirror sobre el envoltorio, no de la aplicación. Confundirlas es un error de análisis frecuente. - Que la extensión no coincida con el contenido no es un caso raro: es lo normal. En el
muestrario, catorce de los dieciséis ficheros
.apksson.xapkrenombrados. La «sección 5 · La extensión miente, y está medido» lo mide y la 4 explica cómo salir de dudas sin descomprimir nada.
3. Los formatos, uno a uno
3.1 .apk — y la trampa de que un split también lo es
Un APK es un ZIP con AndroidManifest.xml y, casi siempre, resources.arsc en la raíz.
Eso es todo lo que hace falta para reconocerlo.
Lo que no se ve a simple vista es que un split es también un .apk, y no se instala
solo. Un config.es.apk de 300 KB tiene manifiesto, tiene extensión .apk y no tiene
código: es un cuarto de aplicación. La diferencia está en un atributo del manifiesto:
BT=~/Library/Android/sdk/build-tools/37.0.0
$BT/aapt2 dump badging config.es.apk | head -1
package: name='com.google.android.keep' versionCode='220671357' versionName='' split='config.es'
split='config.es' y versionName vacío. Un base.apk no trae ni lo uno ni lo otro. La
taxonomía completa —config splits, feature modules y las combinaciones de los dos— está en la
«sección 4 de AAB, splits y contenedores · Taxonomía de splits».
Intentar instalar solo el base de una aplicación que espera split da un error que vale la
pena reconocer de vista, porque es el más frecuente de todos:
adb install com.google.android.keep.apk
Performing Streamed Install
adb: failed to install com.google.android.keep.apk: Failure [INSTALL_FAILED_MISSING_SPLIT: Missing split for com.google.android.keep]
Reproducido el 13 de agosto de 2026 sobre un emulador Android 14 arm64-v8a, con el
base.apk extraído de com.google.android.keep.apks del muestrario.
3.2 .aab — el que no se instala
El Android App Bundle es lo que el desarrollador sube a Play. Play no lo distribuye: lo
usa para generar los APK de cada dispositivo. Que llegue a manos de un analista es raro y
casi siempre significa que alguien se equivocó de fichero.
Tres señales lo delatan de inmediato, y las tres son diferencias con la estructura de un
APK:
- El manifiesto no está en la raíz sino en
base/manifest/AndroidManifest.xml. - Los
.dexno están en la raíz sino enbase/dex/. - No hay
resources.arsc. Hayresources.pb, que es protobuf y no tiene nada que ver.
Más un BundleConfig.pb en la raíz que ningún otro formato lleva.
La consecuencia práctica reparte a las herramientas en dos grupos, y no en el que uno
supondría. jadx lo abre sin más: encuentra los .dex en base/dex/ y hasta decodifica el
resources.pb. apktool no, y lo peor es cómo no lo hace —devuelve éxito y no extrae
nada—; la «sección 6.1 · jadx los abre todos, y apktool ninguno» lo mide. Y un lector de resources.arsc escrito para el formato binario
no sirve aquí en absoluto: protobuf no se le parece en nada.
Para instalarlo o para tratarlo como una aplicación, la vía es pasar antes por
bundletool build-apks, que produce el .apks de la sección siguiente, o por
--mode=universal si lo que se quiere es un APK único.
3.3 .apks — cuatro cosas distintas con el mismo nombre
Esta extensión es el desorden en estado puro. En el muestrario aparece designando cuatro cosas que no tienen nada que ver entre sí:
Lo que dice .apks |
Lo que es | Cómo se distingue |
|---|---|---|
APK Set de bundletool |
ZIP con toc.pb y los APK bajo splits/, standalones/, instant/… |
toc.pb en la raíz |
.xapk renombrado |
ZIP plano de APKCombo | manifest.json con la clave xapk_version |
| Exportación de SAI | ZIP plano con metadatos propios de la aplicación SAI | meta.sai_v1.json o meta.sai_v2.json en la raíz |
| ZIP plano sin más | Solo APK, sin metadatos de ningún tipo |
No queda ninguna otra evidencia |
El APK Set genuino es el único de los cuatro que está documentado. Lo produce
bundletool build-apks y su firma estructural es toc.pb, un protobuf
android.bundle.BuildApksResult que dice qué APK va a qué dispositivo. Su detalle está en
la «sección 3 de AAB, splits y contenedores · El APK Set (.apks)».
La exportación de SAI es la que menos se conoce y la que más fácilmente se clasifica mal.
Desde su versión 3.10, SAI añade a los .apks que exporta meta.sai_v1.json y el icono,
icon.png, en la raíz; desde la 4.0, también meta.sai_v2.json. El v2 lleva meta_version,
package, label, version_code, version_name, export_timestamp, split_apk, min_sdk,
target_sdk y un array backup_components. Es un contenedor autodescriptivo y
perfectamente utilizable, y un detector que no lo contemple lo tira al cajón de «zip plano» y
pierde todo eso.
El muestrario no contiene ningún .apks exportado por SAI, así que esta fila no es una medición
propia: sale del META-FORMAT.md del proyecto y del código que escribe esos ficheros,
ApksSingleBackupTaskExecutor.java (líneas 80-170 del último commit, 55505d2, SAI 4.5), que
los guarda sin comprimir y en este orden —meta.sai_v2.json, meta.sai_v1.json y, solo si
consigue extraer el icono, icon.png— antes de los APK. Lo que sí está medido es que
ninguno de los ficheros del muestrario lleva meta.sai_v*.json.
3.4 .xapk — APKCombo y APKPure
ZIP plano: el base y los config splits en la raíz, sin subdirectorios. Lo acompañan un
manifest.json, un icon.png y —en los de APKCombo— un APKComboInstaller.url.
La clave que identifica el formato sin ambigüedad es xapk_version. El resto del
manifest.json es sorprendentemente completo. De com.google.android.keep.apks del
muestrario, que es un .xapk con la extensión cambiada:
xapk_version 2
package_name com.google.android.keep
name Keep Notes
locales_name {'ar': 'Keep Notes', 'de': 'Keep Notes', 'en': 'Keep Notes', …}
version_code 220671357
version_name 5.26.321.01.97
min_sdk_version 32
target_sdk_version 37
permissions ['android.permission.ACCESS_NETWORK_STATE', …]
total_size 18144742
icon icon.png
split_apks [{'file': 'com.google.android.keep.apk', 'id': 'base'}, …]
split_apks es lo que lo hace valioso: dice el id de cada fichero sin necesidad de abrir
ninguno de los APK. Un inventario de un .xapk sale entero del manifest.json.
Dos detalles del nombrado que despistan: el base no se llama base.apk sino
<paquete>.apk, y los config splits se llaman config.<lo que sea>.apk sin el prefijo
split_. Justo al revés que en el .apkm.
Los .xapk de juegos pueden traer además los .obb de la «sección 3.7 · .obb — el heredado», en una entrada
Android/obb/….
3.5 .apkm — APKMirror
La misma idea que el .xapk con dos diferencias que importan.
La primera: firma su propio ZIP. Un .apkm trae META-INF/MANIFEST.MF,
META-INF/APKMIRRO.SF y META-INF/APKMIRRO.RSA en la raíz, que son una firma JAR clásica
(ver «Esquemas de firma») hecha por APKMirror sobre el
contenedor. Acredita de dónde salió la descarga y no tiene ninguna relación con la firma
de la aplicación, que está dentro del base.apk. Un verify que se confunda de nivel da un
veredicto sobre el envoltorio y lo presenta como si fuera de la aplicación.
La segunda: los nombres van al revés que en el .xapk. Aquí el base sí se llama
base.apk y los config splits llevan prefijo: split_config.arm64_v8a.apk.
Su metadato es info.json, con diecisiete claves. De tv.twitch.android.app.apkm del
muestrario:
apkm_version 5
apk_title Twitch: Live Streaming 26.2.4 (120-640dpi) (Android 8.0+)
app_name Twitch: Live Streaming
release_version 26.2.4
variant (universal) (120-640dpi) (Android 8.0+)
release_title Twitch: Live Streaming 26.2.4 (120-640dpi) (Android 8.0+)
versioncode 2602046
pname tv.twitch.android.app
post_date 2025-09-25 22:42:23
capabilities []
languages ['af', 'am', 'ar', 'as', 'az', 'be', 'bg', 'bn', …]
arches ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']
dpis ['120', '160', '213', '240', '320', '480', '640']
min_api 26
accent_color 9044ff
apk_id 10872180
release_id 10872182
apkm_version vale 5 en los ocho .apkm del muestrario y pname es el nombre del paquete.
El .url de la raíz también cambia: aquí es APKM_installer.url, y en el .xapk,
APKComboInstaller.url. Sirve como confirmación barata cuando el resto no basta.
3.6 El ZIP plano y SAI
El caso más simple y el que peor se identifica: un ZIP con los .apk dentro y nada más.
Sin metadatos, sin firma propia, sin ningún fichero que diga qué es.
El del muestrario es com.netflix.mediaclient.sai.zip, con 39 entradas y las 39 son
.apk. La ausencia total de ficheros descriptivos es literalmente lo único que lo define, y
por eso en el orden de detección de la «sección 4 · Cómo saber en diez segundos qué tienes delante» va el último de los contenedores: se llega a
él por descarte.
Conviene no confundir dos cosas que llevan el mismo nombre. SAI es una aplicación de
Android, un instalador de split que acepta .apks, .xapk, .apkm y ZIP planos; el ZIP
plano se llama «de SAI» por costumbre, porque es lo que SAI consume, no porque SAI lo genere
con esa forma. Lo que SAI exporta es un .apks con los metadatos de la «sección 3.3 · .apks — cuatro cosas distintas con el mismo nombre».
La lista de formatos de entrada no está en la documentación de SAI, pero sí en su código: el
selector de ficheros del instalador filtra por "zip", "apks", "xapk", "apk" y "apkm"
(InstallerXDialogFragment.java, línea 196, en el último commit, 55505d2), es decir, los
cuatro contenedores de esta sección más APK sueltos. Su README declara que el proyecto está
en mantenimiento mínimo («SAI is kinda dead cause I have no motivation for continuing its
development»), y el último commit de su rama principal es del 25 de febrero de 2021.
3.7 .obb — el heredado
Antes del AAB, la forma oficial de superar el límite de tamaño de Play eran los expansion
files: hasta dos ficheros de 2 GB que viajaban fuera del APK y se descargaban aparte.
El nombre sigue un patrón fijo:
[main|patch].<versionCode-de-la-primera-subida>.<nombre-del-paquete>.obb
Por ejemplo main.314159.com.example.app.obb. Se instalan en
<almacenamiento-compartido>/Android/obb/<paquete>/.
Están superados desde agosto de 2021, cuando Play empezó a exigir AAB para las aplicaciones
nuevas, pero siguen apareciendo en descargas de juegos antiguos, a veces dentro de un .xapk.
Un .obb no es un APK: es un contenedor de datos, normalmente un ZIP o un sistema de
ficheros propio del motor del juego.
El muestrario no contiene ninguno; esta sección sale de la documentación oficial, no de una medición.
3.8 Los que no son contenedores de aplicación
Aparecen en el mismo tipo de trabajo y conviene descartarlos rápido:
| Extensión | Qué es | Cómo se reconoce |
|---|---|---|
.dex |
Bytecode Dalvik suelto, fuera de un APK |
Magic dex\n035\0 (u otra versión) en el offset 0 |
.jar |
ZIP de .class de Java. A veces contiene un classes.dex |
.class dentro, o META-INF/MANIFEST.MF sin AndroidManifest.xml |
.odex, .vdex, .oat |
Artefactos que produce el dispositivo al instalar, no el desarrollador | Solo aparecen extraídos de un teléfono. Ver «Artefactos auxiliares» |
.idsig |
La firma v4, que viaja junto al APK y no dentro |
Ver «Firma v4» |
.apex |
Módulo actualizable del sistema, no una aplicación | apex_payload.img en la raíz |
4. Cómo saber en diez segundos qué tienes delante
Se mira el Central Directory del ZIP y ya está. No hace falta descomprimir nada: la
lista de nombres basta para decidir, y se lee en milisegundos por grande que sea el fichero.
unzip -Z1 fichero | head -20
Y se compara con esta tabla, en este orden:
| Nº | Si encuentras… | Entonces es… |
|---|---|---|
| 1 | toc.pb en la raíz |
APK Set genuino de bundletool |
| 2 | BundleConfig.pb y base/manifest/AndroidManifest.xml |
.aab |
| 3 | info.json y META-INF/*.RSA en la raíz |
.apkm de APKMirror |
| 4 | manifest.json con la clave xapk_version |
.xapk de APKCombo o APKPure |
| 5 | meta.sai_v1.json o meta.sai_v2.json |
.apks exportado por SAI |
| 6 | Varias entradas *.apk, ningún metadato y ningún AndroidManifest.xml en la raíz |
ZIP plano de split |
| 7 | AndroidManifest.xml en la raíz, con o sin resources.arsc (los split de ABI no lo llevan) |
APK suelto |
| 8 | Lo anterior más un atributo split en el manifiesto |
Un split, no una aplicación |
El orden no es un detalle de eficiencia, es lo que hace que la regla funcione. Las
evidencias se solapan: un .apkm tiene entradas *.apk en la raíz, así que también cumple la
regla 6; un APK Set las tiene bajo splits/. Un detector que empiece por la regla 6 clasifica
.apkm y APK Set como ZIP plano y pierde sus metadatos. Uno que empiece por la 7 no distingue
una aplicación de un split.
Sobre el .aab conviene una precisión: el orden que fija la «sección 6.2 de
AAB, splits y contenedores · El orden de precedencia» lo pone el último. Aquí va el
segundo, y da igual, porque BundleConfig.pb no coincide con ninguna otra evidencia de la
lista. Adelantarlo tiene la ventaja de que un .aab se descarta antes de intentar tratarlo
como un contenedor de APK, que es lo que no se puede hacer con él.
Comprobado sobre los tres formatos del muestrario:
cd ~/muestras-apk
unzip -Z1 splits/tv.twitch.android.app.apkm | grep -v '\.apk$'
META-INF/MANIFEST.MF
META-INF/APKMIRRO.SF
META-INF/APKMIRRO.RSA
info.json
icon.png
APKM_installer.url
unzip -Z1 splits/com.google.android.keep.apks | grep -v '\.apk$'
manifest.json
APKComboInstaller.url
icon.png
unzip -Z1 splits/com.netflix.mediaclient.sai.zip | grep -v '\.apk$'
El tercero no devuelve nada: 39 entradas y las 39 son .apk. Ese vacío es la evidencia.
5. La extensión miente, y está medido
No es una precaución teórica. Clasificando los 29 contenedores del muestrario por su estructura y comparándolo con lo que dice su nombre:
cd ~/muestras-apk
python3 - <<'PY'
import zipfile, json, glob, os
def detecta(z):
raiz = [x for x in z.namelist() if '/' not in x.rstrip('/')]
if 'toc.pb' in raiz: return 'APK Set'
if 'BundleConfig.pb' in raiz: return '.aab'
if 'info.json' in raiz and any(x.startswith('META-INF/') and x.endswith('.RSA')
for x in z.namelist()): return '.apkm'
if 'manifest.json' in raiz:
if 'xapk_version' in json.loads(z.read('manifest.json')): return '.xapk'
if 'AndroidManifest.xml' not in raiz and any(x.endswith('.apk') for x in z.namelist()):
return 'zip plano'
return '?'
cuenta = {}
for f in sorted(glob.glob('*.xapk') + glob.glob('splits/*')):
if f.endswith('.DS_Store'): continue
with zipfile.ZipFile(f) as z:
clave = (os.path.splitext(f)[1], detecta(z))
cuenta[clave] = cuenta.get(clave, 0) + 1
print(f" {'dice ser':<8} {'es':<10} {'n':>2}")
for (ext, det), n in sorted(cuenta.items()):
print(f' {ext:<8} -> {det:<10} {n:>2}')
PY
dice ser es n
.aab -> .aab 1
.apkm -> .apkm 8
.apks -> .xapk 14
.apks -> APK Set 2
.xapk -> .xapk 3
.zip -> zip plano 1
Catorce de los dieciséis .apks no son APK Set. Son .xapk de APKCombo con la extensión
cambiada, y lo confirma su manifest.json:
unzip -p splits/com.whatsapp.apks manifest.json | python3 -m json.tool | head -3
{
"xapk_version": "2",
"package_name": "com.whatsapp",
Los dos .apks que sí lo son —com.ejemplo.fixture.apks y
com.ejemplo.fixture-universal.apks— se generaron localmente con bundletool. Dicho de otra
forma: de los contenedores que llegaron de fuera, ninguno con extensión .apks era un APK
Set. Un análisis que se fíe del nombre acierta cero veces de catorce.
Los .apkm, los .xapk que sí se llaman .xapk y el ZIP de SAI se clasifican bien por
estructura, así que el problema no es que la detección sea difícil: es que la extensión es un
dato que aporta el sitio de descargas y no el formato.
Y cuando la estructura contradice a la extensión, lo correcto no es fallar: es continuar y dejarlo escrito en el informe. Un desajuste es información sobre la procedencia del fichero, no un error del fichero.
6. Qué se puede hacer con cada uno
La tabla que resuelve la pregunta práctica. Todo lo que sigue está ejecutado el 13 de
agosto de 2026 con bundletool 1.18.3, apktool 3.0.3, jadx 1.5.6, baksmali 3.0.7 y adb
1.0.41.
| Operación | .apk |
.aab |
.apks |
.xapk / .apkm / ZIP plano |
|---|---|---|---|---|
| Ver el manifiesto | aapt2 dump badging |
bundletool dump manifest --bundle |
Extraer el base primero | Extraer el base primero |
| Decompilar a Java | jadx -d out app.apk |
jadx lo abre |
jadx lo abre |
jadx lo abre |
Desensamblar a smali |
baksmali disassemble |
Extraer el DEX primero |
Extraer el base primero | Extraer el base primero |
| Decodificar recursos | apktool d |
bundletool dump resources --bundle |
Extraer el base primero | Extraer el base primero |
| Verificar la firma | apksigner verify |
No aplica | Sobre cada APK de dentro |
Sobre cada APK de dentro. No sobre el envoltorio |
| Instalar | adb install |
No | bundletool install-apks |
adb install-multiple, o un instalador de split |
Fusionar en un APK único |
No aplica | bundletool build-apks --mode=universal |
Requiere fusión de tablas | Requiere fusión de tablas |
6.1 jadx los abre todos, y apktool ninguno
Esta fila merece detalle porque contradice lo que se suele suponer, y porque las dos herramientas se comportan de forma opuesta ante la misma entrada.
jadx entra en cualquier contenedor sin que se lo pidan. Sobre el .aab del muestrario
encuentra el DEX donde está —en base/dex/, no en la raíz— y lo dice en el propio Java que
escribe:
/* JADX INFO: loaded from: base/dex/classes.dex */
public class MainActivity extends Activity {
Además decodifica el resources.pb en protobuf a un árbol res/values/ legible, que es
exactamente lo que un lector de resources.arsc no puede hacer. Y con los contenedores de
terceros no se queda corto: sobre el .xapk de la calculadora de Google escribe 3.468
ficheros .java, con código salido de varios split a la vez, y termina con código 3
por trece métodos que no pudo decompilar.
apktool hace lo contrario, y de la peor manera posible: no falla.
apktool d -f -o salida $MUESTRAS/splits/com.whatsapp.apks ; echo "EXIT=$?"
I: Using Apktool 3.0.3 on com.whatsapp.apks with 8 threads
I: Copying original files...
I: Copying unknown files...
EXIT=0
ls salida ; ls salida/unknown | head -4
apktool.yml
unknown
config.ldpi.apk
config.xxhdpi.apk
icon.png
manifest.json
Código de salida cero, ni un aviso, y cero smali. Lo único que ha hecho es copiar los
catorce APK sin abrir a un directorio llamado unknown/. Con un .aab pasa lo mismo: los
.pb y el AndroidManifest.xml del módulo acaban en unknown/ y el directorio smali/ ni
se crea.
Es el fallo silencioso en estado puro: una herramienta que devuelve éxito habiendo entendido nada. En un pipeline automatizado que compruebe el código de salida, esto pasa por bueno y el error solo aparece más tarde, cuando alguien busca una clase que nunca se extrajo.
6.2 Extraer el base
«Extraer el base primero» quiere decir literalmente eso, y con las herramientas de siempre:
unzip -j contenedor.apks 'com.whatsapp.apk' -d ./trabajo
Recordando el nombrado de la «sección 3.4 · .xapk — APKCombo y APKPure»: en un .xapk el base se llama <paquete>.apk, en
un .apkm y en un ZIP plano se llama base.apk.
Analizar solo el base no es lo mismo que analizar la aplicación. El código está casi
siempre entero ahí, pero las cadenas traducidas viven en los config.<idioma>.apk, las
bibliotecas nativas en los config.<abi>.apk y los módulos de funcionalidad pueden tener
DEX propio. Si el análisis busca una cadena o una biblioteca y no la encuentra, la primera
sospecha es que está en otro split.
Y sobre instalar el conjunto, dos errores que salen a la primera y conviene reconocer. Con
todos los split correctos:
adb install-multiple org.telegram.messenger.apk config.es.apk \
config.arm64_v8a.apk config.xxhdpi.apk
Success
Con un juego cuyo config.<abi> no corresponde a la arquitectura del dispositivo:
adb: failed to finalize session
Failure [INSTALL_FAILED_NO_MATCHING_ABIS: INSTALL_FAILED_NO_MATCHING_ABIS: Failed to extract native libraries, res=-113]
Ambos reproducidos el 13 de agosto de 2026 sobre un emulador Android 14 arm64-v8a. El
segundo salió al instalar los split de Google Keep del muestrario, que solo trae
config.armeabi_v7a. El catálogo completo de errores de instalación está en
«Diagnóstico de fallos».
Un detalle que solo se ve haciéndolo: el sistema renombra los split al instalarlos. Se
le pasa config.es.apk y en el dispositivo queda split_config.es.apk, porque el nombre lo
deriva del atributo split del manifiesto y no del fichero de entrada:
adb shell pm path org.telegram.messenger
package:/data/app/~~cB6DHo33I…==/org.telegram.messenger-F_5lfNc…==/base.apk
package:/data/app/~~cB6DHo33I…==/org.telegram.messenger-F_5lfNc…==/split_config.arm64_v8a.apk
package:/data/app/~~cB6DHo33I…==/org.telegram.messenger-F_5lfNc…==/split_config.es.apk
package:/data/app/~~cB6DHo33I…==/org.telegram.messenger-F_5lfNc…==/split_config.xxhdpi.apk
7. Árbol de decisión
Primero, qué es:
tengo un fichero
│
¿abre como ZIP?
┌──────────────┴──────────────┐
no sí
│ │
¿magic dex\n0NN? mirar el Central Directory
┌──────┴──────┐ y aplicar la tabla de §4
sí no │
│ │ ▼
DEX suelto no es de aquí ┌──────────────────────────┐
(.idsig, .so, │ 1 toc.pb APK Set │
binario, .obb │ 2 BundleConfig .aab │
que no es ZIP) │ 3 info.json+RSA .apkm │
│ 4 xapk_version .xapk │
│ 5 meta.sai_v* SAI │
│ 6 varios *.apk plano │
│ 7 manifest APK │
└──────────────────────────┘
Un .obb que sea un ZIP («sección 3.7 · .obb — el heredado») entra por la rama del «sí» y no cumple ninguna regla de
la tabla: tampoco es de aquí.
Y después, qué hacer con ello:
APK Set ──► bundletool extract-apks --device-spec … para quedarse con lo que toca
bundletool install-apks si hay dispositivo
.aab ──► bundletool build-apks --mode=universal para obtener algo instalable
jadx lo lee tal cual para leer el código
.apkm ──► extraer base.apk · la firma del ZIP es de APKMirror, no de la app
.xapk ──► extraer <paquete>.apk · el base NO se llama base.apk
SAI/plano ──► extraer base.apk
APK ──► jadx · apktool · baksmali · apksigner verify
pero antes: ¿tiene atributo split en el <manifest>?
┌──────────────┴──────────────┐
sí no
│ │
es un trozo de aplicación es la aplicación
y le falta el resto entera
Fuentes
- Formato del Android App Bundle — https://developer.android.com/guide/app-bundle/app-bundle-format
Consultado el 13 de agosto de 2026. De aquí salen las tres señales que distinguen un
.aabde unAPKen la «sección 3.2 · .aab — el que no se instala» y su fila de la tabla maestra. - bundletool — documentación oficial — https://developer.android.com/tools/bundletool
Consultado el 13 de agosto de 2026. De aquí sale la definición del APK Set, la sintaxis de
build-apks,install-apksyextract-apksde las secciones «3.3» y «6», y el modo--mode=universal. Aefyr/SAI,META-FORMAT.md— https://github.com/Aefyr/SAI/blob/master/META-FORMAT.md Consultado el 13 de agosto y el 25 de septiembre de 2026 vía la API de GitHub. De aquí salen la descripción del.apksexportado por SAI de la «sección 3.3 · .apks — cuatro cosas distintas con el mismo nombre» —meta.sai_v1.jsondesde la versión 3.10 ymeta.sai_v2.jsondesde la 4.0— y el esquema demeta.sai_v2.json.Aefyr/SAI,README.md— https://github.com/Aefyr/SAI Consultado el 13 de agosto de 2026 vía la API de GitHub. De aquí sale la naturaleza de SAI como instalador desplity la cita sobre su estado de mantenimiento de la «sección 3.6 · El ZIP plano y SAI».- APK expansion files (OBB) — https://developer.android.com/google/play/expansion-files Consultado el 13 de agosto de 2026. De aquí salen el patrón de nombre, la ruta de instalación, el límite de 2 GB y el estado de obsolescencia de la «sección 3.7 · .obb — el heredado».
- adb — documentación oficial — https://developer.android.com/tools/adb
Consultado el 13 de agosto de 2026. De aquí sale la sintaxis de
adb install-multipleyadb shell pm pathde la «sección 6 · Qué se puede hacer con cada uno». - bundletool —
ModuleSplit.java— https://github.com/google/bundletool/blob/master/src/main/java/com/android/tools/build/bundletool/model/ModuleSplit.java Consultado el 25 de septiembre de 2026. De aquí sale que los splits de bibliotecas nativas se crean sin tabla de recursos (forNativeLibraries,setResourceTable = false), y por tanto sinresources.arsc(«sección 4 · Cómo saber en diez segundos qué tienes delante»). Aefyr/SAI,ApksSingleBackupTaskExecutor.javaySaiExportedAppMeta2.java, commit55505d2(SAI 4.5) — https://github.com/Aefyr/SAI/blob/55505d231b1390e824d1cc0c8f4fa35fd4677105/app/src/main/java/com/aefyr/sai/backup2/impl/storage/ApksSingleBackupTaskExecutor.java Consultado el 25 de septiembre de 2026. De aquí salen el orden, la compresión y la condición del icono de los metadatos del.apksde SAI («sección 3.3 · .apks — cuatro cosas distintas con el mismo nombre»).Aefyr/SAI,InstallerXDialogFragment.java, commit55505d2— https://github.com/Aefyr/SAI/blob/55505d231b1390e824d1cc0c8f4fa35fd4677105/app/src/main/java/com/aefyr/sai/ui/dialogs/InstallerXDialogFragment.java#L196 Consultado el 25 de septiembre de 2026. De aquí sale la lista de extensiones que acepta SAI («sección 3.6 · El ZIP plano y SAI»).