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
問(wèn)題原因就是英文狀態(tài)是會(huì)識(shí)別Expires岖妄,所以在存入cookie1后CookieManager會(huì)認(rèn)為這個(gè)cookie是過(guò)期的,所以會(huì)忽略掉這個(gè)cookie,返回null,但是在中文是不會(huì)識(shí)別Expires咏闪,所以可以返回cookie.
我嘗試去跟蹤了一下源碼去發(fā)現(xiàn)為什么會(huì)出現(xiàn)這種情況
public abstract class CookieManager{
public abstract void setCookie(String url, String value);
}
CookieManager是一個(gè)抽象類,setCookie也是一個(gè)抽象方法,所以必需找到其實(shí)現(xiàn)類
public static CookieManager getInstance() {
return WebViewFactory.getProvider().getCookieManager();
}
進(jìn)入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是一個(gè)接口备图,它的創(chuàng)建實(shí)際上分為兩步。
第一步:獲取工廠類赶袄,這個(gè)工廠是用來(lái)創(chuàng)建WebViewFactoryProvider的實(shí)現(xiàn)類.
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就是目前獲取的工廠類.
第二步:通過(guò)WebViewFactoryProvider的工廠類(現(xiàn)在已經(jīng)知道了是WebViewChromiumFactoryProviderForO)創(chuàng)建WebViewFactoryProvider的實(shí)現(xiàn)類
再回到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());
可以看出來(lái)它是通過(guò)反射WebViewChromiumFactoryProviderForO的CHROMIUM_WEBVIEW_FACTORY_METHOD方法獲取WebViewFactoryProvider的實(shí)現(xiàn)類.
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
源碼中的CHROMIUM_WEBVIEW_FACTORY_METHOD是一個(gè)create函數(shù).
Ok,我們現(xiàn)在找到了WebViewFactoryProvider的實(shí)現(xiàn)類是通過(guò)高反射WebViewChromiumFactoryProviderForO調(diào)用create創(chuàng)建的揽涮,那下面來(lái)看看WebViewChromiumFactoryProviderForO的源碼怎么實(shí)現(xiàn)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);
}
}
可以看出來(lái)WebViewChromiumFactoryProviderForO的create方法創(chuàng)建的其實(shí)就是它自己,但是它的很多方法都是在父類里面的饿肺,我們需要跟進(jìn)父類去看看getCookieManager到底返回的是什么蒋困,才能知道CookieManager的實(shí)現(xiàn)類是什么.
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返回的是一個(gè)CookieManagerAdapter,這里終于找到了CookieManager的實(shí)現(xiàn)類是CookieManagerAdapter
繼續(xù)看看CookieManagerAdapter的setCookie函數(shù)怎么實(shí)現(xiàn)的
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);
}
最終走到了一個(gè)nativeSetCookie方法敬辣,它是native方法. so,目前暫時(shí)也沒(méi)有辦法跟進(jìn)了,目前只能從注釋推斷這其實(shí)中文情況下面expiration是無(wú)效的.