如何编辑或创建WebView的自定义错误页面?

17
我创建了一个WebView布局,用于访问特定的网站。但是当手机没有网络连接或页面超时时,编辑或创建自定义的“网页无法使用”资源会很有用。我知道这是可能的,因为如果您在飞行模式下打开应用程序Wikidroid,您将收到“文章不可用”错误页面,而不是标准的Android“网页无法使用”错误页面。
我在互联网上搜寻了高低之后未能找到任何在线资源来解决此请求。非常感谢任何帮助。提前致谢。
3个回答

20

要确定设备何时具有网络连接,请请求权限<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />,然后可以使用以下代码进行检查。首先将这些变量定义为类变量。

private Context c;
private boolean isConnected = true;

在您的onCreate()方法中,初始化c = this;

然后检查连接性。

ConnectivityManager connectivityManager = (ConnectivityManager)
    c.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
    NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
    if (ni.getState() != NetworkInfo.State.CONNECTED) {
        // record the fact that there is not connection
        isConnected = false;
    }
}

然后要拦截WebView请求,你可以像下面这样做。如果你使用此方法,你可能需要自定义错误消息以包含onReceivedError方法中可用的某些信息。

final String offlineMessageHtml = "DEFINE THIS";
final String timeoutMessageHtml = "DEFINE THIS";

WebView browser = (WebView) findViewById(R.id.webview);
browser.setNetworkAvailable(isConnected);
browser.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (isConnected) {
            // return false to let the WebView handle the URL
            return false;
        } else {
            // show the proper "not connected" message
            view.loadData(offlineMessageHtml, "text/html", "utf-8");
            // return true if the host application wants to leave the current 
            // WebView and handle the url itself
            return true;
        }
    }
    @Override
    public void onReceivedError (WebView view, int errorCode, 
        String description, String failingUrl) {
        if (errorCode == ERROR_TIMEOUT) {
            view.stopLoading();  // may not be needed
            view.loadData(timeoutMessageHtml, "text/html", "utf-8");
        }
    }
});

我查看了你提到的错误,并更新了我的答案以解决它们。在进行Android项目之前,您可能需要更加熟悉Java。良好的Java基础将在调试这些小错误和尝试发现问题时有很大帮助。如果您遇到任何其他问题,请告诉我。 - Brian
2
Brian,感谢您查看代码,我非常感激您的帮助。最终我使用了“onReceivedError”代码,而不是加载“timeoutMessageHtml”字符串,我让应用程序“setContentView()”到一个新的线性布局,该布局具有自定义错误消息。此外,您关于拥有良好的Java基础是100%正确的。我已经阅读了几本Java书籍,并且正在参加一门Java课程,但是我通过实践学习得最好,所以我想创建一个应用程序来学习Java。再次感谢。 - Sid 6x
我发现如果设备关闭了WiFi和3G,则此代码将崩溃,这里的示例对我有效:http://www.androidsnippets.com/check-if-the-network-is-available - Jag
1
如果您可以重写WebViewClient内置的onReceivedError(),为什么要使用这样复杂的解决方案呢? - caw
仅使用onReceivedError()时,无法检测到是否存在任何连接。仅仅对错误做出反应不如预见它并拥有更多信息来建议解决方案。 - Brian
Sharats.com评论,错误地发布在答案中:“@Brian,提供的URL已更新为http://www.androidsnippets.com/check-if-the-network-is-available.html” - Petter Friberg

10

Marco W. 是正确的。

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

    }
});

19
大多数设备上看起来效果不好。在调用onReceivedError()之前,标准错误页面已被呈现。因此,在自定义页面加载完成之前,标准错误页面会可见几毫秒。 - Robert

0

我已经尝试使用上述所有解决方案,但它们都没有起作用。稍微调整了一下我的代码,现在已经得到了解决方案:

package com.samnjor.tipsmaster;

import android.content.Context; import android.graphics.Bitmap;
import android.net.ConnectivityManager; import
android.net.NetworkInfo; import
android.support.v7.app.AppCompatActivity; import android.os.Bundle;
import android.view.View; import android.webkit.WebSettings; import
android.webkit.WebView; import android.webkit.WebViewClient; import
android.widget.ProgressBar; import android.widget.TextView;

import com.google.android.gms.ads.AdListener; import
com.google.android.gms.ads.AdRequest; import
com.google.android.gms.ads.InterstitialAd;

public class TodayTips extends AppCompatActivity {
    String ShowOrHideWebViewInitialUse = "show";
    private WebView webview ;
    private ProgressBar spinner;
    private String TAG = TodayTips.class.getSimpleName();
    InterstitialAd mInterstitialAd;
    final String noconnectionHtml = "Failed to connect ot the internet";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_today_tips);
        mInterstitialAd = new InterstitialAd(this);

        // set the ad unit ID
        mInterstitialAd.setAdUnitId(getString(R.string.adbig));

        AdRequest adRequest = new AdRequest.Builder()
                .build();

        // Load ads into Interstitial Ads
        mInterstitialAd.loadAd(adRequest);

        mInterstitialAd.setAdListener(new AdListener() {
            public void onAdLoaded() {
                showInterstitial();
            }
        });
    }

    private void showInterstitial() {
        if (mInterstitialAd.isLoaded()) {
            mInterstitialAd.show();
        }

        webview =(WebView)findViewById(R.id.webView);
        spinner = (ProgressBar)findViewById(R.id.progressBar1);
        webview.setWebViewClient(new CustomWebViewClient());

        webview.getSettings().setJavaScriptEnabled(true);
        webview.getSettings().setDomStorageEnabled(true);
        webview.setOverScrollMode(WebView.OVER_SCROLL_NEVER);

        if(haveNetworkConnection()){
            webview.loadUrl("http://you domain here");
        } else {


            webview.loadData(noconnectionHtml, "text/html", "utf-8"); //
        }
    }
    private boolean haveNetworkConnection() {
        boolean haveConnectedWifi = false;
        boolean haveConnectedMobile = false;

        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo[] netInfo = cm.getAllNetworkInfo();

        for (NetworkInfo ni : netInfo) {
            if (ni.getTypeName().equalsIgnoreCase("WIFI"))
                if (ni.isConnected())
                    haveConnectedWifi = true;
            if (ni.getTypeName().equalsIgnoreCase("MOBILE"))
                if (ni.isConnected())
                    haveConnectedMobile = true;
        }
        return haveConnectedWifi || haveConnectedMobile;

    }

    // This allows for a splash screen
    // (and hide elements once the page loads)
    private class CustomWebViewClient extends WebViewClient {

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

            // only make it invisible the FIRST time the app is run
            if (ShowOrHideWebViewInitialUse.equals("show")) {
                webview.setVisibility(webview.INVISIBLE);
            }
        }

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

            ShowOrHideWebViewInitialUse = "hide";
            spinner.setVisibility(View.GONE);

            view.setVisibility(webview.VISIBLE);
            super.onPageFinished(view, url);

        }
    }`` }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接