65 votes

L'ensemble d'applications Android introduit un crash de ressource non trouvée dans l'application Android

En utilisant le nouveau Android App Bundle d'Android, j'ai reçu une erreur Ressource non trouvée dans 2 de mes applications du Google Play Store.

Voici la trace de la pile depuis Fabric pour l'une des applications :

Impossible de démarrer l'activité ComponentInfo{/com.Lastyear.MainActivity} : android.content.res.Resources$NotFoundException: Fichier res/drawable/abc_item_background_holo_dark.xml à partir de l'ID de ressource drawable #0x7f08002c
       à android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2377)
       à android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2429)
       à android.app.ActivityThread.access$800(ActivityThread.java:151)
       à android.app.ActivityThread$H.handleMessage(ActivityThread.java:1342)
       à android.os.Handler.dispatchMessage(Handler.java:110)
       à android.os.Looper.loop(Looper.java:193)
       à android.app.ActivityThread.main(ActivityThread.java:5363)
       à java.lang.reflect.Method.invokeNative(Method.java)
       à java.lang.reflect.Method.invoke(Method.java:515)
       à com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
       à com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
       à dalvik.system.NativeStart.main(NativeStart.java)

build.gradle dépendances :

 dépendances {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:customtabs:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.squareup.picasso:picasso:2.5.2'

implementation 'com.android.support:palette-v7:27.1.1'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.android.support:design:27.1.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.github.hotchemi:android-rate:1.0.1'
implementation 'com.hannesdorfmann.smoothprogressbar:library:1.0.0'
implementation 'com.android.support:palette-v7:27.1.1'
implementation 'com.google.android.gms:play-services-ads:15.0.1'
implementation 'com.muddzdev:styleabletoast:1.0.9'
implementation 'com.github.GrenderG:Toasty:1.2.5'
implementation 'com.hannesdorfmann.smoothprogressbar:library:1.0.0'

implementation 'com.wang.avi:library:2.1.3'
implementation 'com.github.medyo:fancybuttons:1.8.4'
implementation 'com.irozon.sneaker:sneaker:1.0.1'
implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'

implementation 'com.getkeepsafe.taptargetview:taptargetview:1.11.0'

implementation('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
    transitive = true;
}

implementation 'petrov.kristiyan:colorpicker-library:1.1.8'}

Autre chose, cela se produit uniquement sur le système d'exploitation Android 4, pas sur les versions plus récentes d'Android. J'ai constaté que d'autres applications rencontrent le même problème de Ressource non trouvée, qui n'existait pas avant d'utiliser Android App Bundle. Y a-t-il un problème dans la bibliothèque ou le code ou est-ce dû à la version bêta de Android App Bundle ?

J'ai également trouvé la ressource drawable à l'origine du crash : Capture d'écran montrant la ressource drawable en surbrillance qui cause le problème.

Je pense que cette question est aussi liée à celle-ci : Erreur de ressource non trouvée res/drawable/abc_switch_thumb_material.xml après avoir ajouté SwitchCompat dans Android App Bundle

1 votes

Vous pouvez essayer de reproduire le problème localement en utilisant bundletool et un émulateur avec les spécifications correspondant au périphérique qui rencontre le crash. Ajouter un peu plus de contexte, comme les dépendances et la structure potentielle des modules, permet de mieux comprendre ce qui se passe ici.

0 votes

J'ai essayé de reproduire l'erreur en utilisant bundletool mais je n'ai pas réussi sur aucun appareil testé. En attendant, j'ai ajouté la capture d'écran et les dépendances.

0 votes

Je sais que c'est un peu tard maintenant, mais comment as-tu réussi à télécharger le fichier aab sur Firebase ?

49voto

Nick Fortescue Points 7259

Il s'agit très probablement des utilisateurs qui partagent (sideload) l'application, soit via des programmes de partage P2P, soit en téléchargeant l'APK sur le web pour que d'autres utilisateurs la téléchargent et l'installent depuis le web.

Les personnes habituées aux applications non Android App Bundle transfèrent simplement et partagent le principal APK. Mais votre application Android bundle a de nombreux "split APKs" pour des éléments tels que les ressources, c'est ainsi que se réalise l'économie de taille. Vous pouvez en apprendre davantage sur ce processus sur la page d'aide . Si un utilisateur installe le principal APK sans installer les bons split APKs, un crash "Ressources introuvables" se produira la première fois que l'application tentera de charger une ressource.

Si vous souhaitez prendre en charge les utilisateurs qui chargent latéralement votre application et seulement le principal APK, vous pouvez essayer de détecter cette situation et afficher un message à l'utilisateur (sans utiliser de ressources) indiquant "Veuillez installer depuis Google Play". Ou vous pourriez simplement décider de ne pas prendre en charge les utilisateurs qui partagent des APK de cette manière.

Je soupçonne qu'à terme, les sites web et les programmes de partage P2P s'amélioreront dans le partage de tels APK de manière correcte, donc je ne m'inquiéterais pas trop longtemps à ce sujet.

