Я открываю webpage, используя WebView, который расширяет WebChromeClient.
На странице есть всплывающее окно для входа, как показано здесь.

Когда я использую 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)));
Если это невозможно, возможно, можно создать собственный экран входа в систему при нажатии кнопки входа. Но при создании пользовательского экрана, как я могу отправить login details (username/password) на WebViewClient и как получить оттуда ответ и т. д.
РЕДАКТИРОВАТЬ!!
Добавлен мой пользовательский код клиента.
Давая логин и пароль onReceivedHttpAuthRequest вот так
@Override
public void onReceivedHttpAuthRequest(WebView view, final HttpAuthHandler handler, String host, String realm) {
handler.proceed("username", "password");
}
Приложение входит в систему и продолжает работу, как и должно. Когда я даю неправильные учетные данные, приложения выдают мне ошибку Web page not available, net::ERR_TOO_MANY_RETRIES, а когда я ничего не даю, я просто вижу пустой белый экран.
Добавил свой ответ. Вы все еще хотите попробовать?
Итак, что происходит, когда вы вводите неправильные учетные данные
Диалог перезагрузится и спросит снова
Я думаю, что этот 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);
}
И убедитесь, что вы включили javascript Enable в своем веб-представлении:
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true)
Это не сработало, добавил свой собственный клиентский код, возможно, это поможет понять, что здесь не так.
У меня есть класс, который расширяет WebChromeClient и в котором есть onJsAlert. Но при проверке из журналов, попадает ли он туда, я обнаружил, что он даже не доходит до этой части. Другие вещи, которые вы упомянули, у меня уже есть.
Если вы пропустите ниже вещи, которые вы можете добавить. webView.getSettings().setPluginsEnabled(true); webView.getSettings().setAllowFileAccess(true); webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
Я бы хотел, чтобы это сработало, но кажется, что это не так.. добавил все из них, кроме `webView.getSettings().setPluginsEnabled(true)`, потому что он не нашел его
Может быть, это как-то связано с тем, что он никогда не достигает onJsAlert в моем ChromeClient ?
Мое решение состояло в том, чтобы подсчитывать повторные попытки и запрашивать новый диалог входа в систему для каждого onReceivedHttpAuthRequest в WebView клиенте.
@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();
}
Пожалуйста, отправьте URL-адрес здесь, чтобы проверить