web-dev-qa-db-fra.com

Android P affichant un message d'erreur de compatibilité API

L'exécution d'une application construite avec le niveau de SDK 27 sur Android P affiche de manière assez imprévisible la boîte de dialogue suivante (le titre de la boîte de dialogue correspond au nom de l'application):

 Mysterious dialog

Problèmes détectés avec la compatibilité de l'API (visitez g.co/dev/appcompat pour plus d'informations)

L'URL mène à cette page sur les restrictions sur les interfaces non SDK . Mon application n'utilise pas la réflexion elle-même, mais Gson.

Il n'y a pas de message de journal immédiatement évident dans Logcat, à l'exception des messages tels que:

Accéder au champ caché Landroid/widget/AbsListView; -> mIsChildViewEnabled: Z (liste grise claire, réflexion)

6
Paul Lammertsma

Il s'avère que l'un de mes modèles Gson a exposé un getter qui a renvoyé File. Gson utilise la réflexion pour inspecter de manière récursive les champs de classes et viole ainsi la réflexion des interfaces SDK non autorisées.

La lecture du document de restriction lié à la question m'a amené à regarder de plus près les messages du journal, et bien sûr, l'un d'entre eux a attiré mon attention:

Accéder au champ caché [...] (liste grise sombre, réflexion)

Je ne me souviens pas exactement du message, mais le fait est que c'était dans la liste grise dark.

J'ai découvert cela en ciblant le SDK de niveau 28 et en activant la nouvelle fonctionnalité StrictMode detectNonSdkApiUsage(), sur laquelle mon application se bloquerait avec une trace de pile:

if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
            .detectNonSdkApiUsage()
            .penaltyLog()
            .build());
}

La trace de la pile n’était pas immédiatement intéressante, mais elle m’a orientée dans la bonne direction.

5
Paul Lammertsma

dans votre classe d'application dans la méthode onCreate () init cette méthode peut être fermer cette boîte de dialogue.

private void closeAndroidPDialog(){
    try {
        Class aClass = Class.forName("Android.content.pm.PackageParser$Package");
        Constructor declaredConstructor = aClass.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
    } catch (Exception e) {
        e.printStackTrace();
    }
    try {
        Class cls = Class.forName("Android.app.ActivityThread");
        Method declaredMethod = cls.getDeclaredMethod("currentActivityThread");
        declaredMethod.setAccessible(true);
        Object activityThread = declaredMethod.invoke(null);
        Field mHiddenApiWarningShown = cls.getDeclaredField("mHiddenApiWarningShown");
        mHiddenApiWarningShown.setAccessible(true);
        mHiddenApiWarningShown.setBoolean(activityThread, true);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

mais c'est dangereux De cette façon, vous ne pouvez pas voir le dialogue.

0
Ven Ren