Empêcher WebView d'afficher «page Web non disponible»

88

J'ai une application qui utilise largement une WebView. Lorsque l'utilisateur de cette application n'a pas de connexion Internet, une page indiquant «page Web non disponible» et divers autres textes apparaissent. Existe-t-il un moyen de ne pas afficher ce texte générique dans ma WebView? Je voudrais fournir ma propre gestion des erreurs.

private final Activity activity = this;

private class MyWebViewClient extends WebViewClient
 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
  // I need to do something like this:
  activity.webView.wipeOutThePage();
  activity.myCustomErrorHandling();
  Toast.makeText(activity, description, Toast.LENGTH_LONG).show();
 }
}

J'ai découvert que WebView-> clearView n'efface pas réellement la vue.

JoJo
la source
3
Pourquoi ne vérifiez-vous pas la connexion Internet avant d'afficher le WebView et s'il n'y a pas de service Internet disponible, vous pouvez ignorer l'affichage de WebView et à la place, vous pouvez afficher une alerte ou un toast sans message Internet?
Andro Selva
@JoJo pouvez-vous cocher une réponse comme correcte? probablement le mien: P
Sherif elKhatib

Réponses:

102

Créez d'abord votre propre page d'erreur en HTML et placez-la dans votre dossier assets, appelons-la myerrorpage.html Puis avec onReceivedError:

mWebView.setWebViewClient(new WebViewClient() {
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        mWebView.loadUrl("file:///android_asset/myerrorpage.html");

    }
});
SnowboardBruin
la source
27
L'ancienne page d'erreur «Page Web non chargée» s'affiche pendant une fraction de seconde avant d'être remplacée par la page d'erreur personnalisée des ressources
Cheenu Madan
1
D'accord avec Cheenu. Il doit y avoir une meilleure solution.
Jozua
3
1. Vous pouvez charger le contenu Web pendant que la WebView est invisible (et peut-être afficher une mauvaise progression dessus) et l'afficher si la page est chargée avec succès / charger "myerrorpage.html" en cas d'erreur. 2. Vous devez savoir que onReceiveError sera déclenché s'il y a des problèmes de chargement du problème OR dans JS qui s'exécute après le chargement de la page (comme les fonctions jQuery qui s'exécutent dans l'événement document.ready ()). Navigateur de bureau - autorisera l'erreur JS sans en informer l'utilisateur, comme le font les navigateurs mobiles.
FunkSoulBrother
5
ajoutez view.loadUrl("about:blank");avant loadUrl pour l'empêcher d'afficher la page d'erreur pendant une fraction de seconde.
Aashish
2
Où mettre ce fichier myerrorpage.html? Où se trouve ce dossier d'actifs Android?
Nived Kannada
34

La meilleure solution que j'ai trouvée est de charger une page vide dans l'événement OnReceivedError comme ceci:

@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
    super.onReceivedError(view, errorCode, description, failingUrl);

    view.loadUrl("about:blank");
}
7heViking
la source
Bonne idée! Dans mon cas, j'ai ajouté view.loadUrl(noConnectionUrl);deux fois (où noConnectionUrl est un fichier local avec un message d'erreur). Cela a également aidé à ne pas «voir» la page d'erreur intégrée pendant une fraction de seconde.
hQuse
4
Veuillez noter que, si vous manipulez, webView.goBack()assurez-vous de gérer la condition de cette page vierge. Sinon, votre page précédente sera chargée et en cas d'échec à nouveau, vous verrez à nouveau cette page vierge.
Chintan Shah
Alors, quelle est la meilleure façon de gérer cela?
MoSoli
@MoSoli Tout dépend de vos besoins. Une alternative à l'affichage d'une page vide serait d'afficher une interface utilisateur personnalisée ou une page Web en cache.
7heViking
10

Enfin, j'ai résolu ce problème. (Cela fonctionne jusqu'à présent ..)

Ma solution est comme ça ...

  1. Préparez la mise en page pour afficher lorsqu'une erreur s'est produite au lieu de la page Web (un 'message de page introuvable' sale) La mise en page a un bouton, "RELOAD" avec quelques messages de guide.

  2. Si une erreur s'est produite, n'oubliez pas d'utiliser boolean et affichez la mise en page que nous préparons.

  3. Si l'utilisateur clique sur le bouton "RELOAD", définissez mbErrorOccured sur false. Et définissez mbReloadPressed sur true.
  4. si mbErrorOccured est false et mbReloadPressed est true, cela signifie que la page Webview a été chargée avec succès. Parce que si l'erreur se reproduit, mbErrorOccured sera défini sur true sur onReceivedError (...)

