Tuesday, 9 July 2019

Android pop-up login screen with WebView

I am opening up a webpage using WebView that extends WebChromeClient.

The page has pop-up for login, as pictured here. enter image description here

When I use the setWebViewClient, it just prompts me white screen so my guess is that it does not support Authentication. When I tried creating custom WebViewClient, I found that it has a method called onReceivedHttpAuthRequest which I think is the correct place, but how do I display the pop-up on screen?

public class BaseWebViewClient extends WebViewClient {

public enum SpinnerMode {
    ALWAYS,
    FIRST,
    DISABLED
}

private final CoordinatorLayout webViewContainer;
private final RelativeLayout progressBarOverlay;

private WeakReference<BaseWebViewActivity> activityRef;
private BaseWebViewStateRemover stateRemover = new BaseWebViewStateRemover();

private boolean isFirstPage = true;
private SpinnerMode spinnerMode;

public BaseWebViewClient(BaseWebViewActivity activity, CoordinatorLayout container, RelativeLayout progressBarOverlay, SpinnerMode spinnerMode) {
    this.activityRef = new WeakReference<BaseWebViewActivity>(activity);
    this.webViewContainer = container;
    this.progressBarOverlay = progressBarOverlay;
    this.spinnerMode = spinnerMode != null ? spinnerMode : SpinnerMode.DISABLED;
}

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    view.loadUrl(url);
    return true;
}

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    Logger.e("onReceivedSslError: " + (error != null ? error.toString() : "null"));
    BaseWebViewActivity activity = activityRef.get();
    if (activity != null) {
        activity.onReceivedSslError(view, handler, error);
    }
    super.onReceivedSslError(view, handler, error);
}

@Nullable
@Override
public WebResourceResponse shouldInterceptRequest(final WebView view, WebResourceRequest request) {
    BaseWebViewActivity context = this.activityRef.get();
    if(context != null) {
        stateRemover.removeStateOnLogoutRequestMatch(context, request, view, webViewContainer);
    } else {
        Logger.w("Cannot remove app session context fully, activity reference is null");
    }
    return super.shouldInterceptRequest(view, request);
}

@Override
public void onPageStarted(final WebView webView, String url, Bitmap favicon) {
    super.onPageStarted(webView, url, favicon);
    Logger.d("Webview loading started for URL " + filterHashFragment(url));

    if (spinnerMode == SpinnerMode.ALWAYS
            || spinnerMode == SpinnerMode.FIRST && isFirstPage) {
        progressBarOverlay.setVisibility(View.VISIBLE);
        webView.setVisibility(View.GONE);
    }
}

@Override
public void onPageFinished(final WebView webView, String url) {
    super.onPageFinished(webView, url);
    Logger.d("Webview loading finished for URL " + filterHashFragment(url));

    if (spinnerMode == SpinnerMode.ALWAYS
            || spinnerMode == SpinnerMode.FIRST && isFirstPage) {
        // Add short delay because onPageFinished triggers often a bit early causing the
        // previous page to be briefly shown.
        SystemClock.sleep(150);
        Activity activity = activityRef.get();
        if(activity != null) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    progressBarOverlay.setVisibility(View.GONE);
                    webView.setVisibility(View.VISIBLE);
                }
            });
        } else {
            Logger.w("activity is not available");
        }
    }

    if (isFirstPage)
        isFirstPage = false;
}

private String filterHashFragment(String url) {
    return url.split("#")[0];
}

}

ChromeClient (it never reaches the onJsAlert)

public class BaseWebChromeClient extends WebChromeClient {
private WeakReference<BaseWebViewActivity> activityRef;

public BaseWebChromeClient(BaseWebViewActivity activity) {
    this.activityRef = new WeakReference<BaseWebViewActivity>(activity);
}

@Override
public boolean onConsoleMessage(ConsoleMessage cm) {
    Log.i("js console: ",   cm.message() + " -- line "
            + cm.lineNumber() + " of "
            + cm.sourceId());
    return true;
}

@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    Log.i("testing123", "got js alert");

    return super.onJsAlert(view, url, message, result);
}
}  

And I call Webview here:

    webView = findViewById(R.id.baseWebView);
    webViewContainer = findViewById(R.id.webview_container);
    WebSettings webSettings = webView.getSettings();
    webSettings.setJavaScriptEnabled(true);
    webSettings.setDomStorageEnabled(true);
    webSettings.setDatabaseEnabled(true);
    webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
    webView.getSettings().setAllowFileAccess(true);
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

    webView.setWebChromeClient(new BaseWebChromeClient(this));
    webView.setWebViewClient(new BaseWebViewClient(this, webViewContainer,
            (RelativeLayout)findViewById(R.id.progressBarOverlay), getSpinnerMode(intent)));

If that is not possible then maybe it is possible to create a custom login scren when the login button is clicked. But when creating the custom screen, then how can I send the login details (username/password) to the WebViewClient and how to get the response from there etc.

EDIT!!

Added my custom client code.

When giving the username and password to onReceivedHttpAuthRequest like this

@Override
public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host, String realm) {
    handler.proceed("username", "password");
}

The application logs in and continues as it should. When I give wrong credentials, the applications gives me an error Web page not available, net::ERR_TOO_MANY_RETRIES and when I give nothing I just see an empty white screen.



from Android pop-up login screen with WebView

No comments:

Post a Comment