zoukankan      html  css  js  c++  java
  • Android WebView 302斗争之旅

    一.背景

    越来越多的业务接入,项目内多多少少会出现几个H5页面,只是单纯的提供WebView容器接入H5页面根本满足不了需求,他们需要登录态,需要制定协议控制Native的导航栏,或者需要JsBridge做一些更复杂的操作,这篇主要讲登录态出现的问题。

    二.涉及的知识

    Android WebView加载url的时候,我们是这样做监听的:

    • 页面加载前会回调onPageStarted
    • 页面加载完成会回调onPageFinished
    • 当页面加载前且在onPageStarted后会回调shouldOverrideUrlLoading让我们决定是否自己处理这个url
    public class PerformanceWebClient extends WebViewClient {
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return super.shouldOverrideUrlLoading(view, url);
        }
    
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }
    
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }
    }
    

    三.自定义返回栈

    14年最初接触的项目,WebView页面是需要登录态的,处理方式就是shouldOverrideUrlLoading方法中,直接将url后面拼入参数,return true告知WebView组件url我们已经处理,你不用管了。

    public class PerformanceWebClient extends WebViewClient {
    
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith("http") || url.startsWith("https")) {
                view.loadUrl(appendParamsToUrl(url));
                return true;
            } else if (isScheme(url)) {
                return true;
            }
            return false;
        }
    
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
        }
    }
    

    简单的代码结构大致是这样,但是迅速暴露出一个问题:302页面返回栈。

    我们主动load的页面会加入到返回栈内,而当我们webview.goBack()的时候,加载的时候还是一个302,导致无法正常关闭页面。

    这时想到一个方法,自己定义返回栈。

    问题是,一个url入栈的标准是什么?

    举一个栗子:

    A==302==>B==302==>C
    

    加载A的url查看回调顺序是:

    onPageStartedA==>onPageStartedB==>onPageStartedC==>onPageFinishedC
    

    从这个角度来看,貌似onPageFinished中将url作为已加载的url挺靠谱的,但是现在存在一个问题,我每次回退栈都要以重新load的形式刷新页面,性能和流量都有耗费。

    还存在一个问题,在实际情况中遇到,某一个业务url加载形式例如:

    A==302==>B==302==>C==302==>D
    

    加载A的url查看回调顺序是这样的:

    onPageStartedA==>onPageStartedB==>onPageStartedC==>onPageFinishedC==>onPageStartedD==>onPageFinishedD
    

    C页面是302到D的,但是也走了onPageStarted方法,猜测是做了某些操作再主动重定向的,这种url我们也不希望加入返回栈内,但是我们不能准确的检测到。

    四.尝试优化

    在后来接手的另一个项目中,也存在了302返回栈的问题,既要保留登陆态,又需要302不加入返回栈。

    这时看到一个这样的处理方式:

    class MerchantOnTouchListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            try {
                WebView.HitTestResult hr = ((WebView) view).getHitTestResult();
                if (hr != null && mLastUrl != null) {
                    switch (hr.getType()) {
                        case WebView.HitTestResult.SRC_ANCHOR_TYPE:
                        case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
                            break;
                        case WebView.HitTestResult.UNKNOWN_TYPE:
                            return true;
                            break;
                        default:
                            return false;
                    }
                    if (previous.isEmpty() || !previous.get(previous.size() - 1).equals(mLastUrl)) {
                        previous.add(mLastUrl);
                    }
                }
            } catch (Exception ignored) {
            }
            return false;
        }
    }
    

    当我们触摸屏幕时(通常就是开始点击链接)使用HitTestResult去看状态,如果得到的type是链接跳转类型,那么将最后加载的url加入返回栈。

    实际效果是:302被避免了,但是页面内如果触摸的地方url有变化(比如params变了)也会加入返回栈,回退次数还是增加了,而且解决不了重新加载的问题。

    就在这时得知了最开始接触的项目更换了登陆方式,App的登陆就是H5页面,登陆成功后拿到Cookie,Cookie既可以给Native访问Api使用,也可以在H5页面做登录态使用,页面栈全部交给WebView容器处理。

    以为这就结束了么?

    但是又出现了一个问题:运营商劫持

    国内的网络环境大家比较了解,Headers的丢失率比较高,丢失了Cookie就等于丢失了登陆状态,这是其中一点;其次是如果业务发展已经很庞大,很难从Native Token 走SSO的方式转化为Cookie方式。

    五.总结

    目前经历了几个项目,一直没有很优雅的解决302的问题,目前的做法也有一些瑕疵,希望在以后的工作中能找到更好的方法。

  • 相关阅读:
    torch上疑问用法总结
    matplotlib库介绍
    java学习总结
    java高级并发编程实战
    java的spi思想--打破双亲委派模型的操作
    linux设置静态ip步骤流程
    jvm调优参数设置
    jvisualvm插件的基本使用
    jvm常见的gc种类
    jvm调优案例与步骤
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5318354.html
Copyright © 2011-2022 走看看