안드로이드

[Android] 웹뷰 webview window.open 처리 (웹뷰 고급편)

IT꿈나무 2021. 9. 29. 13:23
반응형

업무의 배경:

하이브리드 앱 구현시에 휴대폰 인증, 우편번호 찾기 등에서 window.open을 처리할 필요가 있다.

window.open 관련 새로운 웹뷰를 생성에 관련하여 추가적인 구현이 필요하다.

하이브리드 앱 구현시에 웹뷰를 모바일 크롬 버전과 동일하게 만들어 달라는 요청을 받으며 때론 압박을 받곤한다.
업무의 혼성을 방지하기 위에서 모바일의 크롬 브라우저와 동일하게 동작하는 웹뷰를 커스텀으로 만들어 줄 필요가 있다.

 

업무의 목적:

* window.open을 처리해 준다.

* 하이브리드 앱에서 웹뷰를 커스텀하게 구현하여, 모바일의 크롬 브라우저와 동일하게 동작하게 만든다.

* 모바일의 크롬브라우저와 동일하게 웹뷰를 구현함으로써 업무의 혼선을 방지할 수 있다.

 

해결 방안:

window.open 발생시 dialog 안에서 서브 웹뷰 팝업이 발생함.

 

Main

this.mWebView = findViewById(R.id.webView);

WebSettings settings = mWebView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setJavaScriptCanOpenWindowsAutomatically(true);
settings.setSupportMultipleWindows(true);

this.mWebView.setWebChromeClient(new MyWebChromeClient());
this.mWebView.setWebViewClient(new MyWebViewClient(getApplicationContext()));

this.mWebView.loadUrl("http://www.naver.com");

MyWebChromeClient

public class MyWebChromeClient extends WebChromeClient{
    private final String TAG = "MyWebChromeClient";

    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);
        MyLog.i(TAG,"onProgressChanged(view:"+view.toString()+ ", newProgress:"+newProgress+")");
    }
    @Override
    public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
        MyLog.toastMakeTextShow(view.getContext(), "TAG", "window.open 협의가 필요합니다.");
        WebView newWebView = new WebView(view.getContext());
        WebSettings webSettings = newWebView.getSettings();
        WebSettings settings = newWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setJavaScriptCanOpenWindowsAutomatically(true);
        settings.setSupportMultipleWindows(true);
        
        //final Dialog dialog = new Dialog(view.getContext(),R.style.Theme_DialogFullScreen);
        final Dialog dialog = new Dialog(view.getContext());
        dialog.setContentView(newWebView);
        dialog.show();


        dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {

                if(keyCode == KeyEvent.KEYCODE_BACK) {
                    //MyLog.toastMakeTextShow(view.getContext(), "TAG", "KEYCODE_BACK");
                    if(newWebView.canGoBack()){
                        newWebView.goBack();
                    }else{
                        MyLog.toastMakeTextShow(view.getContext(), "TAG", "Window.open 종료");
                        dialog.dismiss();
                    }
                    return true;
                }else{
                    return false;
                }
            }
        });
        newWebView.setWebViewClient(new MyWebViewClient(view.getContext()));
        newWebView.setWebChromeClient(new MyWebChromeClient() {
            @Override
            public void onCloseWindow(WebView window) {
                dialog.dismiss(); }
        });


        WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
        transport.setWebView(newWebView);
        resultMsg.sendToTarget();
        return true;
    }
    @Override
    public void onCloseWindow(WebView window) {
        MyLog.i(getClass().getName(), "onCloseWindow");
        window.setVisibility(View.GONE);
        window.destroy();
        //mWebViewSub=null;
        super.onCloseWindow(window);
    }

    @Override
    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
        MyLog.i(getClass().getName(), "onJsAlert() url:"+url+", message:"+message);
        //return super.onJsAlert(view, url, message, result);
        new AlertDialog.Builder(view.getContext())
                .setTitle("")
                .setMessage(message)
                .setPositiveButton(android.R.string.ok,
                        new AlertDialog.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                result.confirm();

                            }
                        })
                .setCancelable(false)
                .create()
                .show();

        return true;
    }

    @Override
    public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
        MyLog.i(getClass().getName(), "onJsConfirm() url:"+url+", message"+message);
        //return super.onJsConfirm(view, url, message, result);

        new AlertDialog.Builder(view.getContext())
                .setTitle("")
                .setMessage(message)
                .setPositiveButton(android.R.string.ok,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                result.confirm();

                            }
                        })
                .setNegativeButton(android.R.string.cancel,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                result.cancel();
                            }
                        })
                .create()
                .show();
        return true;
    }
}

