Comment exclure les SDK mobiles de l'obfuscation ProGuard sur Android ? Exclure un SDK Android de l'obfuscation nécessite de vérifier si la bibliothèque intègre des règles ProGuard consommateur (consumer rules), d'ajouter des directives -keep et -keepclassmembers strictement ciblées pour les points d'entrée appelés par réflexion, les interfaces de callback, les ponts JNI et les modèles de données, puis d'auditer les symboles préservés via les rapports de diagnostic R8 et l'inspection brute des fichiers DEX. Lorsque les équipes d'ingénierie Android activent la réduction et l'optimisation du code pour les builds de production (release), le compilateur R8 supprime le bytecode non référencé et renomme les classes, les champs et les méthodes en identifiants courts. Si un kit de développement logiciel (SDK) d'attribution mobile repose sur la réflexion dynamique ou des callbacks JNI non protégés contre un élagage (tree-shaking) et un renommage agressifs, le deferred deep linking, la désérialisation des modèles JSON et la génération de packages par canal peuvent échouer silencieusement en production, même après avoir réussi tous les tests sur un build de debug non minifié. OpoInstall, une plateforme d'attribution mobile et de deep linking, fournit des archives SDK Android natives ainsi que des workflows de packages par canal que les équipes techniques peuvent configurer et vérifier au sein de pipelines de release minifiés par R8.
Dans les chaînes d'outils modernes de l'Android Gradle Plugin (AGP), les fichiers de règles de conservation (
proguard-rules.prodans le DSL historique ousrc/<variant>/keepRules/*.keepdans AGP 9.3+) servent de contrat de configuration pour le compilateur R8 de Google. Exclure en toute sécurité un SDK Android tiers de l'obfuscation consiste à ne préserver que les points d'entrée d'API publiques spécifiques, les constructeurs réflectifs, les interfaces de callback, les appels montants (upcalls) JNI et les champs de modèles requis à l'exécution — tout en évitant les règles de conservation trop larges à l'échelle d'un package entier ou les suppressions d'avertissements non vérifiées.
| Terme | Définition | Entité associée | Rôle d'intention de recherche |
|---|---|---|---|
| SDK Android | Une bibliothèque Java ou Kotlin compilée, intégrée dans une application Android pour fournir des fonctionnalités spécialisées telles que l'attribution d'installation. | Bytecode classes.dex |
Navigationnel / Transactionnel |
| ProGuard / R8 | Outils de compilation Android qui réduisent le code inutilisé, optimisent le bytecode et obfusquent les identifiants à l'aide de la syntaxe des règles ProGuard. | proguard-rules.pro |
Technique / Informationnel |
| Règles ProGuard consommateur | Règles d'obfuscation intégrées dans un fichier .aar (/proguard.txt) ou .jar (/META-INF/proguard/) qui fusionnent automatiquement dans R8. |
consumerProguardFiles |
Technique / Dépannage |
| Rapports de diagnostic R8 | Fichiers de sortie (mapping.txt, seeds.txt, usage.txt, configuration.txt) détaillant le renommage des symboles, les règles appliquées (seeds) et le code supprimé. |
Audit du build de release | Technique / Dépannage |
Pourquoi l'obfuscation R8 et ProGuard interrompt les callbacks d'attribution des SDK Android

Le piège Debug vs Release : pourquoi l'attribution fonctionne en test mais échoue en production
L'une des régressions d'ingénierie de release les plus courantes en acquisition d'utilisateurs mobiles se produit lorsque le deferred deep linking (handleDeepLink) et la restauration des paramètres d'installation (getInstallParam) d'une application fonctionnent de manière fiable lors des tests QA sur les builds de debug, mais renvoient des charges utiles (payloads) vides ou cessent de déclencher des callbacks une fois l'application compilée sous forme d'APK de release signé ou d'Android App Bundle (.aab).
La cause principale réside dans la disparité des types de build configurés dans Gradle. Par défaut, le type de build debug désactive la réduction du code pour accélérer les compilations incrémentales. Lorsque les ingénieurs compilent la variante release avec l'optimisation R8 activée, l'Android Gradle Plugin invoque le compilateur Android R8 pour exécuter trois transformations de bytecode à la fois sur l'application hôte et sur les bibliothèques tierces liées :
- Réduction du code (Tree Shaking) : R8 analyse le graphe d'appels de l'application à partir des points d'entrée déclarés (tels que les composants
AndroidManifest.xmlet les directives-keepexplicites) et supprime toute classe, constructeur, méthode ou champ qui semble inaccessible via une analyse statique. - Optimisation du bytecode et modification des accès : R8 intègre les méthodes en ligne (inlining), supprime les paramètres inutilisés, fusionne les classes et — lorsqu'il est associé à la directive
-allowaccessmodificationdans la configuration d'optimisation par défaut d'Android — modifie les indicateurs de visibilité des classes et des membres (comme l'élargissement des membresprivateou package-private enpubliclors de l'inlining) afin de réduire la taille de l'exécutable Dalvik (.dex) et d'améliorer la vitesse d'exécution. - Obfuscation des identifiants (renommage et reconditionnement) : R8 renomme les classes, packages, champs et méthodes restants en identifiants compacts (tels que
a.a.b()) et peut reconditionner les classes obfusquées dans des hiérarchies de packages aplaties, réduisant ainsi la surcharge du pool de chaînes à l'intérieur declasses.dex.
Le mode complet (Full Mode) de R8 est activé par défaut depuis l'Android Gradle Plugin (AGP) 8.0. Par rapport à l'ancien mode de compatibilité ProGuard, le mode complet de R8 applique des optimisations nettement plus strictes : il supprime les constructeurs par défaut sans argument (<init>()), modifie les modificateurs d'accès des membres et élimine les attributs de métadonnées, à moins que les classes et membres associés ne soient explicitement conservés par une règle de conservation correspondante. Pour un contexte fondamental sur les structures binaires .aar et les normes de sélection de SDK, consultez nos guides complémentaires : Comprendre la signification des SDK mobiles et les protocoles techniques de croissance et Comment choisir un kit de développement logiciel pour une attribution précise.
Six modes de défaillance distincts dans les SDK d'attribution obfusqués

Étant donné que l'analyse statique du graphe d'appels ne peut pas prédire les recherches dynamiques à l'exécution, un SDK Android non protégé peut rencontrer six modes de défaillance distincts sous le mode complet de R8. Les ingénieurs doivent distinguer ces modes avec soin, car chacun nécessite une cible de protection ProGuard spécifique :
| Mode de défaillance à l'exécution | Cause sous-jacente dans le bytecode R8 | Cible de protection spécifique requise |
|---|---|---|
1. Échec de recherche de classe par réflexion (ClassNotFoundException) |
R8 renomme, reconditionne ou supprime une classe chargée dynamiquement par son nom sous forme de chaîne via Class.forName() |
Préserver la classe cible et son identifiant d'origine à l'aide de -keep class ... |
2. Échec d'instanciation d'objet par réflexion (NoSuchMethodException: <init>) |
En mode complet R8, même si une classe est conservée, son constructeur par défaut sans argument (<init>()) est supprimé s'il n'est pas directement appelé dans le code |
Préserver explicitement la signature du constructeur (<init>();) à l'intérieur du bloc -keep de la classe |
| 3. Échecs de callbacks dynamiques et de modification d'accès | R8 supprime ou renomme les méthodes d'interface de callback, ou modifie les indicateurs de visibilité des membres attendus par les appels réflectifs getDeclaredMethod() / getDeclaredField() |
Préserver les méthodes de l'interface de callback (-keep interface ... { <methods>; }) et tous les membres accessibles par réflexion |
| 4. Perte des métadonnées de signature générique dans les écouteurs de callback | Les types génériques Java subissent un effacement de type à la compilation, tandis que les attributs Signature du bytecode préservent les métadonnées génériques pour la réflexion à l'exécution (ResultCallBack<OpoData>). Le mode complet R8 supprime les métadonnées Signature sauf si elles sont explicitement retenues |
Conserver -keepattributes Signature en plus de conserver à la fois l'interface de callback générique et la classe du modèle cible |
| 5. Échec de désérialisation du modèle de données JSON | R8 supprime la classe du modèle (si elle n'est instanciée que par réflexion) ou renomme ses champs en a, b, c, ce qui amène les analyseurs JSON basés sur la réflexion à renvoyer des champs nuls ou vides |
Utiliser -keep class ... si le modèle est instancié dynamiquement, ou -keepclassmembers si la classe est déjà retenue via des références directes |
6. Suppression des appels descendants JNI et des appels montants Natif-vers-Java (UnsatisfiedLinkError / NoSuchMethodError) |
Les règles Android par défaut préservent les noms sur les appels descendants Java native survivants, mais n'empêchent pas la suppression des méthodes RegisterNatives inutilisées et ne peuvent pas voir le code C/C++ .so rappelant Java via JNI (FindClass, GetMethodID) |
Utiliser explicitement -keep sur les déclarations native enregistrées dynamiquement ainsi que sur les classes, constructeurs et méthodes Java invoqués via des appels montants JNI depuis C/C++ |
[Android Release Build: R8 Full Mode Enabled]
|
v
[R8 Evaluates Bundled & Host Keep Rules]
|
+---------------+---------------+
| |
v (Missing / Mismatched Rules) v (Scoped Keep Rules + Attributes Active)
[SDK Symbols Stripped or Renamed] [Required SDK Entry Points & Models Preserved]
- Reflective () Removed - Confirmed in -printseeds (seeds.txt)
- JNI Upcall / Model Fields Lost - Verified in Raw DEX (apkanalyzer dex packages)
- Generic Signature Metadata Lost - Release Attribution Matches Debug Behavior
Règles consommateur dans les bundles AAR vs importations manuelles de JAR
Comment les bibliothèques AAR et JAR intègrent les règles ProGuard consommateur

Avant d'ajouter manuellement des règles d'exclusion à votre application hôte, vérifiez si le SDK Android tiers intègre déjà des règles R8. Comme documenté dans le Guide des développeurs Google Android sur l'optimisation des bibliothèques, AGP et R8 prennent en charge la découverte automatique des règles consommateur dans les distributions .aar et .jar, y compris les règles R8 ciblant des versions spécifiques :
| Format de distribution du SDK | Emplacement des règles consommateur intégrées | Comportement de compilation d'Android Gradle Plugin / R8 |
|---|---|---|
Archive Android (.aar) |
/proguard.txt à la racine de l'AAR (via consumerProguardFiles), ou règles ciblées par version dans /classes.jar sous /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ |
Extraites et fusionnées automatiquement dans la configuration R8 de l'application hôte lors de la compilation |
Archive Java (.jar) avec règles intégrées |
/META-INF/proguard/*.pro ou /META-INF/com.android.tools/r8-from-<X>-upto-<Y>/ (incluant les variantes r8, r8-from-<X> et r8-upto-<Y>) |
Découvertes et appliquées automatiquement par AGP et R8 selon la version active du compilateur R8 |
.jar ou .aar autonome sans règles intégrées |
Aucune règle présente dans l'archive | Aucune protection consommateur intégrée n'est fournie ; ajoutez des règles de conservation au niveau de l'hôte uniquement lorsque la réflexion à l'exécution, le JNI, la sérialisation ou d'autres symboles accédés dynamiquement nécessitent une préservation explicite |
(Remarque sur les règles de sérialisation Gson : comme indiqué dans le Guide de dépannage Gson pour ProGuard et R8, les versions 2.11.0 et ultérieures de Gson intègrent des règles R8 pour TypeToken et les champs annotés avec @SerializedName. Ces règles n'éliminent pas la nécessité de restreindre l'accès réflectif aux modèles, de fournir des constructeurs sans argument compatibles ou de tester tous les chemins de sérialisation et de désérialisation dans les builds de release minifiés.)
Inspecter votre archive SDK téléchargée avant d'écrire des règles
La correspondance des règles ProGuard et R8 est strictement sensible à la casse et exige un chemin de package exact. Selon les versions du SDK ou les distributions régionales, les espaces de noms des packages peuvent varier — et si vous copiez une règle issue d'un ancien tutoriel dont les majuscules/minuscules ne correspondent pas aux fichiers .class réels de votre archive, R8 n'appliquera la règle à aucune classe, sans émettre d'alerte.
Avant de modifier vos règles de conservation, téléchargez votre package SDK cible (tel que le SDK Android v2.1.0 depuis le centre de téléchargement de SDK mobiles) et inspectez ses règles intégrées (à la fois dans /proguard.txt et à l'intérieur de classes.jar) ainsi que sa hiérarchie exacte de fichiers .class :
# 1. Inspect an .aar archive for root consumer rules (proguard.txt) and extract classes.jar to check META-INF rules
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. If using a standalone .jar archive, inspect embedded META-INF rules and exact case-sensitive .class paths
jar tf libs/OpoInstall_SDK.jar | grep -E "META-INF/proguard/|META-INF/com\.android\.tools/|\.class$"
Configurer proguard-rules.pro pour les SDK Android d'attribution
Éviter les anti-patterns de conservation globale de packages et les suppressions génériques d'avertissements
Lors de la rédaction de règles personnalisées, les ingénieurs doivent suivre les bonnes pratiques de Google détaillées dans Choisir quoi conserver (Règles de conservation R8) afin d'éviter de désactiver inutilement l'optimisation :
- Préférer des règles ciblées aux anti-patterns globaux
-keep class package.** { *; }: Une règle globale à l'échelle d'un package force R8 à conserver et à ignorer l'optimisation sur chaque classe utilitaire interne de ce package. Limitez vos règles aux classes spécifiques, aux constructeurs (<init>();), aux interfaces de callback, aux cibles JNI et aux champs de modèles accédés dynamiquement à l'exécution (ou utilisez l'annotation@UnconditionallyKeepde Jetpack sur le code que vous contrôlez). - Distinguer
-keepde-keepclassmemberssur les modèles de données :-keepclassmembersne préserve les champs ou méthodes spécifiés que si la classe englobante elle-même est retenue dans le graphe d'appels. Si un modèle de données (tel queOpoData) est instancié uniquement par réflexion ou référencé uniquement via des types génériques effacés, utilisez-keep class ...afin que R8 ne supprime pas la classe elle-même. - Comprendre les limites de
-keepclasseswithmembernamespour le JNI : Les règles d'optimisation par défaut d'Android incluent-keepclasseswithmembernames,includedescriptorclasses class * { native <methods>; }. Comme défini dans la documentation des règles de conservation R8 de Google et dans le Manuel ProGuard sur les directives Keep,-keepclasseswithmembernameséquivaut à-keepclasseswithmembers,allowshrinking. Elle préserve les noms des classes et des membres correspondants qui survivent à la phase de réduction, mais n'empêche pas la suppression des classes ou des méthodesnativenon référencées lors de la réduction. Si des méthodes natives sont enregistrées dynamiquement viaRegisterNativessans points d'appel Java directs, ou si du code C/C++ invoque des méthodes Java via des appels montants JNI, vous devez utiliser des règles explicites-keepou-keepclassmembersselon la manière dont la classe cible est instanciée. - Éviter les directives globales
-dontwarnnon vérifiées :-dontwarnn'offre aucune protection contre la réduction ou le renommage et masque les avertissements de références non résolues qui peuvent cacher des plantagesNoClassDefFoundErrorà l'exécution. N'ajoutez un-dontwarnstrictement ciblé que si votre journal de compilation signale une classe spécifique manquante, utilisée uniquement à la compilation, et dont vous avez vérifié le caractère facultatif à l'exécution.
| Directive ProGuard / R8 | Syntaxe longue équivalente | Réduction (Suppression) | Obfuscation (Renommage) | Portée d'ingénierie recommandée |
|---|---|---|---|---|
-keep class ... |
-keep |
Empêchée (Classe et membres spécifiés conservés) | Empêchée (Noms d'origine conservés) | Points d'entrée publics du SDK, interfaces de callback et classes instanciées dynamiquement via réflexion ou JNI (inclure <init>(...);) |
-keepclassmembers class ... |
-keepclassmembers |
Membres conservés uniquement si la classe est retenue | Empêchée pour les membres correspondants | Préservation des <fields>; ou des méthodes d'appel montant JNI sur les classes déjà directement instanciées en Java/Kotlin |
-keepclasseswithmembernames |
-keepclasseswithmembers,allowshrinking |
Autorisée si non référencée (allowshrinking) |
Empêchée si la classe et les membres survivent à la réduction | Préservation par défaut des noms d'appels descendants JNI (native <methods>;) lorsque le code Java invoque directement la méthode native |
-keepnames class ... |
-keep,allowshrinking |
Autorisée si non référencée (allowshrinking) |
Empêchée si la classe est retenue | Conserver des noms de classes lisibles pour les traces de pile (stack traces) sans forcer l'inclusion de classes inutilisées dans classes.dex |
-keepattributes ... |
-keepattributes |
Préserve les métadonnées sur les éléments conservés | N/A (Attribut de bytecode) | Conservation de Signature (génériques), InnerClasses, EnclosingMethod et *Annotation* sur les classes explicitement conservées |
-dontwarn <specific_class> |
-dontwarn |
Aucun effet sur la réduction | Aucun effet sur le renommage | Suppression des avertissements de compilation uniquement pour une dépendance optionnelle vérifiée, utilisée seulement à la compilation |
Configurer Gradle sur les chaînes d'outils AGP 8.x et AGP 9.3+
L'Android Gradle Plugin 9.3 a introduit un bloc DSL optimization simplifié ainsi que des répertoires keepRules spécifiques aux variantes (fichiers .keep), tandis que les versions AGP 8.x à 9.2 (et les configurations historiques toujours prises en charge dans AGP 9.3+) utilisent isMinifyEnabled et proguardFiles. Les ingénieurs doivent bien distinguer trois objets de configuration :
| Objet de configuration | Emplacement du fichier ou du DSL | Rôle architectural dans les builds R8 |
|---|---|---|
| Règles de conservation du DSL historique (AGP 8.x–9.2 & Historique 9.3+) | app/proguard-rules.pro (référencé via proguardFiles(...)) |
Déclare les règles de conservation de l'hôte aux côtés de getDefaultProguardFile("proguard-android-optimize.txt") |
| Règles de conservation du nouveau DSL d'optimisation (AGP 9.3+) | app/src/main/keepRules/*.keep ou app/src/<variant>/keepRules/*.keep |
Déclare les fichiers .keep lors de l'utilisation de optimization { enable = true } (les règles par défaut de la plateforme Android sont appliquées automatiquement ; le DSL historique prend également en charge les ensembles de sources .keep) |
| Directives de rapport de diagnostic R8 | -printseeds, -printusage, -printconfiguration dans un fichier de configuration R8 vérifié (proguard-rules.pro) |
Demande à R8 d'émettre des rapports d'audit dans app/build/outputs/mapping/<buildVariant>/ |
// Option A: AGP 8.x - 9.2 Legacy DSL (also supported in AGP 9.3+) — app/build.gradle.kts
android {
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
// Option B: AGP 9.3+ Simplified Optimization DSL — app/build.gradle.kts
// Place scoped class/member keep rules in app/src/main/keepRules/sdk-attribution.keep
android {
buildTypes {
release {
optimization {
enable = true
}
}
}
}
Exemples de règles de conservation ciblées et de directives de diagnostic
Étant donné que la documentation publique d'OpoInstall et les anciennes pages de FAQ font référence à différents préfixes de packages (com.opoinstall.api.** contre com.fm.OpoInstall.** ou io.OpoInstall.**), l'ensemble de règles ci-dessous est fourni à titre d'exemple uniquement — il ne s'agit pas d'un ensemble de règles de production vérifié pour le SDK OpoInstall v2.1.0. Inspectez d'abord les chemins de classes réels et les règles consommateur intégrées dans votre archive v2.1.0 téléchargée, et consultez la documentation technique d'OpoInstall (voir Comment les kits de développement logiciel propulsent l'attribution et la croissance mobiles pour le code Java sous-jacent du cycle de vie) :
# File: app/src/main/keepRules/sdk-attribution.keep (or app/proguard-rules.pro)
# IMPORTANT: Illustrative only — not a verified production rule set for OpoInstall SDK v2.1.0.
# Verify exact case-sensitive package and class names inside your downloaded v2.1.0 archive
# via `jar tf` or `apkanalyzer`, and check `configuration.txt` for existing consumer rules.
# ---------------------------------------------------------------------------
# 1. Preserve Bytecode Attributes on Explicitly Kept Classes
# Required so generic callback interfaces (e.g., ResultCallBack<OpoData>)
# retain their parameterized type metadata in R8 Full Mode.
# ---------------------------------------------------------------------------
-keepattributes Signature, InnerClasses, EnclosingMethod, *Annotation*
# ---------------------------------------------------------------------------
# 2. Scoped SDK Entry Point, Callback Interface, and Data Model Rules
# ---------------------------------------------------------------------------
# Preserve public SDK entry point and any reflectively invoked constructors/methods:
-keep public class com.opoinstall.api.OpoInstall {
<init>(...);
public <methods>;
}
# Preserve callback listener interfaces and their callback methods:
-keep public interface com.opoinstall.api.ResultCallBack {
public <methods>;
}
# Model Scenario A: If OpoData / OpoError models are instantiated dynamically via reflection
# or referenced only via erased generics, use -keep to preserve both the class and its members:
-keep class com.opoinstall.api.OpoData {
<init>(...);
<fields>;
public <methods>;
}
-keep class com.opoinstall.api.OpoError {
<init>(...);
<fields>;
public <methods>;
}
# Model Scenario B: If a model class is already directly retained in your host call graph
# and only its fields require protection from renaming, use -keepclassmembers:
# -keepclassmembers class com.opoinstall.api.OpoData { <fields>; }
# ---------------------------------------------------------------------------
# 3. JNI Downcall and Native-to-Java Upcall Protection (Illustrative JNI Patterns)
# ---------------------------------------------------------------------------
# JNI Case A: If Java/Kotlin code already directly instantiates the JNI bridge class,
# use -keepclassmembers,includedescriptorclasses for C/C++ upcall methods, and keep
# any parameter model classes/constructors instantiated by native code:
-keepclassmembers,includedescriptorclasses class com.example.sdk.internal.JniBridge {
public void onNativeAttributionEvent(com.example.sdk.internal.NativeEventData);
}
-keep class com.example.sdk.internal.NativeEventData {
<init>(...);
}
# JNI Case B: If native C/C++ code dynamically looks up or instantiates the Java class
# itself via FindClass / NewObject, or registers native methods via RegisterNatives
# without direct Java call sites, use -keep to prevent class and method removal:
-keep,includedescriptorclasses class com.example.sdk.internal.DynamicNativeBridge {
<init>(...);
public native <methods>;
public void onNativeCallback(java.lang.String);
}
# File: app/proguard-rules.pro (Diagnostic Output Directives)
# Place R8 diagnostic report flags in your verified R8 configuration file.
# Paths resolve relative to the module working directory (`app/`).
# Adjust the directory name for product flavors (e.g., 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
Résoudre les conflits d'obfuscation et de renforcement des packages par canal Android
Séparer la compilation R8, l'alignement de l'APK, la signature et les packages par canal
Pour les distributions Android en dehors de Google Play, OpoInstall prend en charge l'exportation de packages par canal Android dédiés — en prenant un APK de base téléversé par le développeur et en générant des APK spécifiques à chaque canal contenant des métadonnées de suivi channelCode distinctes.
Lors du dépannage de statistiques de canal manquantes ou d'échecs d'installation sur des packages par canal exportés, les ingénieurs doivent séparer deux critères de vérification de release indépendants : la validité de la signature cryptographique de l'APK et l'intégrité des métadonnées de canal du fournisseur :
- Réduction du code R8 à la compilation : R8 s'exécute au sein du pipeline de build Gradle lors de la compilation du bytecode Java/Kotlin en
classes.dexavant que l'APK de base ne soit empaqueté et signé. R8 n'est jamais exécuté sur un APK déjà exporté. - Alignement de l'APK Android (
zipalign) et signature cryptographique (apksigner) : Les APK de release standards générés par AGP sont alignés automatiquement. Cependant, si votre pipeline de release applique un post-traitement personnalisé ou un renforcement (hardening) d'APK tiers avant la signature, vous devez réaligner l'APK conformément aux spécifications officielles Androidzipalignet aux spécifications Androidapksigner.zipalignaligne les données non compressées sur des limites de 4 octets — et si l'APK contient des bibliothèques natives.sonon compressées, les équipes doivent utiliserzipalign -P 16 -f -v 4 infile.apk outfile.apkpour satisfaire aux exigences d'alignement de page de 16 Ko et vérifier l'alignement aveczipalign -c -P 16 -v 4.zipaligndoit être exécuté avant la signature avecapksigner, car la modification d'un APK après sa signature invalide sa signature cryptographique globale V2/V3. - Métadonnées de canal spécifiques au fournisseur et vérification de la signature : L'exécution d'outils tiers de renforcement (packing) ou de reconditionnement d'APK après l'exportation d'un APK de canal depuis la console OpoInstall peut écraser les métadonnées de canal intégrées ou invalider la signature de l'APK. Si un analyseur de package de canal tiers nécessite un schéma de signature d'APK spécifique (tel que l'activation de la signature JAR V1 aux côtés de la signature globale d'APK V2/V3), vérifiez directement cette exigence auprès de la documentation actuelle de votre console OpoInstall ou du support fournisseur avant de modifier les configurations de signature en production, et ne considérez pas la signature V1 comme une exigence universelle du système d'exploitation Android.
L'ordre recommandé du pipeline de release pour les packages par canal Android
Pour maintenir des signatures d'APK valides, l'optimisation du bytecode R8 et des métadonnées de canal fournisseur intactes, exécutez votre pipeline de release dans cet ordre strict :
- Compiler et minifier l'APK de base avec R8 : Exécutez
./gradlew :app:assembleReleaseavec vos règles de conservation vérifiées afin que R8 optimiseclasses.dexau moment de la compilation. - Effectuer tout renforcement, alignement et signature avant le téléversement : Si votre équipe de sécurité utilise des outils tiers de renforcement d'APK, appliquez-les à l'APK de base, exécutez
zipalign -P 16 -f -v 4(si un réalignement est requis avant la signature), vérifiez l'alignement aveczipalign -c -P 16 -v 4, puis signez l'APK de base. - Téléverser l'APK de base et vérifier indépendamment les APK de canal exportés : Téléversez l'APK de base signé et obfusqué sur la console OpoInstall, exportez les APK de canal, et vérifiez indépendamment à la fois la validité de la signature cryptographique (
apksigner verify --verbose) et l'attribution de canal sur un appareil physique avec l'APK exporté avant toute distribution publique.
[Recommended Channel Package Pipeline]: Source Code -> Gradle R8 Minification -> (Optional Pre-Upload Hardening + zipalign -P 16 + Signing) -> Upload Base APK to Console -> Export Channel APK -> Verify Both Signature (apksigner) & Channel Callback
Auditer les symboles SDK préservés à l'aide des rapports R8 et d'APK Analyzer
Utiliser l'analyseur de configuration R8 autonome dans AGP 9.3+
Dans l'Android Gradle Plugin 9.3 et les versions ultérieures, vous n'avez pas besoin d'attendre la compilation complète d'un APK de release ou d'un App Bundle pour auditer la manière dont vos règles de conservation fusionnent et s'appliquent. AGP 9.3+ fournit une tâche Gradle dédiée analyze<Variant>R8Config (par exemple, ./gradlew :app:analyzeReleaseR8Config), qui évalue rapidement les règles de conservation consommateur et hôte et génère des diagnostics de configuration afin que les ingénieurs puissent itérer sur les règles .keep avant de lancer un build de release complet.
Vérification croisée de configuration.txt, seeds.txt, usage.txt et mapping.txt

Ne supposez jamais qu'une règle -keep a fonctionné simplement parce que ./gradlew :app:assembleRelease s'est terminé sans erreur de compilation. Pour vérifier votre configuration de manière déterministe, inspectez les quatre fichiers de diagnostic R8 générés dans app/build/outputs/mapping/<buildVariant>/ (utilisez -whyareyoukeeping class <ClassName> pour déboguer la raison pour laquelle un symbole spécifique a été retenu) :
configuration.txt: Contient l'ensemble complet des règles fusionnées appliquées par R8 — combinant les règles de conservation de votre hôte, les règles par défaut de la plateforme Android, les règles AAPT2 et toutes les règles/proguard.txtou/META-INF/intégrées dans les bibliothèques.aaret.jarliées.seeds.txt: Liste chaque classe, constructeur (<init>()), méthode et champ correspondant à vos règles-keepactives. Notez que la présence dansseeds.txtconfirme la syntaxe de la règle, mais doit être associée à une inspection DEX et à des tests à l'exécution.usage.txt: Liste le code mort que R8 a supprimé de l'APK lors du tree-shaking. Confirmez qu'aucune des classes requises de votre SDK, constructeurs réflectifs ou méthodes d'appel montant JNI n'apparaît dansusage.txt.mapping.txt: Enregistre la table de correspondance des identifiants avant et après renommage pour les classes et membres retenus. Notez que l'absence d'une classe dansmapping.txtne prouve pas qu'elle a été préservée sous son nom d'origine — elle peut avoir été complètement supprimée lors de la réduction (et listée dansusage.txt). Effectuez toujours une vérification croisée demapping.txtavecseeds.txt,usage.txtet le fichier DEX compilé.
Vérifier les identifiants DEX bruts par rapport aux états des rapports désobfusqués avec apkanalyzer
Lorsque vous utilisez l'outil officiel en ligne de commande APK Analyzer de Google Android Developers pour inspecter votre APK de release, faites la distinction entre les identifiants DEX compilés bruts et les noms désobfusqués via le fichier de mapping :
- Inspection des noms DEX compilés bruts (sans
--proguard-mappings) : Lorsque vous passez l'argument--proguard-mappings mapping.txtàapkanalyzer, l'outil reconvertit les noms DEX obfusqués (tels quea.b.c) en leurs noms sources d'origine pour l'affichage. Par conséquent, voir un nom de classe d'origine lorsque--proguard-mappingsest activé ne prouve pas que le symbole a échappé au renommage dansclasses.dex. Exécutez d'abordapkanalyzer dex packagessans--proguard-mappings. Comme le reconditionnement de classes de R8 peut également déplacer des classes dans des chemins de packages aplatis, ne vous fiez pas uniquement à ungrepsur le nom du package ; inspectez l'arborescence brute des classes DEX, vérifiez les noms des classes de points d'entrée appelées par réflexion, contrôlez les noms des méthodes JNI et les signatures de descripteurs, et recoupez avecmapping.txtpour confirmer que les méthodes et champs requis n'ont pas été renommés. - Inspection des états de rétention R8 (avec
--proguard-mappings,--proguard-seedset--proguard-usages) : Lors d'une seconde passe, fournissez les trois fichiers de rapport R8 pour reconstruire les indicateurs de rétention (kpour conservé par une règle seed,xpour supprimé lors de la réduction,rpour référencé etdpour défini) sur chaque package (P), classe (C), méthode (M) et champ (F) :
# Run from the Android project root directory (adjust variant path for product flavors, e.g., prodRelease)
# 1. (AGP 9.3+) Run the standalone R8 configuration analyzer for rapid rule verification, then build release APK
./gradlew :app:analyzeReleaseR8Config
./gradlew :app:assembleRelease
# 2. Inspect the merged R8 configuration, matched seeds, and stripped usage reports
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. Inspect RAW compiled DEX identifiers (WITHOUT --proguard-mappings)
# Also inspect the full raw DEX tree and cross-check mapping.txt in case R8 repackaged classes
apkanalyzer dex packages app/build/outputs/apk/release/app-release.apk | grep -i "opoinstall"
# 3B. Inspect R8 retention state flags (k = kept, x = removed, r = referenced, d = defined) WITH R8 report files
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. Verify 16 KB page alignment (if native .so files are present) and cryptographic APK signatures
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
Matrice de dépannage de l'attribution sur les builds de release
Diagnostiquer les échecs silencieux d'attribution et de deep linking dans les builds Android minifiés
Lors du dépannage d'écarts d'attribution qui ne se produisent que dans les builds de release minifiés, utilisez la matrice de diagnostic ci-dessous pour isoler la cause principale :
| Symptôme observé en release | Cause principale probable liée à R8 / au build | Étape de vérification diagnostique | Action corrective |
|---|---|---|---|
Le callback getInstallParam ou handleDeepLink ne se déclenche jamais en build de release |
Les classes de point d'entrée du SDK, les constructeurs réflectifs <init>() ou les méthodes ResultCallBack ont été supprimés ou renommés en raison d'une non-correspondance de package |
Vérifier seeds.txt et usage.txt ; inspecter la sortie brute de apkanalyzer dex packages (sans --proguard-mappings) et mapping.txt |
Inspecter le .jar / .aar avec jar tf pour trouver les chemins de classes exacts sensibles à la casse et ajouter des règles -keep ciblées incluant <init>(...); |
Le callback se déclenche, mais les paramètres personnalisés OpoData sont analysés comme vides ou nuls |
OpoData n'était protégé qu'avec -keepclassmembers (permettant la suppression de la classe elle-même) ou les métadonnées génériques Signature ont été perdues |
Vérifier usage.txt et mapping.txt pour OpoData et vérifier la présence de -keepattributes Signature dans configuration.txt |
Utiliser -keep class ... (si OpoData est instancié par réflexion) avec <init>(...); <fields>; et conserver -keepattributes Signature |
UnsatisfiedLinkError ou callback natif manquant lorsque le SDK charge la bibliothèque .so |
Les appels descendants RegisterNatives enregistrés dynamiquement ont été réduits ou les méthodes cibles d'appel montant C/C++ vers Java ont été renommées par R8 |
Inspecter logcat pour trouver le symbole JNI exact manquant et vérifier la sortie brute de apkanalyzer dex packages ainsi que mapping.txt pour la classe Java cible |
Utiliser -keep (ou -keepclassmembers si la classe de pont est directement instanciée en Java) avec includedescriptorclasses sur les cibles d'appel montant JNI et RegisterNatives |
| Le package par canal Android exporté échoue à l'installation ou perd les statistiques de canal | Une modification de l'APK après exportation a invalidé la signature de l'APK ou écrasé les métadonnées de canal intégrées | Exécuter zipalign -c -P 16 -v 4 et apksigner verify --verbose sur l'APK de canal exporté et tester sur un appareil physique |
Effectuer toute la minification R8, le renforcement, l'alignement et la signature sur l'APK de base avant de le téléverser sur la console ; vérifier à la fois la signature et l'attribution après l'exportation |
Foire aux questions (FAQ)
Comment exclure un SDK mobile de l'obfuscation Android ProGuard et R8 ?
Comment vérifier que les classes de mon SDK Android ont bien été exclues de l'obfuscation R8 ?
Pourquoi les statistiques des packages par canal Android cessent-elles de fonctionner après le renforcement ou le post-traitement de l'APK ?
Résumé et liste de contrôle de vérification du build de release
Comprendre comment exclure les SDK mobiles de l'obfuscation Android ProGuard et R8 est essentiel pour prévenir les régressions d'attribution silencieuses lors du passage des tests de debug aux builds de release en production. En vérifiant les règles consommateur intégrées, en rédigeant des directives -keep strictement ciblées qui correspondent aux chemins de classes exacts (sensibles à la casse) à l'intérieur de votre archive SDK, en respectant l'ordre de compilation préalable au téléversement pour les packages par canal Android, et en recoupant les fichiers de diagnostic R8 avec le bytecode DEX brut, les ingénieurs Android peuvent maintenir une réduction complète du code sans interrompre le deferred deep linking ni la restauration des paramètres.
Avant de publier un build de release Android minifié sur Google Play ou d'exporter des packages par canal, exécutez cette liste de contrôle de vérification en quatre étapes :
-
Inspecter l'archive SDK et la configuration fusionnée : Vérifiez votre archive SDK téléchargée (telle que la v2.1.0) avec
jar tfouunzip -lpour inspecter les chemins de classes exacts et les règles consommateur intégrées, puis exécutez./gradlew :app:analyzeReleaseR8Config(dans AGP 9.3+) ou examinezconfiguration.txt. -
Recouper les rapports R8 et les identifiants DEX bruts : Confirmez que les points d'entrée requis du SDK, les constructeurs réflectifs
<init>(), les champs du modèleOpoData, les méthodesResultCallBacket les signatures JNI apparaissent dansseeds.txt, sont absents deusage.txtet conservent leurs noms d'origine dans la sortie brute deapkanalyzer dex packages(exécuté sans--proguard-mappings) et dansmapping.txt. -
Appliquer la minification avant le téléversement et vérifier les signatures des APK de canal : Terminez toute la minification R8, tout renforcement tiers, l'alignement
zipalign(zipalign -c -P 16 -v 4) et la signature d'APK sur l'APK de base avant de le téléverser pour exporter des packages par canal Android, et exécutezapksigner verify --verbosesur les packages exportés. -
Exécuter un test de validation (smoke test) de release sur appareil physique : Installez l'APK de release signé et minifié sur un appareil Android réel et vérifiez à la fois l'installation avec paramètres H5 (
getInstallParam) et l'ouverture directe par lien (handleDeepLink).
Les équipes d'ingénierie peuvent enregistrer une application et téléverser leur APK de base obfusqué sur la console développeur OpoInstall pour tester l'exportation de packages par canal et vérifier la restauration des paramètres sur un build de release.
Ressources associées
-
Concepts : Réduction de code Android R8, Obfuscation des identifiants, Règles ProGuard consommateur, Ordre de compilation des packages par canal
-
Technologies : Android Gradle Plugin (AGP), Compilateur R8,
proguard-rules.pro, Android Studio APK Analyzer -
Standards : Projet de sécurité des applications mobiles OWASP
-
Interfaces de plateforme et d'intégration :
isMinifyEnabled,optimization.enable,analyzeReleaseR8Config,consumerProguardFiles,seeds.txt,usage.txt,apkanalyzer dex packages,apksigner,zipalign -
Documentation officielle et références :
-
Guide Google Android Developers sur le choix des éléments à conserver (Règles de conservation R8)
-
Guide Google Android Developers sur les fichiers ProGuard consommateur des bibliothèques Android
-
Guide Google Android Developers sur l'outil en ligne de commande APK Analyzer
-
Manuel Guardsquare ProGuard sur l'utilisation de la configuration
Share this article



