安卓弹出式WebView登录屏幕

9

我正在使用扩展 WebChromeClientWebView 打开一个网页。

页面有一个登录弹窗,如下所示。 enter image description here

当我使用 setWebViewClient 时,它只会提示我一个白屏,所以我猜测它不支持 Authentication。当我尝试创建自定义的 WebViewClient 时,发现它有一个叫做 onReceivedHttpAuthRequest 的方法,我认为这是正确的位置,但是如何在屏幕上显示弹窗呢?

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(它永远不会到达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);
}
}  

我在这里调用Webview:

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

如果不可能的话,也许可以在点击登录按钮时创建自定义登录界面。但是当创建自定义界面时,如何将登录详情(用户名/密码)发送到WebViewClient,以及如何从那里获取响应等问题。 编辑!! 添加了我的自定义客户端代码。
在这样的情况下,将用户名和密码提供给onReceivedHttpAuthRequest
@Override
public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host, String realm) {
    handler.proceed("username", "password");
}

应用程序登录并按照预期继续执行。当我提供错误的凭据时,应用程序会给出一个错误:网页不可用net::ERR_TOO_MANY_RETRIES,而当我什么也不提供时,我只能看到一个空白屏幕。

请在此处发布URL以进行测试。 - Rahul Khurana
添加了我的答案。你还想试试吗? - Richard
当您输入错误的凭据时,现在会发生什么? - Rahul Khurana
对话框将会重置并再次询问。 - Richard
2个回答

0

我认为这个URL覆盖了包含此弹出窗口的其他URL。从你的问题来看,这个弹出窗口来自主URL而不是你的自定义URL。因此,在你的webChromeClient中,你必须使用以下代码。

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

这将帮助您显示弹出窗口。

要启用JS弹出窗口,请使用以下代码。

 @Override
     public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    //Required functionality here
   return super.onJsAlert(view, url, message, result);
  }

请确保在您的 Web 视图中启用 JavaScript:

webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true)

这个不起作用,我添加了自定义的客户端代码,也许这可以帮助理解出问题的原因。 - Richard
我有一个继承了WebChromeClient的类,并且其中有onJsAlert方法。但是当我从日志中检查它是否到达时,我发现它甚至没有到达那个部分。你提到的其他事情我已经做了。 - Richard
如果您遗漏了以下内容,可以添加:webView.getSettings().setPluginsEnabled(true); webView.getSettings().setAllowFileAccess(true); webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); - Tariqul Islam
我希望它能够工作,但似乎并没有。我添加了所有的内容,但是没有加上 webView.getSettings().setPluginsEnabled(true),因为它没有找到。 - Richard
也许这与它从未到达我的ChromeClient中的onJsAlert有关? - Richard

0
我的解决方案是计算重试次数,并在每个WebView客户端的onReceivedHttpAuthRequest上提示一个新的登录对话框。
@Override
public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host, String realm) {
    httpAuthRequestCounter++;
    if (httpAuthRequestCounter < 2) {
        alertDialog(handler);
        httpAuthRequestCounter = 0;
    } else {
        handler.cancel();
        goBackToLoginScreen();
    }
}

private void alertDialog(final HttpAuthHandler httpAuthHandler) {
    final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(baseWebViewActivity);
    LayoutInflater inflater = baseWebViewActivity.getLayoutInflater();
    View dialogView = inflater.inflate(R.layout.login_dialog, null);

    final EditText txtUsername = (EditText) dialogView.findViewById(R.id.dauth_userinput);
    final EditText txtPassword = (EditText) dialogView.findViewById(R.id.dauth_passinput);

    dialogBuilder.setView(dialogView);

    dialogBuilder.setPositiveButton(android.R.string.ok,
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    httpAuthHandler.proceed(txtUsername.getText().toString(), txtPassword.getText().toString());
                }
            }
    );
    dialogBuilder.setNegativeButton(android.R.string.cancel,
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton) {
                    httpAuthHandler.cancel();
                    goBackToLoginScreen();

                }
            }
    );

    dialogBuilder.setCancelable(false);

    AlertDialog alertDialog = dialogBuilder.create();
    alertDialog.show();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接