CookieManager setCookie Expires字段的识别

作者 : 开心源码 本文共6020个字,预计阅读时间需要16分钟 发布时间: 2022-05-12 共204人阅读
CookieManager cookieManager = CookieManager.getInstance();String domain = ".bilibili.com";String cookie1 = "bili_jct=b33fd713ea7cc6d29d65462794b28441; Domain=.bilibili.com; Expires=Expires=Sun, 18 Jan 1970 22:11:45 GMT+08:00";String cookie2 = "bili_jct=49b9bcc2c21f19cc9dcb8382b84cf552; Domain=.bilibili.com; Expires=Expires=周日, 18 1月 1970 22:11:40 GMT+08:00";cookieManager.setCookie(domain, cookie1);String cookie1R = cookieManager.getCookie(domain);Log.i("Cookie","load cookie1 "+cookie1R);cookieManager.setCookie(domain, cookie2);String cookie2R = cookieManager.getCookie(domain);Log.i("Cookie","load cookie1 "+cookie2R);

输出

: load cookie1 null: load cookie1 bili_jct=49b9bcc2c21f19cc9dcb8382b84cf552

问题起因就是英文状态是会识别Expires,所以在存入cookie1后CookieManager会认为这个cookie是过期的,所以会忽略掉这个cookie,返回null,但是在中文是不会识别Expires,所以可以返回cookie.
我尝试去跟踪了一下源码去发现为什么会出现这种情况

public abstract class CookieManager{       public abstract void setCookie(String url, String value);}

CookieManager是一个笼统类,setCookie也是一个笼统方法,所以必须找到其实现类

public static CookieManager getInstance() {        return WebViewFactory.getProvider().getCookieManager();}

进入getProvider