Voici ma source complète. Regarde ça.

public class MyWebViewActivity extends ActionBarActivity implements OnClickListener {

    private final String TAG = MyWebViewActivity.class.getSimpleName();
    private WebView mWebView = null;
    private final String URL = "http://www.google.com";
    private LinearLayout mlLayoutRequestError = null;
    private Handler mhErrorLayoutHide = null;

    private boolean mbErrorOccured = false;
    private boolean mbReloadPressed = false;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);

        ((Button) findViewById(R.id.btnRetry)).setOnClickListener(this);
        mlLayoutRequestError = (LinearLayout) findViewById(R.id.lLayoutRequestError);
        mhErrorLayoutHide = getErrorLayoutHideHandler();

        mWebView = (WebView) findViewById(R.id.webviewMain);
        mWebView.setWebViewClient(new MyWebViewClient());
        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        mWebView.setWebChromeClient(getChromeClient());
        mWebView.loadUrl(URL);
    }

    @Override
    public boolean onSupportNavigateUp() {
        return super.onSupportNavigateUp();
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();

        if (id == R.id.btnRetry) {
            if (!mbErrorOccured) {
                return;
            }

            mbReloadPressed = true;
            mWebView.reload();
            mbErrorOccured = false;
        }
    }

    @Override
    public void onBackPressed() {
        if (mWebView.canGoBack()) {
            mWebView.goBack();
            return;
        }
        else {
            finish();
        }

        super.onBackPressed();
    }

    class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return super.shouldOverrideUrlLoading(view, url);
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }

        @Override
        public void onLoadResource(WebView view, String url) {
            super.onLoadResource(view, url);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            if (mbErrorOccured == false && mbReloadPressed) {
                hideErrorLayout();
                mbReloadPressed = false;
            }

            super.onPageFinished(view, url);
        }

        @Override
        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
            mbErrorOccured = true;
            showErrorLayout();
            super.onReceivedError(view, errorCode, description, failingUrl);
        }
    }

    private WebChromeClient getChromeClient() {
        final ProgressDialog progressDialog = new ProgressDialog(MyWebViewActivity.this);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCancelable(false);

        return new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
            }
        };
    }

    private void showErrorLayout() {
        mlLayoutRequestError.setVisibility(View.VISIBLE);
    }

    private void hideErrorLayout() {
        mhErrorLayoutHide.sendEmptyMessageDelayed(10000, 200);
    }

    private Handler getErrorLayoutHideHandler() {
        return new Handler() {
            @Override
            public void handleMessage(Message msg) {
                mlLayoutRequestError.setVisibility(View.GONE);
                super.handleMessage(msg);
            }
        };
    }
}

Ajout: Voici la mise en page ...

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rLayoutWithWebView"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<WebView
    android:id="@+id/webviewMain"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<LinearLayout
    android:id="@+id/lLayoutRequestError"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:background="@color/white"
    android:gravity="center"
    android:orientation="vertical"
    android:visibility="gone" >

    <Button
        android:id="@+id/btnRetry"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:minWidth="120dp"
        android:text="RELOAD"
        android:textSize="20dp"
        android:textStyle="bold" />
</LinearLayout>

cmcromance
la source
Pouvez-vous s'il vous plaît partager votre fichier de ressources? Je suis novice.
Rajan Rawal
@RajanRawal J'ai édité et ajouté l'exemple de mise en page. :)
cmcromance
Je ne vois aucune barre de progression, mais je peux voir le code ici. :-(
Rajan Rawal
7

Consultez la discussion sur Android WebView onReceivedError () . C'est assez long, mais le consensus semble être que a) vous ne pouvez pas empêcher la page "page Web non disponible" d'apparaître, mais b) vous pouvez toujours charger une page vide après avoir obtenu une erreur onReceivedError

À débarrasser
la source
Ces types parlent de onReceivedErrorne pas déclencher du tout. Il se déclenche correctement dans mon code lorsqu'il n'y a pas de connexion Internet.
JoJo
7

Lorsque la vue Web est intégrée dans une vue personnalisée de telle sorte que l'utilisateur croit presque voir une vue native et non une vue Web, dans un tel scénario, il est absurde de voir l'erreur «La page n'a pas pu être chargée». Ce que je fais habituellement dans une telle situation, c'est de charger une page vierge et d'afficher un message toast comme ci-dessous

