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 2011

@JoJo 정답을 맞출 수 있습니까? 아마 내 것 : P
Sherif elKhatib

답변:


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
Cheenu와 동의합니다. 더 나은 해결책이 있어야합니다.
Jozua

3
1. WebView가 보이지 않는 동안 웹 콘텐츠를로드하고 (그리고 그 위에 진행률이 나쁘게 표시 될 수 있음) 페이지가 성공적으로로드되었는지 표시하거나 오류시 "myerrorpage.html"을로드 할 수 있습니다. 2. 페이지가로드 된 후 실행되는 JS에서 OR 문제를로드하는 데 문제가있는 경우 onReceiveError가 트리거됩니다 (예 : document.ready () 이벤트에서 실행되는 jQuery 함수). 데스크톱 브라우저-모바일 브라우저와 마찬가지로 사용자에게 알리지 않고 JS 오류를 허용합니다.
FunkSoulBrother 2015-08-26

5
view.loadUrl("about:blank");1 초 동안 오류 페이지를 표시하지 않도록 loadUrl 앞에 추가 하십시오.
Aashish

2
myerrorpage.html 파일을 어디에 넣을까요? 그 안드로이드 자산 폴더는 어디에 있습니까?
Nived Kannada

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()이 빈 페이지의 상태를 반드시 취급 해주십시오 . 그렇지 않으면 이전 페이지가로드되고 다시 실패하면이 빈 페이지가 다시 표시됩니다.
Chintan Shah

그래서, 그것을 처리하는 가장 좋은 방법은 무엇입니까?
MoSoli

@MoSoli 그것은 모두 당신의 필요에 달려 있습니다. 빈 페이지를 표시하는 대신 사용자 지정 UI 또는 캐시 된 웹 페이지를 표시 할 수 있습니다.
7heViking

10

마침내 나는 이것을 해결했다. (지금까지 작동합니다 ..)

내 솔루션은 다음과 같습니다.

  1. 웹 페이지 대신 오류가 발생했을 때 표시 할 레이아웃을 준비합니다 (더티 '페이지를 찾을 수 없음 메시지'). 레이아웃에는 몇 가지 안내 메시지와 함께 "RELOAD"버튼이 하나 있습니다.

  2. 오류가 발생하면 부울 사용을 기억하고 준비한 레이아웃을 표시하십시오.

  3. 사용자가 "RELOAD"버튼을 클릭하면 mbErrorOccured를 false로 설정합니다. 그리고 mbReloadPressed를 true로 설정합니다.
  4. mbErrorOccured가 false이고 mbReloadPressed가 true이면 webview가 페이지를 성공적으로로드했음을 의미합니다. 오류가 다시 발생하면 mbErrorOccured가 onReceivedError (...)에서 true로 설정됩니다.

여기 내 전체 출처가 있습니다. 이것 좀 봐.

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 2015

@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 () 에서 토론을 확인하십시오 . 꽤 길지만 합의는 a) "웹 페이지를 사용할 수 없음"페이지가 나타나는 것을 멈출 수는 없지만 b) onReceivedError가 발생하면 항상 빈 페이지를로드 할 수 있다는 것입니다.


이 사람들은 onReceivedError전혀 트리거하지 않는 것에 대해 이야기 하고 있습니다. 인터넷에 연결되어 있지 않을 때 내 코드에서 올바르게 트리거됩니다.
JoJo

2

GET요청을 사용 하여 페이지 콘텐츠를 가져온 다음을 사용하여 해당 데이터를 표시 Webview할 수 있습니다. 이렇게하면 여러 서버 호출을 사용하지 않습니다. 또는 객체의 유효성 Javascript을 확인하는 데 사용할 수 있습니다 DOM.


그것은 좋은 생각이지만, 우리가 이와 같은 일을해야한다는 것은 정말 불행한 일입니다 ...
Jeffrey Blattman 2012-08-09

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 함수를 호출하기 전에 리소스가 있는지 확인할 수 있다고 가정합니다. 단순히 함수를 재정의하고 super ()를 호출하기 전에 확인을 수행하십시오.

비고 (주제에서 벗어날 수 있음) : 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

잘 필사적 인 대책!
보안관 elKhatib

1
어쨌든 여전히 오버로드하고 html 콘텐츠를 가져올 수 있으며 오류가 있는지 확인하십시오. 하지 않으면 것은 구문 분석하고이를 표시
보안관 elKhatib

실제로 이것을 어떻게 구현할까요?
조조

@JoJo, 실제로이 방법은 HEAD 응답을 반환하는 것이 304 또는 500 응답을 반환하는 것보다 훨씬 더 적은 오버 헤드를 갖기 때문에 유효하지 않은 URL의 경우 서버의로드를 줄입니다.
저스틴 쉴드

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 ()를 수행 할 수 없기 때문에 빈 페이지를로드하는 솔루션을 피했습니다.



당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.