static WebViewFactoryProvider getProvider() {        synchronized (sProviderLock) {            // For now the main purpose of this function (and the factory abstraction) is to keep            // us honest and minimize usage of WebView internals when binding the proxy.            if (sProviderInstance != null) return sProviderInstance;            //代码省略            try {                Class<WebViewFactoryProvider> providerClass = getProviderClass();                Method staticFactory = null;                try {                    staticFactory = providerClass.getMethod(                        CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);                } catch (Exception e) {                    if (DEBUG) {                        Log.w(LOGTAG, "error instantiating provider with static factory method", e);                    }                }                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");                try {                    sProviderInstance = (WebViewFactoryProvider)                            staticFactory.invoke(null, new WebViewDelegate());                    if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);                    return sProviderInstance;                } catch (Exception e) {                    Log.e(LOGTAG, "error instantiating provider", e);                    throw new AndroidRuntimeException(e);                } finally {                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);                }            } finally {                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);                StrictMode.setThreadPolicy(oldPolicy);            }        }    }

可以看到sProviderInstance就是我们要的WebViewFactoryProvider,WebViewFactoryProvider是一个接口,它的创立实际上分为两步。

第一步:获取工厂类,这个工厂是用来创立WebViewFactoryProvider的实现类.

 Class<WebViewFactoryProvider> providerClass = getProviderClass();
private static Class<WebViewFactoryProvider> getProviderClass() {        //代码省略       ClassLoader clazzLoader = webViewContext.getClassLoader();       return getWebViewProviderClass(clazzLoader);}
public static Class<WebViewFactoryProvider> getWebViewProviderClass(ClassLoader clazzLoader)            throws ClassNotFoundException {        return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,                true, clazzLoader);    }
private static final String CHROMIUM_WEBVIEW_FACTORY =            "com.android.webview.chromium.WebViewChromiumFactoryProviderForO";

WebViewChromiumFactoryProviderForO就是目前获取的工厂类.

第二步:通过WebViewFactoryProvider的工厂类(现在已经知道了是WebViewChromiumFactoryProviderForO)创立WebViewFactoryProvider的实现类

再回到getProvider中看看下面这些代码:

                Method staticFactory = null;                try {                    staticFactory = providerClass.getMethod(                        CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);                } catch (Exception e) {                    if (DEBUG) {                        Log.w(LOGTAG, "error instantiating provider with static factory method", e);                    }                }                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");                try {                    sProviderInstance = (WebViewFactoryProvider)                            staticFactory.invoke(null, new WebViewDelegate());

可以看出来它是通过反射WebViewChromiumFactoryProviderForO的CHROMIUM_WEBVIEW_FACTORY_METHOD方法获取WebViewFactoryProvider的实现类.

private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";

源码中的CHROMIUM_WEBVIEW_FACTORY_METHOD是一个create函数.
Ok,我们现在找到了WebViewFactoryProvider的实现类是通过高反射WebViewChromiumFactoryProviderForO调用create创立的,那下面来看看WebViewChromiumFactoryProviderForO的源码怎样实现create.

class WebViewChromiumFactoryProviderForO extends WebViewChromiumFactoryProvider {    public static WebViewChromiumFactoryProvider create(android.webkit.WebViewDelegate delegate) {        return new WebViewChromiumFactoryProviderForO(delegate);    }    protected WebViewChromiumFactoryProviderForO(android.webkit.WebViewDelegate delegate) {        super(delegate);    }}

可以看出来WebViewChromiumFactoryProviderForO的create方法创立的其实就是它自己,但是它的很多方法都是在父类里面的,我们需要跟进父类去看看getCookieManager究竟返回的是什么,才能知道CookieManager的实现类是什么.
···
public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
@Override
public CookieManager getCookieManager() {
synchronized (mLock) {
if (mCookieManager == null) {
if (!mStarted) {
// We can use CookieManager without starting Chromium; the native code
// will bring up just the parts it needs to make this work on a temporary
// basis until Chromium is started for real. The temporary cookie manager
// needs the application context to have been set.
ContentMain.initApplicationContext(mWebViewDelegate.getApplication());
}
mCookieManager = new CookieManagerAdapter(new AwCookieManager());
}
}
return mCookieManager;
}
}
···
WebViewChromiumFactoryProvider中的getCookieManager返回的是一个CookieManagerAdapter,这里终于找到了CookieManager的实现类是CookieManagerAdapter
继续看看CookieManagerAdapter的setCookie函数怎样实现的

public class CookieManagerAdapter extends CookieManager {AwCookieManager mChromeCookieManager;@Override    public void setCookie(String url, String value) {        try {            mChromeCookieManager.setCookie(fixupUrl(url), value);        } catch (ParseException e) {            Log.e(LOGTAG, "Not setting cookie due to error parsing URL: " + url, e);        }    }}
@JNINamespace("android_webview")public final class AwCookieManager {    /**     * Set cookie for a given url. The old cookie with same host/path/name will     * be removed. The new cookie will be added if it is not expired or it does     * not have expiration which implies it is session cookie.     * @param url The url which cookie is set for     * @param value The value for set-cookie: in http response header     */   public void setCookie(final String url, final String value) {        nativeSetCookie(url, value);    }   private native void nativeSetCookie(String url, String value);}

最终走到了一个nativeSetCookie方法,它是native方法. so,目前暂时也没有办法跟进了,目前只能从注释推断这其实中文情况下面expiration是无效的.

自己是从事了七年开发的Android工程师,不少人私下问我,2019年Android进阶该怎样学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助那些想进阶提升Android开发,却又不知道怎样进阶学习的朋友。【包括高级UI、性能优化、架构师课程、NDK、Kotlin、混合式开发(ReactNative+Weex)、Flutter等架构技术资料】,希望能帮助到您面试前的复习且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。

资料获取方式:加入Android架构交流QQ群聊:513088520 ,进群即领取资料!!!

点击链接加入群聊【Android移动架构总群】:加入群聊

资料大全

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » CookieManager setCookie Expires字段的识别

发表回复