¿Cómo excluir los SDKs móviles de la ofuscación de ProGuard en Android? Excluir un SDK de Android de la ofuscación requiere verificar si la librería incluye reglas ProGuard para el consumidor, añadir directivas -keep y -keepclassmembers de alcance preciso para puntos de entrada accesibles mediante reflexión, interfaces de callback, puentes JNI, y modelos de datos, además de auditar los símbolos preservados a través de informes de diagnóstico de R8 e inspección del código DEX crudo. Cuando los equipos de ingeniería de Android habilitan la reducción y optimización de código para las compilaciones de producción, el compilador R8 elimina el bytecode no referenciado y renombra clases, campos y métodos con identificadores cortos. Si un SDK de atribución móvil depende de reflexión dinámica o callbacks JNI que no están protegidos contra la eliminación agresiva de código (tree-shaking) y el renombrado, el deep linking diferido, la deserialización de modelos JSON y las compilaciones de paquetes de canal pueden fallar silenciosamente en producción, incluso después de haber superado todas las pruebas en una compilación de depuración (debug) sin minificar. OpoInstall, una plataforma de atribución móvil y deep linking, proporciona archivos de SDK para Android y flujos de trabajo de paquetes de canal nativos que los equipos de ingeniería pueden configurar y verificar dentro de los pipelines de compilación en release minificados por R8.
En las cadenas de herramientas modernas del Android Gradle Plugin (AGP), los archivos de reglas de preservación (
proguard-rules.proen el DSL heredado osrc/<variant>/keepRules/*.keepen AGP 9.3+) sirven como contrato de configuración para el compilador R8 de Google. Excluir de forma segura un SDK de Android de terceros de la ofuscación significa preservar solo los puntos de entrada de la API pública específica, constructores reflectivos, interfaces de callback, llamadas JNI y campos de modelo requeridos en tiempo de ejecución, evitando reglas demasiado amplias a nivel de paquete o la supresión de advertencias no verificadas.
| Término | Definición | Entidad Relacionada | Rol en la intención de búsqueda |
|---|---|---|---|
| SDK de Android | Librería compilada en Java o Kotlin integrada en una aplicación Android para proporcionar capacidades especializadas como la atribución de instalaciones. | Bytecode classes.dex |
Navegacional / Transaccional |
| ProGuard / R8 | Herramientas de compilación de Android que reducen el código no utilizado, optimizan el bytecode y ofuscan identificadores usando sintaxis de reglas ProGuard. | proguard-rules.pro |
Técnico / Informativo |
| Reglas ProGuard de Consumidor | Reglas de ofuscación integradas dentro de un .aar (/proguard.txt) o .jar (/META-INF/proguard/) que se fusionan automáticamente en R8. |
consumerProguardFiles |
Técnico / Resolución de problemas |
| Informes de Diagnóstico de R8 | Archivos de salida (mapping.txt, seeds.txt, usage.txt, configuration.txt) que detallan el renombrado de símbolos, las reglas de preservación aplicadas y el código eliminado. |
Auditoría de compilación release | Técnico / Resolución de problemas |
¿Por qué la ofuscación de R8 y ProGuard interrumpe los callbacks de atribución del SDK de Android?

La trampa entre Debug y Release: por qué la atribución funciona en pruebas pero falla en producción
Una de las regresiones de ingeniería de lanzamiento más comunes en la captación de usuarios móviles ocurre cuando el deep linking diferido (handleDeepLink) y la restauración de parámetros de instalación (getInstallParam) de una aplicación funcionan correctamente durante las pruebas de QA en compilaciones de depuración, pero devuelven payloads vacíos o dejan de activar callbacks una vez que la aplicación se compila como un APK firmado en versión release o un Android App Bundle (.aab).
La causa raíz reside en la disparidad entre tipos de compilación configurada en Gradle. Por defecto, el tipo de compilación debug deshabilita la reducción de código para acelerar las compilaciones incrementales. Cuando los ingenieros compilan la variante release con la optimización R8 habilitada, el Android Gradle Plugin invoca al Compilador R8 de Android para ejecutar tres transformaciones de bytecode tanto en la aplicación anfitriona como en las librerías de terceros vinculadas:
- Reducción de código (Tree Shaking): R8 analiza el grafo de llamadas de la aplicación comenzando desde los puntos de entrada declarados (como los componentes en
AndroidManifest.xmly las directivas explícitas-keep) y elimina cualquier clase, constructor, método o campo que parezca inalcanzable mediante análisis estático. - Optimización de Bytecode y Modificación de Acceso: R8 integra métodos, elimina parámetros no utilizados, fusiona clases y, cuando se combina con la directiva
-allowaccessmodificationen la configuración de optimización por defecto de Android, modifica las banderas de visibilidad de clases y miembros (por ejemplo, convirtiendo miembrosprivateo package-private enpublicdurante la integración) para reducir el tamaño del archivo Dalvik Executable (.dex) y mejorar la velocidad de ejecución. - Ofuscación de Identificadores (Renombrado y Reempaquetado): R8 renombra las clases, paquetes, campos y métodos restantes en identificadores compactos (como
a.a.b()) y puede reempaquetar clases ofuscadas en jerarquías de paquetes aplanadas, reduciendo la sobrecarga de los pools de cadenas dentro declasses.dex.
El Modo Completo (Full Mode) de R8 ha estado habilitado por defecto desde el Android Gradle Plugin (AGP) 8.0. En comparación con el modo de compatibilidad ProGuard heredado, el modo completo de R8 aplica optimizaciones sustancialmente más estrictas: elimina constructores sin argumentos por defecto (<init>()), altera los modificadores de acceso de los miembros y elimina atributos de metadatos a menos que las clases y miembros asociados sean retenidos explícitamente mediante una regla de preservación coincidente. Para obtener contexto fundamental sobre las estructuras binarias .aar y los estándares de adquisición de SDK, consulte nuestras guías complementarias, Entendiendo el significado de los SDK móviles y los protocolos de crecimiento técnico y Cómo elegir un kit de desarrollo de software para una atribución precisa.
Seis modos de fallo distintos en SDKs de atribución ofuscados

Debido a que el análisis estático del grafo de llamadas no puede predecir las búsquedas dinámicas en tiempo de ejecución, un SDK de Android sin protección puede experimentar seis modos de fallo distintos bajo el Modo Completo de R8. Los ingenieros deben distinguir estos modos de fallo cuidadosamente, ya que cada uno requiere un objetivo de protección ProGuard específico:
| Modo de Fallo en Tiempo de Ejecución | Causa del Bytecode R8 | Objetivo de Protección Requerido |
|---|---|---|
1. Fallo de búsqueda de clase por reflexión (ClassNotFoundException) |
R8 renombra, reempaqueta o elimina una clase cargada dinámicamente por nombre de cadena mediante Class.forName() |
Preservar la clase objetivo y su identificador original usando -keep class ... |
2. Fallo de instanciación de objeto por reflexión (NoSuchMethodException: <init>) |
En modo completo, incluso si una clase se preserva, su constructor sin argumentos por defecto (<init>()) se elimina si no se llama directamente en el código |
Preservar explícitamente la firma del constructor (<init>();) dentro del bloque -keep |
| 3. Fallos en Callback Dinámico y Modificación de Acceso | R8 elimina o renombra los métodos de interfaz de callback, o altera las banderas de visibilidad de miembros esperadas por llamadas reflectivas getDeclaredMethod() / getDeclaredField() |
Preservar los métodos de la interfaz de callback (-keep interface ... { <methods>; }) y cualquier miembro accedido por reflexión |
| 4. Pérdida de Metadatos de Firma Genérica en Listeners | Los genéricos en Java sufren borrado de tipo en tiempo de compilación, mientras que los atributos Signature del bytecode preservan metadatos para reflexión (ResultCallBack<OpoData>). R8 Full Mode elimina estos metadatos si no se retienen explícitamente |
Retener -keepattributes Signature además de mantener tanto la interfaz de callback genérica como la clase de modelo objetivo |
| 5. Fallo de Deserialización de Modelo de Datos JSON | R8 elimina la clase del modelo (si solo se instancia por reflexión) o renombra sus campos a a, b, c, causando que los parsers JSON basados en reflexión devuelvan campos nulos o vacíos |
Usar -keep class ... si el modelo se instancia dinámicamente, o -keepclassmembers si la clase ya se retiene mediante referencias directas |
6. Eliminación de JNI Downcall y Upcall Nativo-a-Java (UnsatisfiedLinkError / NoSuchMethodError) |
Las reglas por defecto de Android preservan los nombres en los native downcalls, pero no evitan que métodos RegisterNatives no usados sean eliminados, y no pueden ver el código C/C++ .so que llama de vuelta a Java mediante JNI (FindClass, GetMethodID) |
Usar explícitamente -keep para declaraciones native registradas dinámicamente y cualquier clase, constructor o método Java invocado vía upcalls JNI |
[Compilación Android Release: Modo Completo R8 Habilitado]
|
v
[R8 evalúa reglas de preservación propias y del host]
|
+---------------+---------------+
| |
v (Reglas faltantes o no coincidentes) v (Reglas de preservación activas + Atributos)
[Símbolos del SDK eliminados o renombrados] [Puntos de entrada y modelos del SDK preservados]
- () reflectivo eliminado - Confirmado en -printseeds (seeds.txt)
- JNI Upcall / Campos de modelo perdidos - Verificado en DEX crudo (apkanalyzer dex packages)
- Metadatos de Firma Genérica perdidos - La atribución en release coincide con debug
Reglas de Consumidor en Bundles AAR vs. Importaciones JAR manuales
Cómo los archivos AAR y JAR incluyen reglas ProGuard de consumidor

Antes de añadir reglas de exclusión manual a su aplicación, inspeccione si el SDK de Android de terceros ya incluye reglas R8 integradas. Como se documenta en la Guía de desarrolladores de Android sobre optimización de librerías, AGP y R8 soportan el descubrimiento automático de reglas de consumidor tanto en distribuciones .aar como .jar, incluyendo reglas R8 segmentadas por versión:
| Formato de Distribución del SDK | Ubicación de Regla de Consumidor Integrada | Comportamiento de Android Gradle Plugin / R8 |
|---|---|---|
Android Archive (.aar) |
/proguard.txt en la raíz del AAR (vía consumerProguardFiles), o reglas segmentadas por versión dentro de /classes.jar bajo /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ |
Extraído y fusionado automáticamente en la configuración R8 de la aplicación en tiempo de compilación |
Java Archive (.jar) con reglas integradas |
/META-INF/proguard/*.pro o /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ (incluyendo variantes r8, r8-from-<X>, y r8-upto-<Y>) |
Descubierto y aplicado automáticamente por AGP y R8 según la versión activa del compilador |
.jar o .aar autónomo sin reglas integradas |
Ninguna presente dentro del archivo | No se proporciona protección integrada; añada reglas de preservación a nivel de host solo cuando la reflexión, JNI, serialización u otros símbolos accedidos dinámicamente requieran preservación explícita |
(Nota sobre reglas de serialización Gson: Como se documenta en la Guía de solución de problemas de Gson para ProGuard y R8, Gson 2.11.0 y versiones posteriores incluyen reglas R8 para TypeToken y campos anotados con @SerializedName. Estas reglas no eliminan la necesidad de restringir el acceso a modelos reflectivos, proporcionar constructores sin argumentos compatibles o probar todos los caminos de serialización y deserialización en compilaciones minificadas.)
Inspeccionando el archivo SDK descargado antes de escribir reglas
La coincidencia de reglas de ProGuard y R8 es estrictamente sensible a mayúsculas y exacta en la ruta del paquete. En diferentes versiones del SDK o distribuciones regionales, los espacios de nombres de los paquetes pueden variar; si copia una regla de un tutorial antiguo cuyo paquete no coincide con los archivos .class reales en su archivo, R8 no encontrará ninguna coincidencia.
Antes de editar sus reglas de preservación, descargue su paquete SDK objetivo (como el SDK de Android v2.1.0 desde el centro de descargas de SDKs móviles) e inspeccione sus reglas integradas (tanto en /proguard.txt como dentro de classes.jar) junto con su jerarquía exacta de .class:
# 1. Inspeccionar un archivo .aar para reglas de consumidor raíz (proguard.txt) y extraer classes.jar para verificar reglas META-INF
unzip -l opoinstall-android-sdk.aar
unzip -p opoinstall-android-sdk.aar proguard.txt
unzip -p opoinstall-android-sdk.aar classes.jar > temp_classes.jar
jar tf temp_classes.jar | grep -E "META-INF/proguard/|META-INF/com\.android\.tools/|\.class$"
# 2. Si usa un archivo .jar autónomo, inspeccione las reglas META-INF integradas y las rutas .class exactas
jar tf libs/OpoInstall_SDK.jar | grep -E "META-INF/proguard/|META-INF/com\.android\.tools/|\.class$"
Configurando proguard-rules.pro para SDKs de atribución de Android
Evitando antipatrones de preservación a nivel de paquete y supresión general de advertencias
Al escribir reglas personalizadas, los ingenieros deben seguir las mejores prácticas de Google sobre Elegir qué conservar (reglas de preservación R8) para evitar deshabilitar la optimización innecesariamente:
- Prefiera reglas precisas sobre los antipatrones
-keep class package.** { *; }: Una regla general a nivel de paquete obliga a R8 a conservar y omitir la optimización en cada clase auxiliar interna en ese paquete. Limite sus reglas a las clases específicas, constructores (<init>();), interfaces de callback, objetivos JNI y campos de modelo accedidos dinámicamente en tiempo de ejecución (o utilice la anotación@UnconditionallyKeepde Jetpack en el código que usted controla). - Distinga
-keepde-keepclassmembersen modelos de datos:-keepclassmemberssolo preserva campos o métodos especificados si la clase contenedora se retiene en el grafo de llamadas. Si un modelo de datos (comoOpoData) se instancia únicamente vía reflexión o es referenciado solo a través de tipos genéricos borrados, use-keep class ...para que R8 no elimine la clase misma. - Entienda las limitaciones de
-keepclasseswithmembernamespara JNI: Las reglas de optimización por defecto de Android incluyen-keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; }. Como se define en la documentación de R8 de Google y el Manual de ProGuard sobre directivas de preservación,-keepclasseswithmembernameses equivalente a-keepclasseswithmembers,allowshrinking. Preserva los nombres de clases y miembros coincidentes que sobreviven a la fase de reducción, pero no evita que clases o métodosnativeno referenciados sean eliminados durante la reducción. Si los métodos nativos se registran dinámicamente medianteRegisterNativessin sitios de llamada directos en Java, o si el código C/C++ invoca métodos Java vía upcalls JNI, debe usar reglas-keepo-keepclassmembersexplícitas según cómo se instancia la clase objetivo. - Evite directivas blanket
-dontwarnno verificadas:-dontwarnproporciona cero protección contra la reducción o el renombrado y suprime advertencias de referencias no resueltas que pueden ocultar fallosNoClassDefFoundErroren tiempo de ejecución. Solo añada un-dontwarnde alcance limitado si su registro de compilación informa de una clase específica faltante (solo de compilación) que usted ha verificado que es opcional en tiempo de ejecución.
| Directiva ProGuard / R8 | Sintaxis de forma larga equivalente | Reducción (Eliminación) | Ofuscación (Renombrado) | Alcance de ingeniería recomendado |
|---|---|---|---|---|
-keep class ... |
-keep |
Prevenida (clase y miembros especificados conservados) | Prevenida (nombres originales conservados) | Puntos de entrada públicos, interfaces de callback y clases instanciadas dinámicamente (incluir <init>(...);) |
-keepclassmembers class ... |
-keepclassmembers |
Miembros conservados solo si la clase es retenida | Prevenida para miembros coincidentes | Preservar <fields>; o métodos de upcall JNI en clases instanciadas directamente en Java/Kotlin |
-keepclasseswithmembernames |
-keepclasseswithmembers,allowshrinking |
Permitida si no se referencia (allowshrinking) |
Prevenida si la clase/miembros sobreviven a la reducción | Preservación de nombres de downcall JNI (native <methods>;) cuando el código Java invoca el método native |
-keepnames class ... |
-keep,allowshrinking |
Permitida si no se referencia (allowshrinking) |
Prevenida si la clase es retenida | Mantener nombres de clase legibles para seguimientos de pila (stack traces) sin forzar clases no usadas en classes.dex |
-keepattributes ... |
-keepattributes |
Preserva metadatos en elementos retenidos | N/A (Atributo de bytecode) | Retener Signature (genéricos), InnerClasses, EnclosingMethod y *Annotation* en clases explícitamente preservadas |
-dontwarn <clase_específica> |
-dontwarn |
Sin efecto en la reducción | Sin efecto en el renombrado | Suprimir advertencias en tiempo de compilación solo para una dependencia opcional verificada |
Configurando Gradle en cadenas de herramientas AGP 8.x y AGP 9.3+
El Android Gradle Plugin 9.3 introdujo un bloque DSL de optimization simplificado y directorios keepRules específicos por variante (archivos .keep), mientras que AGP 8.x hasta 9.2 (y configuraciones heredadas aún soportadas en AGP 9.3+) utilizan isMinifyEnabled y proguardFiles. Los ingenieros deben mantener tres objetos de configuración distintos:
| Objeto de Configuración | Ubicación del Archivo o DSL | Rol Arquitectónico en Compilaciones R8 |
|---|---|---|
| Reglas de Preservación DSL Heredadas (AGP 8.x–9.2 y Heredado 9.3+) | app/proguard-rules.pro (referenciado vía proguardFiles(...)) |
Declara reglas de preservación del host junto con getDefaultProguardFile("proguard-android-optimize.txt") |
| Reglas de Preservación DSL de Optimización (AGP 9.3+) | app/src/main/keepRules/*.keep o app/src/<variant>/keepRules/*.keep |
Declara archivos .keep al usar optimization { enable = true } |
| Directivas de Informe de Diagnóstico R8 | -printseeds, -printusage, -printconfiguration en un archivo de configuración R8 verificado (proguard-rules.pro) |
Instruye a R8 a emitir informes de auditoría en app/build/outputs/mapping/<buildVariant>/ |
// Opción A: AGP 8.x - 9.2 DSL Heredado (también soportado en AGP 9.3+) — app/build.gradle.kts
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
// Opción B: AGP 9.3+ DSL de Optimización Simplificado — app/build.gradle.kts
// Coloque las reglas de preservación de clases/miembros en app/src/main/keepRules/sdk-attribution.keep
android {
buildTypes {
release {
optimization {
enable = true
}
}
}
}
Reglas de preservación ilustrativas y directivas de diagnóstico
Debido a que la documentación pública de OpoInstall y las páginas de FAQ históricas hacen referencia a diferentes prefijos de paquete (com.opoinstall.api.** vs. com.fm.OpoInstall.** o io.OpoInstall.**), el conjunto de reglas a continuación es solo ilustrativo: no es un conjunto de reglas de producción verificado para el SDK de OpoInstall v2.1.0. Inspeccione las rutas de clase reales y las reglas de consumidor integradas dentro de su archivo descargado v2.1.0 primero, y consulte la documentación técnica de OpoInstall (vea Cómo los Kits de Desarrollo de Software potencian la atribución y el crecimiento móvil para el código de ciclo de vida de Java subyacente):
# Archivo: app/src/main/keepRules/sdk-attribution.keep (o app/proguard-rules.pro)
# IMPORTANTE: Solo ilustrativo — no es un conjunto de reglas de producción verificado para OpoInstall SDK v2.1.0.
# Verifique los nombres de paquete y clase sensibles a mayúsculas dentro de su archivo v2.1.0 descargado
# mediante `jar tf` o `apkanalyzer`, y verifique `configuration.txt` por reglas de consumidor existentes.
# ---------------------------------------------------------------------------
# 1. Preservar atributos de Bytecode en clases explícitamente preservadas
# Requerido para que las interfaces de callback genéricas (ej. ResultCallBack<OpoData>)
# retengan sus metadatos de tipo parametrizado en R8 Full Mode.
# ---------------------------------------------------------------------------
-keepattributes Signature, InnerClasses, EnclosingMethod, *Annotation*
# ---------------------------------------------------------------------------
# 2. Reglas de punto de entrada, interfaz de callback y modelos de datos del SDK
# ---------------------------------------------------------------------------
# Preservar el punto de entrada público del SDK y cualquier constructor/método invocado por reflexión:
-keep public class com.opoinstall.api.OpoInstall {
<init>(...);
public <methods>;
}
# Preservar interfaces de listener de callback y sus métodos:
-keep public interface com.opoinstall.api.ResultCallBack {
public <methods>;
}
# Escenario A: Si los modelos OpoData / OpoError se instancian dinámicamente por reflexión
# o se referencian solo vía genéricos borrados, use -keep para preservar la clase y sus miembros:
-keep class com.opoinstall.api.OpoData {
<init>(...);
<fields>;
public <methods>;
}
-keep class com.opoinstall.api.OpoError {
<init>(...);
<fields>;
public <methods>;
}
# Escenario B: Si una clase modelo ya es retenida directamente en el grafo de llamadas
# y solo sus campos requieren protección contra el renombrado, use -keepclassmembers:
# -keepclassmembers class com.opoinstall.api.OpoData { <fields>; }
# ---------------------------------------------------------------------------
# 3. Protección de JNI Downcall y Native-to-Java Upcall (Patrones JNI ilustrativos)
# ---------------------------------------------------------------------------
# Caso JNI A: Si el código Java/Kotlin ya instancia directamente la clase puente JNI,
# use -keepclassmembers,includedescriptorclasses para métodos de upcall C/C++,
# y preserve las clases/constructores de parámetros instanciados por código nativo:
-keepclassmembers,includedescriptorclasses class com.example.sdk.internal.JniBridge {
public void onNativeAttributionEvent(com.example.sdk.internal.NativeEventData);
}
-keep class com.example.sdk.internal.NativeEventData {
<init>(...);
}
# Caso JNI B: Si el código nativo C/C++ busca o instancia dinámicamente la clase Java
# mediante FindClass / NewObject, o registra métodos nativos vía RegisterNatives
# sin sitios de llamada Java directos, use -keep para prevenir la eliminación de clases y métodos:
-keep,includedescriptorclasses class com.example.sdk.internal.DynamicNativeBridge {
<init>(...);
public native <methods>;
public void onNativeCallback(java.lang.String);
}
# Archivo: app/proguard-rules.pro (Directivas de salida de diagnóstico)
# Coloque las banderas de informe de diagnóstico R8 en su archivo de configuración verificado.
# Las rutas se resuelven relativas al directorio de trabajo del módulo (`app/`).
# Ajuste el nombre del directorio para variantes de producto (ej. build/outputs/mapping/prodRelease/).
-printseeds build/outputs/mapping/release/seeds.txt
-printusage build/outputs/mapping/release/usage.txt
-printconfiguration build/outputs/mapping/release/configuration.txt
Resolución de conflictos de ofuscación y fortalecimiento en paquetes de canal de Android
Separación de compilación R8, alineación APK, firma y paquetes de canal
Para distribuciones de Android fuera de Google Play, OpoInstall soporta la exportación de Paquetes de Canal de Android dedicados, tomando un APK base subido por el desarrollador y generando APKs específicos para cada canal que llevan metadatos de rastreo channelCode distintos.
Al solucionar problemas de estadísticas de canal faltantes o fallos de instalación en paquetes de canal exportados, los ingenieros deben separar dos criterios de verificación de lanzamiento independientes: validez de la firma criptográfica del APK e integridad de los metadatos del canal del proveedor:
- Reducción de código R8 en tiempo de compilación: R8 se ejecuta dentro del pipeline de compilación de Gradle al convertir bytecode Java/Kotlin en
classes.dexantes de que el APK base sea empaquetado y firmado. R8 nunca se ejecuta en un APK ya exportado. - Alineación de APK (
zipalign) y Firma Criptográfica (apksigner): Los APKs estándar de lanzamiento construidos por AGP se alinean automáticamente. Sin embargo, si su pipeline de lanzamiento aplica post-procesamiento personalizado o refuerzo (hardening) de terceros antes de firmar, debe volver a alinear el APK bajo las especificaciones oficiales dezipalignde Android y las especificaciones deapksignerde Android.zipalignalinea datos sin comprimir en límites de 4 bytes; si el APK contiene librerías nativas.sosin comprimir, los equipos deben usarzipalign -P 16 -f -v 4 infile.apk outfile.apkpara cumplir con los requisitos de alineación de página de 16 KB y verificar conzipalign -c -P 16 -v 4.zipaligndebe ejecutarse antes de firmar conapksigner, ya que modificar un APK después de firmarlo invalida su firma criptográfica V2/V3. - Verificación de Firma y Metadatos de Canal Específicos del Proveedor: Ejecutar herramientas de refuerzo (hardening) o reempaquetado de terceros después de exportar un APK de canal desde la consola de OpoInstall puede sobrescribir los metadatos del canal integrados o invalidar la firma del APK. Si un parser de paquetes de canal de terceros requiere un esquema de firma APK específico (como habilitar la firma JAR V1 junto con la firma V2/V3), verifique ese requisito directamente con su documentación actual de OpoInstall o soporte del proveedor antes de modificar las configuraciones de firma de producción, y no trate la firma V1 como un requisito universal del SO Android.
Orden recomendado del pipeline de lanzamiento para paquetes de canal de Android
Para mantener firmas APK válidas, optimización R8 intacta y metadatos de canal de proveedor, ejecute su pipeline de lanzamiento en esta secuencia estricta:
- Compilar y minificar el APK base con R8: Ejecute
./gradlew :app:assembleReleasecon sus reglas de preservación verificadas para que R8 optimiceclasses.dexen tiempo de compilación. - Completar refuerzo pre-subida, alineación y firma: Si su equipo de seguridad utiliza herramientas de refuerzo de terceros, aplíquelas al APK base, ejecute
zipalign -P 16 -f -v 4(si es necesaria la realineación antes de firmar), verifique conzipalign -c -P 16 -v 4y firme el APK base. - Subir el APK base y verificar independientemente los APKs de canal exportados: Suba el APK base firmado y ofuscado a la consola de OpoInstall, exporte los APKs de canal y verifique independientemente tanto la validez de la firma criptográfica (
apksigner verify --verbose) como la atribución de canal en el dispositivo físico en el APK exportado antes de la distribución pública.
[Pipeline recomendado para paquetes de canal]: Código Fuente -> Minificación Gradle R8 -> (Refuerzo previo opcional + zipalign -P 16 + Firma) -> Subir APK base a consola -> Exportar APK de canal -> Verificar firma (apksigner) y Callback de canal
Auditoría de símbolos del SDK preservados usando informes de R8 y APK Analyzer
Uso del Analizador de configuración R8 autónomo en AGP 9.3+
En el Android Gradle Plugin 9.3 y posteriores, no necesita esperar a una compilación completa de APK o App Bundle para auditar cómo se fusionan y coinciden sus reglas de preservación. AGP 9.3+ proporciona una tarea de Gradle dedicada analyze<Variant>R8Config (por ejemplo, ./gradlew :app:analyzeReleaseR8Config), que evalúa rápidamente las reglas del consumidor y del host y emite diagnósticos de configuración para que los ingenieros puedan iterar sobre las reglas .keep antes de ejecutar una compilación completa.
Verificación cruzada de configuration.txt, seeds.txt, usage.txt y mapping.txt

Nunca asuma que una regla -keep funcionó simplemente porque ./gradlew :app:assembleRelease finalizó sin errores. Para verificar su configuración determinísticamente, inspeccione los cuatro archivos de diagnóstico de R8 generados en app/build/outputs/mapping/<buildVariant>/ (use -whyareyoukeeping class <ClassName> cuando depure por qué un símbolo específico fue retenido):
configuration.txt: Contiene el conjunto de reglas completo y fusionado aplicado por R8, combinando sus reglas de preservación, reglas de plataforma Android por defecto, reglas AAPT2 y cualquier regla/proguard.txto/META-INF/integrada dentro de librerías.aary.jarvinculadas.seeds.txt: Lista cada clase, constructor (<init>()), método y campo que coincidió con sus reglas activas-keep. Note que la coincidencia enseeds.txtconfirma la sintaxis de la regla, pero debe ser emparejada con inspección DEX y pruebas en tiempo de ejecución.usage.txt: Lista el código muerto que R8 eliminó del APK durante la reducción. Confirme que ninguna de sus clases de SDK requeridas, constructores reflectivos o métodos de upcall JNI aparecen enusage.txt.mapping.txt: Registra el mapa de traducción de identificadores antes y después para clases y miembros retenidos. Note que la ausencia enmapping.txtno prueba que una clase se preservó bajo su nombre original: puede haber sido eliminada completamente durante la reducción (y listada enusage.txt). Realice siempre referencia cruzada demapping.txtcontraseeds.txt,usage.txty el archivo DEX compilado.
Verificación de identificadores DEX crudos vs. estados de informes deobfuscados con apkanalyzer
Al utilizar el CLI de APK Analyzer de Google Android Developers oficial para inspeccionar su APK de lanzamiento, distinga entre identificadores DEX compilados crudos y nombres desofuscados por mapeo:
- Inspeccionando nombres DEX compilados crudos (Sin
--proguard-mappings): Cuando pasa--proguard-mappings mapping.txtaapkanalyzer, la herramienta traduce los nombres DEX ofuscados (comoa.b.c) de vuelta a sus nombres originales. Por lo tanto, ver un nombre de clase original cuando--proguard-mappingsestá habilitado no prueba que el símbolo escapó del renombrado enclasses.dex. Ejecuteapkanalyzer dex packagessin--proguard-mappingsprimero. Debido a que el reempaquetado de clases de R8 puede mover clases a rutas de paquete aplanadas, no confíe solo en ungrepde paquete; inspeccione el árbol de clases DEX crudo, verifique los nombres de las clases de puntos de entrada de reflexión, revise los nombres de métodos JNI y firmas de descriptores, y verifiquemapping.txtpara confirmar que los métodos y campos requeridos no fueron renombrados. - Inspeccionando estados de retención de R8 (Con
--proguard-mappings,--proguard-seedsy--proguard-usages): En una segunda pasada, proporcione los tres archivos de informe de R8 para reconstruir las banderas de retención (kpor retenido por una regla seed,xpor eliminado durante la reducción,rpor referenciado ydpor definido) a través de cada paquete (P), clase (C), método (M) y campo (F):
# Ejecutar desde el directorio raíz del proyecto Android (ajuste la ruta de la variante para sabores de producto, ej. prodRelease)
# 1. (AGP 9.3+) Ejecute el analizador de configuración R8 autónomo para verificación rápida, luego compile el APK de lanzamiento
./gradlew :app:analyzeReleaseR8Config
./gradlew :app:assembleRelease
# 2. Inspeccione la configuración R8 fusionada, los seeds coincidentes y los informes de uso eliminados
grep -i -C 3 "opoinstall" app/build/outputs/mapping/release/configuration.txt
grep -i "opoinstall" app/build/outputs/mapping/release/seeds.txt
grep -i "opoinstall" app/build/outputs/mapping/release/usage.txt
# 3A. Inspeccione identificadores DEX compilados CRUDOS (SIN --proguard-mappings)
# Inspeccione también el árbol DEX crudo completo y verifique mapping.txt en caso de reempaquetado
apkanalyzer dex packages app/build/outputs/apk/release/app-release.apk | grep -i "opoinstall"
# 3B. Inspeccione banderas de estado de retención R8 (k=retenido, x=eliminado, r=ref, d=def) CON informes R8
apkanalyzer dex packages \
--proguard-mappings app/build/outputs/mapping/release/mapping.txt \
--proguard-seeds app/build/outputs/mapping/release/seeds.txt \
--proguard-usages app/build/outputs/mapping/release/usage.txt \
app/build/outputs/apk/release/app-release.apk | grep -i "opoinstall"
# 4. Verifique la alineación de página de 16 KB (si hay archivos .so nativos) y firmas APK criptográficas
zipalign -c -P 16 -v 4 app/build/outputs/apk/release/app-release.apk
apksigner verify --verbose app/build/outputs/apk/release/app-release.apk
Matriz de solución de problemas de atribución en lanzamientos
Diagnóstico de fallos silenciosos de atribución y deep-link en compilaciones Android minificadas
Al solucionar discrepancias de atribución que solo ocurren en compilaciones release minificadas, use la matriz de diagnóstico a continuación para aislar la causa raíz:
| Síntoma observado en Release | Causa raíz probable en R8 / Build | Paso de verificación diagnóstica | Acción correctiva |
|---|---|---|---|
El callback getInstallParam o handleDeepLink no se dispara |
Clases de punto de entrada del SDK, constructores reflectivos <init>(), o métodos ResultCallBack fueron eliminados o renombrados |
Verificar seeds.txt y usage.txt; inspeccionar salida apkanalyzer dex packages (sin mapeo) y mapping.txt |
Inspeccionar el .jar / .aar con jar tf para hallar rutas de clase precisas y añadir reglas -keep incluyendo <init>(...); |
Callback se dispara, pero parámetros personalizados de OpoData salen vacíos/nulos |
OpoData fue protegido solo con -keepclassmembers (permitiendo que la clase sea eliminada) o se perdieron metadatos Signature |
Revisar usage.txt y mapping.txt para OpoData y verificar configuration.txt para -keepattributes Signature |
Usar -keep class ... con <init>(...); <fields>; y retener -keepattributes Signature |
UnsatisfiedLinkError o callback nativo faltante al cargar .so |
Downcalls RegisterNatives fueron reducidos o métodos de upcall C/C++-a-Java renombrados |
Inspeccionar logcat para el símbolo JNI faltante y revisar apkanalyzer y mapping.txt |
Usar -keep (o -keepclassmembers) con includedescriptorclasses en los objetivos de upcall JNI y RegisterNatives |
| El paquete de canal de Android falla al instalar o no registra estadísticas | Modificación del APK post-exportación invalidó la firma o sobrescribió metadatos | Ejecutar zipalign -c -P 16 -v 4 y apksigner verify en el APK exportado y probar en un dispositivo físico |
Completar toda la minificación R8, refuerzo, alineación y firma en el APK base antes de subirlo a la consola; verificar tras la exportación |
Preguntas Frecuentes (FAQ)
¿Cómo excluyo un SDK móvil de la ofuscación ProGuard y R8 en Android?
¿Cómo verifico que mis clases de SDK de Android fueron excluidas de la ofuscación R8?
¿Por qué las estadísticas de los paquetes de canal de Android dejan de funcionar después del hardening o post-procesamiento del APK?
Resumen y lista de verificación de compilación para lanzamientos
Entender cómo excluir SDKs móviles de la ofuscación de ProGuard y R8 es fundamental para prevenir regresiones de atribución silenciosas al realizar la transición de pruebas de depuración a compilaciones de producción. Al verificar las reglas de consumidor, escribir directivas -keep de alcance preciso que coincidan con las rutas exactas dentro del archivo de su SDK, respetar el orden de compilación para paquetes de canal de Android y verificar la salida diagnóstica de R8 contra el bytecode DEX, los ingenieros pueden mantener una reducción de código completa sin romper el deep linking diferido o la restauración de parámetros.
Antes de publicar una compilación Android minificada en Google Play o exportar paquetes de canal, ejecute esta lista de verificación de cuatro pasos:
-
Inspeccione el archivo SDK y la configuración fusionada: Revise su archivo SDK descargado (como v2.1.0) con
jar tfounzip -lpara inspeccionar las rutas de clase exactas y las reglas de consumidor, y ejecute./gradlew :app:analyzeReleaseR8Config(en AGP 9.3+) o reviseconfiguration.txt. -
Verifique informes R8 e identificadores DEX crudos: Confirme que los puntos de entrada del SDK, constructores
<init>(), campos del modeloOpoData, métodosResultCallBacky firmas JNI aparezcan enseeds.txt, estén ausentes deusage.txty retengan sus nombres originales en la salida deapkanalyzer dex packages(sin--proguard-mappings) ymapping.txt. -
Aplique minificación pre-subida y verifique firmas de paquetes de canal: Complete toda la minificación R8, refuerzo de terceros,
zipalign(zipalign -c -P 16 -v 4) y la firma del APK base antes de subirlo para exportar paquetes de canal, y ejecuteapksigner verify --verboseen los paquetes exportados. -
Ejecute una prueba de humo de lanzamiento en dispositivo físico: Instale el APK firmado y minificado en un dispositivo Android real y verifique tanto la instalación de parámetros H5 (
getInstallParam) como la activación con un clic (handleDeepLink).
Los equipos de ingeniería pueden registrar una aplicación y subir su APK base ofuscado en la consola de desarrolladores de OpoInstall para probar la exportación de paquetes de canal y verificar la restauración de parámetros en compilaciones release.
Materiales relacionados
-
Conceptos: Reducción de código Android R8, ofuscación de identificadores, reglas ProGuard de consumidor, orden de compilación de paquetes de canal
-
Tecnologías: Android Gradle Plugin (AGP), Compilador R8,
proguard-rules.pro, Android Studio APK Analyzer -
Estándares: Proyecto de seguridad de aplicaciones móviles OWASP
-
Interfaces de Plataforma e Integración:
isMinifyEnabled,optimization.enable,analyzeReleaseR8Config,consumerProguardFiles,seeds.txt,usage.txt,apkanalyzer dex packages,apksigner,zipalign -
Documentación oficial y referencias:
Share this article



