web-dev-qa-db-fra.com

Pourquoi Android OS 8 WebView avec la balise de sélection HTML bloque-t-il l'application?

J'ai une application hybride Cordova Android et l'application se bloque lorsque l'utilisateur appuie sur une liste déroulante dans ma WebView sous Android OS 8. J'ai créé une simple page avec une balise <select> et le problème est reproductible. J'ai une solution de contournement qui consiste à créer ma propre alerte contextuelle, mais je me demande simplement si cela arrive à quelqu'un d'autre et s'il s'agit d'un bogue OS8 WebView.

Ci-dessous, une simple page avec la balise <select> 

https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_select

Ci-dessous mon journal des crashs

11:04:58.643 3208-3208/com.****.****E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.****.****, PID: 3208 Android.content.res.Resources$NotFoundException: Resource ID #0x0
    at Android.content.res.ResourcesImpl.getValue(ResourcesImpl.Java:195)
    at Android.content.res.Resources.loadXmlResourceParser(Resources.Java:2133)
    at Android.content.res.Resources.getLayout(Resources.Java:1142)
    at Android.view.LayoutInflater.inflate(LayoutInflater.Java:421)
    at Android.widget.ArrayAdapter.createViewFromResource(ArrayAdapter.Java:416)
    at Android.widget.ArrayAdapter.getView(ArrayAdapter.Java:407)
    at org.chromium.content.browser.input.SelectPopupAdapter.getView(SelectPopupAdapter.Java:53)
    at Android.widget.AbsListView.obtainView(AbsListView.Java:2372)
    at Android.widget.ListView.measureHeightOfChildren(ListView.Java:1408)
    at Android.widget.ListView.onMeasure(ListView.Java:1315)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:185)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:185)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1514)
    at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:806)
    at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:685)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:185)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:185)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:6580)
    at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:185)
    at com.Android.internal.policy.DecorView.onMeasure(DecorView.Java:721)
    at Android.view.View.measure(View.Java:21998)
    at Android.view.ViewRootImpl.performMeasure(ViewRootImpl.Java:2410)
    at Android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.Java:1471)
    at Android.view.ViewRootImpl.performTraversals(ViewRootImpl.Java:1751)
    at Android.view.ViewRootImpl.doTraversal(ViewRootImpl.Java:1386)
    at Android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.Java:6733)
    at Android.view.Choreographer$CallbackRecord.run(Choreographer.Java:911)
    at Android.view.Choreographer.doCallbacks(Choreographer.Java:723)
    at Android.view.Choreographer.doFrame(Choreographer.Java:658)
    at Android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.Java:897)
    at Android.os.Handler.handleCallback(Handler.Java:789)
    at Android.os.Handler.dispatchMessage(Handler.Java:98)
    at Android.os.Looper.loop(Looper.Java:164)
    at Android.app.ActivityThread.main(ActivityThread.Java:6541)
    at Java.lang.reflect.Method.invoke(Native Method)
    at com.Android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.Java:240)
    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:767)

Mon problème n'est pas le même que celui-ci 

Essayer d'ouvrir la balise SELECT dans Android WebView bloque l'application

MISE À JOUR DU 9 janvier 2018: Je n'ai pas encore de solution, ma solution temporaire consiste à supprimer la balise et à utiliser simplement une entrée. Lorsque l'utilisateur sélectionne cet élément, nous passons l'événement au code natif pour ouvrir une boîte de dialogue de sélection et mettre à jour l'entrée une fois que l'utilisateur a effectué une sélection.

MISE À JOUR DU 23 MARS 2018: Après une enquête plus approfondie, j'ai remarqué qu'elle se bloque uniquement si la WebView se trouve dans un fragment, mais pas dans une activité.

J'ai trouvé ci-dessous les commentaires de ce post:

Essayer d'ouvrir la balise SELECT dans Android WebView bloque l'application

"Lorsque l'utilisateur clique sur une balise SELECT, Android affiche en interne ses options à l'aide d'un AlertDialog natif. La vue Web doit être créée avec un contexte d'activité car l'instance d'AlertDialog a besoin d'un contexte d'activité."

Je crois que c'est un bug dans Android, probablement pas gérer correctement le contexte pour Fragment.

UPDATE 17 avril 2018:

Comme Kenyee l'a fait remarquer, à partir d'ici https://issuetracker.google.com/issues/77246450 , dit Google 

Vous ne devez pas sous-classer l'objet ressources - cela n'a jamais été pris en charge et n'a été possible que par accident (c'est pourquoi il est désormais marqué comme obsolète). L'infrastructure a besoin de connaître tous les objets de ressources pour pouvoir les mettre à jour lorsque la vue Web est chargée (car la vue Web ajoute des chemins d'accès supplémentaires au gestionnaire d'actifs).

