Заборонити WebView відображати “веб-сторінка недоступна”


88

У мене є програма, яка широко використовує WebView. Коли у користувача цієї програми немає з’єднання з Інтернетом, з’являється сторінка із написом «веб-сторінка недоступна» та інший інший текст. Чи є спосіб не відображати цей загальний текст у моєму WebView? Я хотів би забезпечити власну обробку помилок.

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();
 }
}

Я виявив, що WebView-> clearView насправді не очищає вигляд.


3
Чому б вам не перевірити підключення до Інтернету перед тим, як показувати webView, і якщо немає доступної мережі Інтернету, ви можете пропустити показ WebView, і замість цього ви можете показати попередження або тост без повідомлення в Інтернеті?
Andro Selva,

@JoJo, чи можете ви позначити відповідь як правильну? ймовірно, моє: P
Шериф ель-Хатіб

Відповіді:


102

Спочатку створіть свою власну сторінку помилок у HTML та помістіть її у папку ваших ресурсів, назвемо її myerrorpage.html Потім за допомогою onReceivedError:

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

    }
});

27
Стара сторінка помилки "Веб-сторінка не завантажена" відображається на частку секунди, перш ніж її замінить спеціальна сторінка помилок з активів
Чену Мадан

1
Погодьтеся з Чену. Має бути краще рішення.
Джозуа

3
1. Ви можете завантажити веб-вміст, поки WebView невидимий (і, можливо, відображати прогрес погано над ним) і показати його, якщо сторінка успішно завантажена / завантажте "myerrorpage.html" за помилкою. 2. Вам слід пам’ятати, що onReceiveError спрацьовує, якщо виникають проблеми із завантаженням проблеми АБО в JS, яка запускається після завантаження сторінки (наприклад, функції jQuery, що запускаються у події document.ready ()). Настільний браузер - дозволить помилку JS, не повідомляючи про це користувача, як це роблять мобільні браузери.
FunkSoulBrother

5
add view.loadUrl("about:blank");перед loadUrl, щоб на частку секунди не відображати сторінку помилок.
Aashish

2
Куди покласти файл myerrorpage.html? Де знаходиться ця папка Android-активів?
Ніведі Каннада

34

Найкраще рішення, яке я знайшов, - це завантажити порожню сторінку в події OnReceivedError наступним чином:

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

    view.loadUrl("about:blank");
}

Гарна ідея! У моєму випадку я додав view.loadUrl(noConnectionUrl);двічі (де noConnectionUrl - це локальний файл із повідомленням про помилку). Це також допомогло не «бачити» вбудовану сторінку помилок на частку секунди.
hQuse

4
Зверніть увагу, що, якщо ви обробляєте, webView.goBack()переконайтеся, що обробляєте умови для цієї порожньої сторінки. В іншому випадку попередня сторінка буде завантажена, і якщо вона знову не вдасться, ви знову побачите цю порожню сторінку.
Чінтан-шах

Отже, який найкращий спосіб вирішити це?
MoSoli

@MoSoli Все залежить від ваших потреб. Альтернативою відображення порожньої сторінки може бути показ користувацького інтерфейсу користувача або кешованої веб-сторінки.
7heViking

10

Нарешті, я це вирішив. (Це працює дотепер ..)

Моє рішення таке ...

  1. Підготуйте макет, щоб показати, коли замість веб-сторінки сталася помилка (брудне повідомлення "сторінку не знайдено") Макет має одну кнопку "RELOAD" із деякими повідомленнями керівництва.

  2. Якщо сталася помилка, пам’ятайте про використання логічного значення та покажіть макет, який ми готуємо.

  3. Якщо користувач натискає кнопку "ПЕРЕЗАТРИМАТИ", встановіть для mbErrorOcured значення false. І встановіть для mbReloadPress значення true.
  4. якщо mbErrorOccured має значення false, а mbReloadPress - істина, це означає, що сторінка веб-перегляду успішно завантажена. Тому що, якщо помилка повторилася знову, mbErrorOccured буде встановлено як true у onReceivedError (...)

Ось моє повне джерело. Перевір це.

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);
            }
        };
    }
}

Додаток: Ось макет ....

<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>


Чи можете ви поділитися своїм файлом ресурсів? Я новачок.
Rajan Rawal

@RajanRawal Я відредагував і додав приклад макета. :)
cmcromance

Я не бачу жодної стрічки прогресу, але я бачу там код. :-(
Rajan Rawal

8

Коли веб-перегляд вбудований у якийсь спеціальний вигляд, такий що користувач майже вірить, що він бачить власний вигляд, а не веб-перегляд, у такому випадку показ помилки "сторінка не може бути завантажена" є недоречним. Що я зазвичай роблю в такій ситуації, це завантажую порожню сторінку і показую тост, як показано нижче

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);
            }
        });

7

