Android- Webview onPageFinished调用两次

ldxq2e6h  于 2023-06-20  发布在  Android
关注(0)|答案(9)|浏览(578)

我有一个活动,它通过拦截重定向URL来进行OAuth身份验证,一旦它出现在webview中。但是,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())。

n6lpvg4x

n6lpvg4x1#

如果onPageStarted方法启动onPageFinished后URL正常,但如果在onPageStarted启动shouldOverrideUrlLoading然后onPageFinished后URL被重定向。你只需要检查加载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中执行某些操作之前,请检查回调是否已进入shouldOverrideUrlLoading方法

@Override
public void onPageFinished(WebView view, String url) {

  if (!isRedirected) {
    //Do something you want when finished loading 
  }
}
sulc1iza

sulc1iza2#

也许它能帮助某人。
我有一些问题-方法onPageFinished调用了两次。
System. out. println();
在第一次执行时webView.getProgress()== 89,在第二次执行时== 100。100表示页面加载完成。

wvt8vs2t

wvt8vs2t3#

所以,上面的答案都没有给我一个解决方案,因为我的问题不是重定向,webview只是在同一个网页上调用onPageFinished 3次。我的解决方案如下,主要思想是在同一个URL上执行一次功能。

private String urlFinished = " ";

@Override
public void onPageFinished(WebView view, String url) {

    Logger.d(TAG, "onPageFinished");

    if (!urlFinished.equals(url)) {
      //Place your code here
    }

    urlFinished = url;

    super.onPageFinished(view, url);
}
olhwl3o2

olhwl3o24#

我正在查看一个事件,其中m.yotube.com触发了两个onPageFinished事件,但对我来说,它似乎不是由重定向引起的。经过一些研究,我发现在didStopLoading触发的onPageFinished之前,还有一个额外的onPageFinished由didFinishNavigation触发,其他页面也会收到。

参见:
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之前!)是我在Fragments中使用webview.restoreState()的时候。它在尝试恢复上次查看的页面时触发两个onPageFinished事件。

vsikbqxv

vsikbqxv5#

Android出于某种原因调用onPageFinished()两次(和onPageStarted()三次!)当加载的URL不是工作URL时。临时解决方案是将redirect_uri更改为工作网站的url;在这种情况下,我将其更改为https://www.google.com/(lol,对不起Google)。onPageFinished只被调用一次。
但是-我仍然想知道为什么当加载的URL不是一个工作的URL时,webview的行为会有所不同,以及什么是比将redirect_uri更改为google.com更好的解决方案。

gxwragnw

gxwragnw6#

这个技巧帮助我(不推荐,但帮助)

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

rkkpypqq7#

由于onPageFinished被多次调用,因此在执行任何进一步操作之前,您只需检查该方法是否已被调用。

@Override
public void onPageFinished(WebView view, String url) {
     if (loaded) {
          return;
     }

     // Do something...

     loaded = true;
}
rqcrx0a6

rqcrx0a68#

这里有一个更好的解决方案(不是最好的)。由于(在我的情况下)第二次触发非常快,我假设我可以依赖System.currentTimeMillis(),如下所示:

webView.webViewClient = object : WebViewClient() {
    private var recentPageFinish = 0L
    override fun onPageFinished(webview: WebView, url: String) {
        if (System.currentTimeMillis() - recentPageFinish > 1000) {
            parsePage(webview)
        }
        recentPageFinish = System.currentTimeMillis()
    }
}

该解决方法防止任何其他(短时间,1000 ms)链式触发,并且它从第一个触发调用parsePage()。无论如何,复杂的网页/网站不会在onPageFinished()触发器上准备好,因为javascript(计数器/帧/web-api-calls/等)正在运行。通常,如果要解析页面,应该在onPageFinished()触发器之后等待一段时间。

ujv3wf0j

ujv3wf0j9#

解决方案的最佳途径;
问题--> Android设备onPagefinished调用两次。(IOS设备没有问题)
解决方案-->在OnLoadStop之前你可以调用定义bool参数的onLoadStart方法。

*onLoadStart:(controller,url)async{ //bool param define this section },
*onLoadStop:(controller,url)async { if(bool param){ // than control enter code here } }

相关问题