Android-Webview onPageFinished Called Twice
У меня есть активность, которая делает аутентификацию OAuth, перехватывая URL-адрес перенаправления, когда он появляется в веб-просмотре. Однако функция onPageFinished почему-то вызвана дважды по какой-то причине, что действительно испортило мое приложение. Здесь код:
public class WebViewActivity extends Activity {
private WebView gWebView;
final String REDIRECT_URI = "https://localhost:5000/receive_code";
final String CLIENT_ID = "can't post it here";
final String CLIENT_SECRET = "can't post it here";
final String SCOPE = "basic names genomes analyses";
Hashtable<String, String> riskPairs;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);
gWebView = (WebView) findViewById(R.id.webView1);
gWebView.loadUrl("https://api.23andme.com/authorize/?redirect_uri="
+ REDIRECT_URI + "&response_type=code&client_id=" + CLIENT_ID
+ "&scope=" + SCOPE);
Log.d("WEBVIEW", "got to webpage");
gWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (url.startsWith(REDIRECT_URI)) {
Log.d("WEBVIEW", "onpagefinished is called");
System.out.println("got to override");
if (url.indexOf("code=") != -1) {
//if the query contains code
String queryString = null;
try {
queryString = new URL(url).getQuery();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(queryString);
String[] params = queryString.split("&");
String code = null;
for (String param : params) {
if (param.startsWith("code=")) {
code = param.substring(param.indexOf('=') + 1);
}
}
gWebView.setVisibility(View.GONE);
new PostRequest().execute(code);
// don't go to redirectUri
}
}
}
});
}
class PostRequest extends AsyncTask<String,Void,String>{ code getting client data...}
P.S.
Пожалуйста, не отмечайте это как дубликат... Я прочитал аналогичный вопрос в StackOverflow и вызвал ShouldOverrideUrlLoading для меня не работает (именно поэтому я использовал onPageFinished() в первую очередь).
Ответы
Ответ 1
Если URL-адрес в порядке после того, как метод onPageStarted запущен onPageFinished, но если URL-адрес перенаправлен после
onPageStarted запускает shouldOverrideUrlLoading, а затем onPageFinished.
Вы должны просто проверить, перенаправлен ли URL загрузки или нет.
private boolean isRedirected;
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (!isRedirected) {
//Do something you want when starts loading
}
isRedirected = false;
}
Если URL-адрес перенаправлен, обратный вызов запускает эту функцию
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
isRedirected = true;
return true;
}
Прежде чем делать что-то в onPageFinished, проверьте, был ли обратный вызов введен в метод toOverrideUrlLoading
@Override
public void onPageFinished(WebView view, String url) {
if (!isRedirected) {
//Do something you want when finished loading
}
}
Ответ 2
Android почему-то вызывает onPageFinished() дважды (и onPageStarted() три раза!), когда загруженный URL-адрес не работает. Временное решение изменяет redirect_uri на URL рабочего веб-сайта; в этом случае я изменил его на https://www.google.com/ (lol, извините Google). onPageFinished затем вызывается только один раз.
НО. Я все еще хочу получить ответы на вопрос о том, почему webview ведет себя по-другому, когда загруженный URL-адрес не является рабочим, и что является лучшим решением, чем изменение redirect_uri на google.com.
Ответ 3
Я просматриваю событие, когда m.yotube.com запускает два события onPageFinished, но это не похоже на перенаправление для меня. После некоторых исследований я обнаружил, что есть еще один дополнительный параметр onPageFinished, инициированный didFinishNavigation, до того, как был вызван didStopLoading, который также получает другие страницы.
![stack trace #1]()
![stack trace #2]()
См. также:
https://chromium.googlesource.com/chromium/src.git/+/master/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@Override
public void didFinishNavigation(final String url, boolean isInMainFrame, boolean isErrorPage,
boolean hasCommitted, boolean isSameDocument, boolean isFragmentNavigation,
Integer pageTransition, int errorCode, String errorDescription, int httpStatusCode) {
...
if (client != null && isFragmentNavigation) {
client.getCallbackHelper().postOnPageFinished(url);
}
}
@Override
public void didStopLoading(String validatedUrl) {
if (validatedUrl.length() == 0) validatedUrl = ContentUrlConstants.ABOUT_BLANK_DISPLAY_URL;
AwContentsClient client = getClientIfNeedToFireCallback(validatedUrl);
if (client != null && validatedUrl.equals(mLastDidFinishLoadUrl)) {
client.getCallbackHelper().postOnPageFinished(validatedUrl);
mLastDidFinishLoadUrl = null;
}
}
В другом экземпляре я получаю дополнительные onPageFinished звонки (даже до onPageStarted!), когда я использую webview.restoreState() в фрагментах. он запускает два события onPageFinished при попытке возобновить последнюю просматриваемую страницу.
Ответ 4
Этот трюк помогает мне (не рекомендуется, но помогает)
private boolean alreadyEvaluated = false;
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
Logger.d(TAG, "onPageStarted");
super.onPageStarted(view, url, favicon);
}
@Override
public void onPageFinished(WebView view, String url) {
Logger.d(TAG, "onPageFinished");
if (!alreadyEvaluated) {
alreadyEvaluated = true;
view.loadUrl("javascript:window.MyJavaScript.getPageText(document.getElementsByTagName('body')[0].innerText);");
} else {
alreadyEvaluated = false;
}
super.onPageFinished(view, url);
}