MyWebViewClient

public class MyWebViewClient extends WebViewClient {
    private String TAG = "MyWebViewClient";
    private Context mApplicationContext =null;
    public MyWebViewClient(Context _applicationContext) {
        mApplicationContext = _applicationContext;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        MyLog.i(TAG,"shouldOverrideUrlLoading(view:"+view+ ", request:"+request+")");
        return super.shouldOverrideUrlLoading(view, request);
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        MyLog.i(TAG,"onPageStarted(view:"+view+ ", url:"+url+ ", favicon:"+favicon+")");
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        MyLog.i(TAG,"onPageFinished(view:"+view+ ", url:"+url+")");
    }

    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            //Log.i(TAG, "onReceivedError() " + error.getErrorCode() + " ---> " + error.getDescription());
            onReceivedError(error.getErrorCode(),String.valueOf(error.getDescription()));

        }
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            // Log.i(TAG, "onReceivedError() " + errorCode + " ---> " + description);
            onReceivedError(errorCode,description);
        }

    }

    private void onReceivedError(int errorCode, String description){
        MyLog.i(getClass().getName(), "onReceivedError() " + errorCode + " ---> " + description);
        switch (errorCode) {
            case WebViewClient.ERROR_TIMEOUT:   //연결 시간 초과
            case WebViewClient.ERROR_CONNECT:   //서버로 연결 실패
                //case WebViewClient.ERROR_UNKNOWN:   // 일반 오류
            case WebViewClient.ERROR_FILE_NOT_FOUND: //404
            case WebViewClient.ERROR_HOST_LOOKUP :
            case WebViewClient.ERROR_UNSUPPORTED_AUTH_SCHEME:
            case WebViewClient.ERROR_AUTHENTICATION:
            case WebViewClient.ERROR_PROXY_AUTHENTICATION:
            case WebViewClient.ERROR_IO:
            case WebViewClient.ERROR_REDIRECT_LOOP:
            case WebViewClient.ERROR_UNSUPPORTED_SCHEME:
            case WebViewClient.ERROR_FAILED_SSL_HANDSHAKE:
            case WebViewClient.ERROR_BAD_URL:
            case WebViewClient.ERROR_FILE:
            case WebViewClient.ERROR_TOO_MANY_REQUESTS:
            case WebViewClient.ERROR_UNSAFE_RESOURCE:
                MyLog.toastMakeTextShow(mApplicationContext,getClass().getName(),"WebViewClient,onReceivedError("+errorCode+") 에러 발생 " );;
                MyLog.e(TAG,"WebViewClient,onReceivedError("+errorCode+") 에러 발생 "  );
                break;
        }
    }
}

기타: 다이얼로그 팝업이 전체 풀화면으로 오지 않을 경우 아래 내용 반영[4]

<style name="Theme.DialogFullScreen" parent="@android:style/Theme.Holo.Light.Dialog">
        <item name="android:windowFullscreen">false</item> //false 처리
    </style>
    
    
    WindowManager.LayoutParams wmlp = dialog.getWindow().getAttributes();
        wmlp.width = android.view.WindowManager.LayoutParams.MATCH_PARENT;
        wmlp.height = android.view.WindowManager.LayoutParams.MATCH_PARENT;

참고자료:

[1] https://ymson.tistory.com/entry/WebView-windowopen-%EC%B2%98%EB%A6%AC

[2] https://mikelim.mintocean.com/entry/Android-Webview에서-새로운-창을-열때

[3]https://okky.kr/article/456078

[4]https://www.masterqna.com/android/61349/마테리얼-다이얼로그-custom-dialog-activity-좌우-기본-margin-값-없애는-방법은-없나요

 

MyWebView-20220830.zip
0.11MB

반응형