Si vous constatez que cela se produit beaucoup plus fréquemment sur des versions Android inférieures, il s'agit probablement non pas d'un bug dans les versions Android inférieures, mais plutôt parce que dans des pays où les utilisateurs partagent souvent des applications en P2P (comme l'Inde), les utilisateurs sont également beaucoup plus susceptibles d'utiliser des téléphones de versions plus anciennes.

0 votes

Est-ce qu'il y a un moyen de détecter le chargement latéral? J'ai eu des problèmes similaires et j'ai dû distribuer des APK au lieu de des bundles. Les crashes rapportés (et les e-mails reçus à ce sujet) sont chronophages et perturbateurs. Il n'y a aucun moyen de déterminer facilement si l'utilisateur se plaint à cause d'un bug dans l'application ou d'un problème lié au bundle / chargement latéral. Je considérerais cela comme un défaut dans la conception des bundles car ils auraient dû envisager cela et fournir un mécanisme intégré pour détecter cela (et éventuellement télécharger automatiquement les APK restants ou afficher une belle erreur).

0 votes

0 votes

Non ce n'est pas. J'ai le même problème exact et je connecte le paquet d'installation, il est correctement défini sur 'com.android.vending'

29voto

EAK TEAM Points 263

Cela est un peu tardif mais Google a introduit une nouvelle API pour la prévention des crashes lors du Sideloading, qui vous permet de détecter une installation incomplète d'applications construites en utilisant un Android App Bundle.

Par exemple, considérez une application qui utilise des Android App Bundles pour optimiser la taille du téléchargement de l'application en utilisant des APKs divisés. Lorsqu'un utilisateur télécharge l'application depuis le Google Play store, il s'assure que l'appareil télécharge et installe l'ensemble complet d'APKs divisés nécessaires pour exécuter cette application sur ce dispositif particulier. Lorsque vous contournez le Google Play pour sideloader une application, la plateforme n'a pas suffisamment de données pour valider l'installation de l'application, et la fonctionnalité correcte de l'application n'est pas garantie.

Tout d'abord, incluez la bibliothèque Play Core 1.6.0 ou supérieure dans votre projet.

Incluez ce qui suit dans le fichier build.gradle de votre projet d'application :

buildscript {
    dependencies {
        ...
        // Utilisez bundletool 0.9.0 ou plus lorsque vous construisez avec le
        // plug-in Android Gradle.
        classpath 'com.android.tools.build:bundletool:0.9.0'
    }
}

Vous pouvez utiliser 1 de ces 3 méthodes ci-dessous

1) Enregistrer des vérifications via le manifeste

    ...

2) Appliquer des vérifications dans une classe Application personnalisée

public class MyCustomApplication extends Application {
    @Override
    public void onCreate() {

        if (MissingSplitsManagerFactory.create(this).disableAppIfMissingRequiredSplits()) {
            // Ignorer l'initialisation de l'application.
            return;
        }

        super.onCreate();
        ...
    }
}

3) Appliquer des vérifications aux fournisseurs de contenu

public class ExampleProvider extends ContentProvider {
    @Override
    public boolean onCreate() {

        if (MissingSplitsManagerFactory.create(getContext()).isMissingRequiredSplits()) {
            // Ignorer l'initialisation du fournisseur.
            return false;
        }

        super.onCreate();
        ...
    }
}

En savoir plus : https://developer.android.com/reference/com/google/android/play/core/release-notes?hl=en-419#1-6-0

1 votes

Avez-vous essayé de le mettre en œuvre par vous-même? Avez-vous rencontré des problèmes avec cela? Parce que j'ai essayé et rencontré différents problèmes. Voici mon problème expliqué. Veuillez examiner cela et si vous avez une réponse, veuillez me le faire savoir. stackoverflow.com/questions/56725415/…

1 votes

Merci beaucoup! Ceci devrait être la nouvelle réponse acceptée :D

0 votes

@NaveenTP, je l'utilise depuis la publication de cette API, tout fonctionne correctement.

16voto

Oleksii Kropachov Points 1698

La réponse acceptée est absolument correcte - la source de ce problème est le chargement latéral du fichier APK.

Néanmoins, beaucoup de gens cherchent toujours une solution de contournement, demandant comment gérer correctement ce cas.

Dans mon application, j'ai fait ce qui suit :

  1. Créez une image de 1x1 nommée pixel.png et placez-la dans tous les dossiers suivants : drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-xxhdpi, drawable-xxxhdpi.

  2. Créez une Activity simple qui affiche un message statique, par exemple :

    Cette copie de l'application est corrompue et ne peut pas être lancée.

    Veuillez installer la version originale depuis Google Play

  3. Ensuite, appelez simplement getDrawable(R.drawable.pixel) depuis Activity.onCreate() enveloppé dans une clause try/catch.

  4. Si une exception est interceptée, terminez simplement l'Activity en cours et démarrez une autre à partir de l'étape n°2.

Fini !

Capture d'écran

Cette solution fonctionne bien, j'ai même des données de Firebase Analytics confirmant cela.