Éditer le 29 novembre 2018 On dirait que cette question a dérangé beaucoup de gens. 

  • La solution que j'ai essayée et testée est de ne pas sous-classer la ressource.
  • Mettre à jour la compilation de sdk et la version de bibliothèque prise en charge a fonctionné pour certaines personnes.
  • L'ajout d'une classe wrapper à Resource peut fonctionner. J'ai essayé cette approche lors de mon enquête initiale. Elle résolvait le problème de plantage lié à la sélection. Elle restait toujours bloquée lorsque vous mainteniez enfoncé un affichage en mode texte pour faire apparaître les options "COPIER", "COLLER" . 
14
Dennis Hui

On dirait que ce bogue: https://issuetracker.google.com/issues/77246450

Ne pas sous-classer les ressources ... apparemment ne sera pas corrigé.

2
kenyee

J'ai le même problème sur Android 8.0. Enfin, je le résous. Essayez de mettre à jour votre compilation compileSdkVersion à 26, Et mettez à jour votre ordinateur de poche.Android.support:appcompat-v7 .

3
Steven Zhang

Si ce problème persiste, j’ai constaté que ce n’était même pas mon code qui sous-classait la classe Resources, mais plutôt la version de la bibliothèque de prise en charge de Google que j’utilisais. Mise à jour de la version de la bibliothèque de support et cela a fonctionné à merveille!

2
Arash Tadayon

Peut-être que vous utilisez custom ContextWrapper dans votre classe Activity. Dans mon cas, je remplace la méthode attachBaseContext. Vérifiez cette méthode et utilisez super.attachBaseContext(newBase).

0
rz0

Après une enquête, j'ai isolé le problème de WebView dans Fragment sur OS8 uniquement. Ma solution consiste à utiliser l'activité au lieu de fragment pour ce flux particulier. Il me semble un défaut d'Android dans Fragment.

0
Dennis Hui

Nous avons en fait trouvé une solution de contournement à ce problème il y a quelques temps nous permettant de continuer à sous-classer Resources et de ne pas bloquer nos WebViews. La mise en garde est que nous ne pouvons pas laisser notre WebView voir ou interagir avec notre sous-classe de ressources ET nous devons créer le WebView par programme. La première étape consiste à exposer une méthode dans la sous-classe Ressources pour extraire les ressources d'origine.

Disons que notre sous-classe de ressources s'appelle CustomResourcesWrapper et que notre sous-classe ContextWrapper s'appelle CustomContextWrapper.

Tout d'abord, nous mettons à jour la CustomResourcesWrapper afin de pouvoir accéder à l'objet Resources d'origine

public class CustomResourcesWrapper {

    public static Resources findOriginalResources(Context context) {
        if (context.getResources() instanceof CustomResourcesWrapper) {
            return ((CustomResourcesWrapper) context.getResources()).getOriginalResources();
        }
        if (context instanceof ContextWrapper) {
            return findOriginalResources(((ContextWrapper) context).getBaseContext());
        }
        return context.getResources();
    }

    private Resources getOriginalResources() {
        return originalResources;
    }
}

Nous supposons également que la variable CustomContextWrapper ressemble à ceci ...

public class CustomContextWrapper extends ContextWrapper {

    private final Resources wrappedResources;

    public CustomContextWrapper(Context base, Resources resources) {
        super(base);
        this.wrappedResources = resources;
    }

    @Override
    public Resources getResources() {
        return wrappedResources;
    }
}

Ensuite, nous créons une méthode d'assistance statique pour "décompresser" nos ressources personnalisées et les masquer.

// the method name is a bit of a misnomer, 
// we're actually unwrapping, then re-wrapping
public static Context unwrapCustomContext(Context wrapped) {
    Resources originalResources = CustomResourcesWrapper.findOriginalResources(wrapped);
    Context customUnwrappedContext = new CustomContextWrapper(wrapped, originalResources);
    return new ContextThemeWrapper(customUnwrappedContext, Android.support.v7.appcompat.R.style.Theme_AppCompat_Light);
}

Lorsque vient le temps de créer une vue Web, assurez-vous que la variable Context que nous lui avons transmise passe par la méthode ci-dessus, à savoir WebView webView = new WebView(unwrapCustomContext(context)). Je ne suis pas tout à fait sûr de savoir pourquoi, mais la ContextThemeWrapper est une partie obligatoire de ce hack.

0
Geoff

J'ai creusé dans les journaux de crash. Bien que cette réponse ne résolve pas votre problème, vous pouvez obtenir des informations utiles.

Je ne suis pas sûr de savoir pourquoi cela se produit sur Android 8.0, je ne pouvais pas le reproduire sur l'émulateur d'Android 8.0

0
Akhil