Перегляньте обговорення на веб- сайті Android WebView onReceivedError () . Це досить довго, але, здається, консенсус полягає в тому, що а) ви не можете зупинити появу сторінки "веб-сторінка недоступна", але б) ви завжди можете завантажити порожню сторінку після отримання onReceivedError


Ці хлопці говорять про те, що onReceivedErrorвзагалі не спрацьовують. Він правильно спрацьовує в моєму коді, коли немає з’єднання з Інтернетом.
JoJo

2

Ви можете використовувати GETзапит, щоб отримати вміст сторінки, а потім відобразити ці дані за допомогою Webview, таким чином, ви не використовуєте кілька викликів сервера. Альтернативу можна використовувати Javascriptдля перевірки DOMоб’єкта на дійсність.


це гарна ідея, однак, дуже шкода, що нам потрібно робити щось подібне ...
Джеффрі Блаттман

2

Можливо, я неправильно розумію запитання, але схоже, ви кажете, що отримали помилку, отриману зворотний виклик, і ви просто запитуєте, який найкращий спосіб не показувати помилку? Чому б вам просто не видалити веб-вигляд з екрана та / або не показати інший вигляд поверх нього?


2

Тут я знайшов найпростіше рішення. перевірте це ..

   @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);
        }

А ось метод 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;
}

1

Я припускаю, що якщо ви наполягаєте на цьому, ви можете просто перевірити, чи є там ресурс, перш ніж викликати функцію loadURL. Просто перевизначте функції та зробіть перевірку перед викликом супер ()

ЗАБЕЗПЕЧЕННЯ (можливо, поза темою): У http є метод HEAD, який описується наступним чином:

Метод HEAD ідентичний GET, за винятком того, що сервер НЕ ПОВИНЕН повертати тіло повідомлення у відповіді

Цей метод може бути корисним. У будь-якому випадку, як будь-коли ви це реалізуєте ... перевірте цей код:

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
}
}

Ви можете спробувати цю перевірку за допомогою

if(url.openConnection().getContentLength() > 0)

6
Перевірка наявності ресурсу перед тим, як насправді перейти туди, подвоїть навантаження на сервер, оскільки на 1 віртуальний запит буде 2 фізичних запити. Це здається трохи надмірним.
JoJo

ну відчайдушні заходи!
Sherif elKhatib

1
У будь-якому випадку ви все одно можете перевантажити його та отримати вміст html ,, перевірити, чи не помилка. Якщо не проаналізувати і продемонструвати
Sherif elKhatib

як би насправді це реалізувати?
JoJo

@JoJo, насправді цей метод зменшує навантаження на сервер у разі невірної URL-адреси, оскільки повернення відповіді HEAD має значно менші накладні витрати порівняно з поверненням відповіді 304 або 500.
Justin Shield

0

Я б просто змінив веб-сторінку на те, що ви використовуєте для обробки помилок:

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/");

все це можна знайти на http://developer.android.com/reference/android/webkit/WebView.html


0

Сьогодні я працював над цією проблемою відмови від цих дратівливих сторінок помилок Google. Це можливо за допомогою прикладу коду Android, побаченого вище та на багатьох інших форумах (запитайте, як я знаю):

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();
       }
    }
});

ЯКЩО ви помістите його в shouldOverrideUrlLoading () як ще один веб-клієнт. Принаймні, це працює для мене на моєму пристрої 2.3.6. Пізніше ми побачимо, де це ще працює. Впевнений, це зараз би мене лише пригнічувало. Біт goBack - це моє. Можливо, ви цього не хочете.


0

Спробуйте це

 @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());
      }
 }

0

Ми можемо встановити видимість webView на 0 (view.INVISIBLE) і показати деяке повідомлення. Цей код працює для мого додатка, що працює на 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());
    }

0

Мені довелося зіткнутися з цією проблемою, а також намагався вирішити її з різних точок зору. Нарешті я знайшов рішення, використовуючи єдиний прапор, щоб перевірити, чи не сталася помилка.

... 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());
    }
 }

Таким чином я приховую сторінку щоразу, коли виникає помилка, і показую її, коли сторінка завантажується знову належним чином.

Також додано невелику затримку на випадок.

Я уникнув рішення завантаження порожньої сторінки, оскільки це не дозволяє робити webview.reload () пізніше, оскільки воно додає цю нову сторінку в історію навігації.


-1

спробуйте виконати this shouldOverrideUrlLoading , перш ніж перенаправляти на іншу URL-адресу, перевіряйте наявність зв’язків в Інтернеті на основі завантаження цієї сторінки чи ні.


-1

перевизначити метод WebViewClient

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

view.loadUrl('about:blank') має побічні ефекти, оскільки скасовує завантаження вихідної URL-адреси.


view.clearView () є застарілим, см stackoverflow.com/questions/3715482/clear-webview-content
silva96
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.