Sur les 46 000 nouveaux utilisateurs (événement first_open), 266 utilisateurs ont rencontré cette erreur (qui a été interceptée) et 221 utilisateurs ont cliqué sur le bouton qui mène à Google Play.

Voici mon code source (également disponible sur GitHub) :

DrawablesValidator.java

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget Space;
import android.widget.TextView;
import android.widget Toast;

public class DrawablesValidator extends Activity {
    public static void ensureDrawablesValid(@NonNull Activity activity) {
        try {
            // IMPORTANT créez une image de 1x1 nommée pixel.png et placez-la dans tous les dossiers
            //           drawable-mdpi
            //           drawable-hdpi
            //           drawable-xhdpi
            //           drawable-xxhdpi
            //           drawable-xxxhdpi
            activity.getDrawable(R.drawable.pixel);
        } catch (Resources.NotFoundException ex) {
            // REMARQUE facultativement, rappelez l'exception à Crashlytics ou simplement un événement à Analytics

            activity.finish();
            activity.startActivity(new Intent(activity, DrawablesValidator.class));
        }
    }

    // REMARQUE ne vous souciez pas des traductions des messages texte ici, ne les mettez pas dans strings.xml
    //      nous supposons que si l'utilisateur est assez intelligent pour obtenir l'APK depuis l'extérieur et l'installer,
    //      alors l'utilisateur comprendra certainement quelques messages en anglais :)
    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle state) {
        super.onCreate(state);

        int dp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
        int dp8 = dp * 8;
        int dp16 = dp * 16;
        int dp80 = dp * 80;

        LinearLayout root = new LinearLayout(this);
        root.setOrientation(LinearLayout.VERTICAL);
        root.setGravity(Gravity.CENTER_HORIZONTAL);
        root.setPadding(dp80, dp16, dp80, dp16);

        Space spaceTop = new Space(this);

        TextView title = new TextView(this);
        title.setPadding(0, dp8, 0, dp8);
        title.setTextSize(20);
        title.setText("Réinstaller l'application");

        TextView message = new TextView(this);
        message.setPadding(0, dp8, 0, dp8);
        message.setTextSize(16);
        message.setText("Cette copie de l'application est corrompue et ne peut pas être lancée." +
                "\n\n" +
                "Veuillez installer la version originale depuis Google Play");

        Button button = new Button(this);
        button.setPadding(dp16, dp8, dp16, dp8);
        button.setText("Continuer");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName())));
                } catch (Exception ex) {
                    Toast.makeText(getApplicationContext(), "Impossible d'ouvrir Google Play", Toast.LENGTH_SHORT).show();
                }
            }
        });

        Space spaceBottom = new Space(this);

        int wc = ViewGroup.LayoutParams.WRAP_CONTENT;
        int mp = ViewGroup.LayoutParams.MATCH_PARENT;

        root.addView(spaceTop, lp(0, 0, 1, -1));
        root.addView(title, lp(wc, wc, 0, -1));
        root.addView(message, lp(mp, wc, 0, -1));
        root.addView(button, lp(wc, wc, 0, Gravity.END));
        root.addView(spaceBottom, lp(mp, wc, 1, -1));

        setContentView(root);
    }

    private LinearLayout.LayoutParams lp(int width, int height, int weight, int gravity) {
        LinearLayout.LayoutParams result = new LinearLayout.LayoutParams(width, height);
        result.weight = weight;
        result.gravity = gravity;
        return result;
    }
}

14voto

Pierre Points 4658

Le problème est probablement que votre application a été chargée latéralement, c'est-à-dire qu'elle n'a pas été installée via le Play Store, et que des APK incompatibles ont été installés manuellement sur ces appareils.

0 votes

Non, il est peu probable que ce soit le problème car cela se produit uniquement sur Android 4.

0 votes

Ensuite, la recommandation de @keboardsurfer est la meilleure pour tenter de le reproduire.

0 votes

Je tente de le reproduire avec bundletool mais il renvoie une erreur "Impossible d'installer les APK découpés sur un appareil avec un niveau API inférieur à 21".

4voto

gautam kumar Points 472

Comme cela se produit uniquement sur les appareils Android 4 après la migration vers Android App Bundle, j'ai trouvé une solution après avoir ajouté :-

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); }

Et dans build.gradle :-

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

tel qu'expliqué dans ce post : - Utilisation des drawable vectoriels Android sur les crash pré-Lollipop

En ce qui concerne la deuxième question :- Erreur de ressource non trouvée res/drawable/abc_switch_thumb_material.xml après avoir ajouté SwitchCompat dans Android App Bundle

Comme cela se produit sur toutes les versions d'Android, j'ai installé latéralement l'APK et ai pu reproduire la même erreur dans le logcat. Cela ne peut être résolu qu'en supprimant le SwitchCompat de mon projet. Je sais que c'est un correctif temporaire et Google devrait certainement faire quelque chose à ce sujet pour qu'au moins le crash ne se produise pas après l'installation latérale de l'APK, peut-être rediriger vers le Play Store serait une meilleure option. Mais le crash de l'application après la migration vers Android App Bundle affecte certainement la stabilité de l'application car de nombreux utilisateurs le font régulièrement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X