업무의 배경:
하이브리드 앱 구현시에 휴대폰 인증, 우편번호 찾기 등에서 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-값-없애는-방법은-없나요
'안드로이드' 카테고리의 다른 글
[Android] Webview에서 URI_INTENT_SCHEME 오류 (0) | 2021.09.29 |
---|---|
[Android] 웹뷰(webview) ShouldOverrideUrlLoading을 이용하여 응용 프로그램이 제어할 수 있는 기회를 처리 방법(url scheme) (0) | 2021.09.29 |
[Android] 하이브리드 앱 만들기 (기본편)Hybrid webview default (0) | 2021.09.29 |
[Android] 웹뷰(webview) 디버깅(debugging) 방법. (0) | 2021.09.29 |
Android 설치된 앱(패키지) 등록된 permission 확인 (0) | 2021.09.29 |