webView.setWebViewClient(new WebViewClient() {

            @Override
            public void onReceivedError(WebView view, int errorCode,
                    String description, String failingUrl) {
                Log.e(TAG," Error occured while loading the web page at Url"+ failingUrl+"." +description);     
                view.loadUrl("about:blank");
                Toast.makeText(App.getContext(), "Error occured, please check newtwork connectivity", Toast.LENGTH_SHORT).show();
                super.onReceivedError(view, errorCode, description, failingUrl);
            }
        });
Jeevan
la source
2

Vous pouvez utiliser une GETdemande pour obtenir le contenu de la page, puis afficher ces données à l'aide de Webview, de cette façon, vous n'utilisez pas plusieurs appels de serveur. Alternative que vous pouvez utiliser Javascriptpour vérifier la DOMvalidité de l' objet.

Ravi Vyas
la source
c'est une bonne idée, cependant, c'est vraiment dommage que nous devions faire quelque chose comme ça ...
Jeffrey Blattman
2

Peut-être ai-je mal compris la question, mais il semble que vous dites que vous recevez un rappel d'erreur et que vous demandez simplement quelle est la meilleure façon de ne pas afficher l'erreur? Pourquoi ne supprimez-vous pas simplement la vue Web de l'écran et / ou n'affichez-vous pas une autre vue par-dessus?

Matthew Horst
la source
2

Ici, j'ai trouvé la solution la plus simple. Regarde ça..

   @Override
        public void onReceivedError(WebView view, int errorCode,
                                    String description, String failingUrl) {
//                view.loadUrl("about:blank");
            mWebView.stopLoading();
            if (!mUtils.isInterentConnection()) {
                Toast.makeText(ReportingActivity.this, "Please Check Internet Connection!", Toast.LENGTH_SHORT).show();
            }
            super.onReceivedError(view, errorCode, description, failingUrl);
        }

Et voici la méthode isInterentConnection () ...

public boolean isInterentConnection() {
    ConnectivityManager manager = (ConnectivityManager) mContext
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    if (manager != null) {
        NetworkInfo info[] = manager.getAllNetworkInfo();
        if (info != null) {
            for (int i = 0; i < info.length; i++) {
                if (info[i].getState() == NetworkInfo.State.CONNECTED) {
                    return true;
                }
            }
        }
    }
    return false;
}
Ankush Joshi
la source
1

Je suppose que si vous insistez pour faire cela, vous pouvez simplement vérifier si la ressource est là avant d'appeler la fonction loadURL. Remplacez simplement les fonctions et faites la vérification avant d'appeler le super ()

REMARQUE (peut-être hors sujet): Dans http, il existe une méthode appelée HEAD qui est décrite comme suit:

La méthode HEAD est identique à GET sauf que le serveur NE DOIT PAS renvoyer un corps de message dans la réponse

Cette méthode peut être pratique. Quoi qu'il en soit, comment jamais vous l'implémentez ... vérifiez ce code:

import java.util.Map;

import android.content.Context;
import android.webkit.WebView;

public class WebViewPreLoad extends WebView{

public WebViewPreLoad(Context context) {
super(context);
}
public void loadUrl(String str){
if(//Check if exists)
super.loadUrl(str);
else
//handle error
}
public void loadUrl(String url, Map<String,String> extraHeaders){
if(//Check if exists)
super.loadUrl(url, extraHeaders);
else
//handle error
}
}

Vous pouvez essayer cette vérification en utilisant

if(url.openConnection().getContentLength() > 0)
Sherif elKhatib
la source
6
Vérifier si la ressource est là avant d'y aller effectivement doublerait la charge sur le serveur car il y aurait 2 requêtes physiques pour 1 requête virtuelle. Cela semble un peu exagéré.
JoJo du
mesures bien désespérées!
Sherif elKhatib
1
Quoi qu'il en soit, vous pouvez toujours le surcharger et obtenir le contenu html, vérifier s'il contient une erreur. Sinon analyser et l'afficher
Sherif elKhatib
comment pourrait-on réellement mettre cela en œuvre?
JoJo du
@JoJo, en fait, cette méthode réduit la charge sur le serveur en cas d'URL invalide car le renvoi d'une réponse HEAD a une surcharge beaucoup plus faible que le renvoi d'une réponse 304 ou 500.
Justin Shield
0

Je changerais simplement la page Web en ce que vous utilisez pour la gestion des erreurs:

getWindow().requestFeature(Window.FEATURE_PROGRESS);  
webview.getSettings().setJavaScriptEnabled(true);  
final Activity activity = this;  
webview.setWebChromeClient(new WebChromeClient() {  
public void onProgressChanged(WebView view, int progress) {  
 // Activities and WebViews measure progress with different scales.  
 // The progress meter will automatically disappear when we reach 100%  
 activity.setProgress(progress * 1000);  
 }  
});  
webview.setWebViewClient(new WebViewClient() {  
public void onReceivedError(WebView view, int errorCode, String description, String 
failingUrl) {  
 Toast.makeText(activity, "Oh no! " + description, Toast.LENGTH_SHORT).show();  
}  
});  
webview.loadUrl("http://slashdot.org/");

tout cela peut être trouvé sur http://developer.android.com/reference/android/webkit/WebView.html

Éphraïm
la source
0

J'ai travaillé sur ce problème d'abandon de ces pages d'erreur Google irritables aujourd'hui. C'est possible avec l'exemple de code Android vu ci-dessus et dans de nombreux autres forums (demandez comment je sais):

wv.setWebViewClient(new WebViewClient() {
    public void onReceivedError(WebView view, int errorCode,
                            String description, String failingUrl) {
       if (view.canGoBack()) {
          view.goBack();
        }
       Toast.makeText(getBaseContext(), description, Toast.LENGTH_LONG).show();
       }
    }
});

SI vous le mettez dans shouldOverrideUrlLoading () en tant que client Web de plus. Au moins, cela fonctionne pour moi sur mon appareil 2.3.6. Nous verrons où cela fonctionne plus tard. Cela ne ferait que me déprimer maintenant, j'en suis sûr. Le bit goBack est à moi. Vous n'en voulez peut-être pas.

R Earle Harris
la source
0

Essaye ça

 @SuppressWarnings("deprecation")
 @Override
 public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
      // Your handling
 }

 @Override
 public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
      }
 }
Virat18
la source
0

Nous pouvons définir la visibilité de webView sur 0 (view.INVISIBLE) et afficher un message. Ce code fonctionne pour mon application fonctionnant sur lolipop.

@SuppressWarnings("deprecation")
    @Override
    public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl) {
        // hide webView content and show custom msg
        webView.setVisibility(View.INVISIBLE);
        Toast.makeText(NrumWebViewActivity.this,getString(R.string.server_not_responding), Toast.LENGTH_SHORT).show();
    }

    @TargetApi(android.os.Build.VERSION_CODES.M)
    @Override
    public void onReceivedError(WebView view, WebResourceRequest req, WebResourceError rerr) {
        // Redirect to deprecated method, so you can use it in all SDK versions
        onReceivedError(view, rerr.getErrorCode(), rerr.getDescription().toString(), req.getUrl().toString());
    }
Mahen
la source
0

J'ai dû faire face à ce problème et j'ai également essayé de le résoudre sous différents angles. Enfin, j'ai trouvé une solution en utilisant un seul indicateur pour vérifier si une erreur s'est produite.

... extends WebViewClient {

    boolean error;

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {

        showLoading(true);
        super.onPageStarted(view, url, favicon);

        error  = false; // IMPORTANT
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);

        if(!error) {
            Observable.timer(100, TimeUnit.MICROSECONDS, AndroidSchedulers.mainThread())
                    .subscribe((data) -> view.setVisibility(View.VISIBLE) );
        }

        showLoading(false);
    }


    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {

        view.stopLoading();

        view.setVisibility(View.INVISIBLE) 
        error  = true;  

        // Handle the error
    }


     @Override
    @TargetApi(android.os.Build.VERSION_CODES.M)
    public void onReceivedError(WebView view,
                                WebResourceRequest request,
                                WebResourceError error) {

        this.onReceivedError(view, error.getErrorCode(),
                error.getDescription().toString(),
                request.getUrl().toString());
    }
 }

De cette façon, je cache la page à chaque fois qu'il y a une erreur et je l'affiche lorsque la page s'est à nouveau chargée correctement.

Ajout d'un petit délai au cas où.

J'ai évité la solution de charger une page vide car elle ne vous permet pas de faire webview.reload () plus tard car elle ajoute cette nouvelle page dans l'historique de navigation.

José M Lechon
la source
-1

essayez ceci shouldOverrideUrlLoading , avant de rediriger vers une autre URL, vérifiez si la connexion Internet basée sur cette page doit être chargée ou non.

Bipin Vayalu
la source
-1

remplacer votre méthode WebViewClient

@Override
public void onReceivedError(WebView view, int errorCode,
    String description, String failingUrl) {
    view.clearView();
}

view.loadUrl('about:blank') a des effets secondaires, car il annule le chargement de l'URL d'origine.

canard de canard
la source
view.clearView () est obsolète, voir stackoverflow.com/questions/3715482/clear-webview-content
silva96