Android中CookieManager的底层实现

 

                  前几天,项目组有个技术问题,想用本地加载html, js写cookie的方法,绕过去。

                  想法是没有问题的, 但是测试的时候发现, 每次重新打开App, 都取不到以前Cookie里面设的值。

                 后来去App/data下面找WebView.db,打开来一看,cookie情报根本没有存。

                 原因是js写cookie的时候,没有指明expire, WebKit默认把它当成临时cookie, webview终了之后就丢失了。

                 这个问题本身不复杂,不过趁机我看了一把Andorid底层读取Cookie的source root:

 

以下source root

 

  1. 取Cookie的API

                 

  1. CookieManager.getInstance().getCookie(url); 
CookieManager.getInstance().getCookie(url);

 

2.CookieManager的getInstance()

 

  1. /**
  2.     * Gets the singleton CookieManager instance. If this method is used
  3.     * before the application instantiates a {@link WebView} instance,
  4.     * {@link CookieSyncManager#createInstance(Context)} must be called
  5.     * first.
  6.     *
  7.     * @return the singleton CookieManager instance
  8.     */ 
  9.    publicstaticsynchronized CookieManager getInstance() { 
  10.        return WebViewFactory.getProvider().getCookieManager(); 
  11.    } 
 /**

     * Gets the singleton CookieManager instance. If this method is used

     * before the application instantiates a {@link WebView} instance,

     * {@link CookieSyncManager#createInstance(Context)} must be called

     * first.

     *

     * @return the singleton CookieManager instance

     */

    public static synchronized CookieManager getInstance() {

        return WebViewFactory.getProvider().getCookieManager();

    }
3.WebViewFactory是个工厂模式,额

 

 

  1. staticsynchronized WebViewFactoryProvider getProvider() { 
  2.     // For now the main purpose of this function (and the factory abstraction) is to keep  
  3.     // us honest and minimize usage of WebViewClassic internals when binding the proxy.  
  4.     if (sProviderInstance != null) return sProviderInstance; 
  5.  
  6.     sProviderInstance = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY); 
  7.     if (sProviderInstance == null) { 
  8.         if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage"); 
  9.         sProviderInstance = new WebViewClassic.Factory(); 
  10.     } 
  11.     return sProviderInstance; 
    static synchronized WebViewFactoryProvider getProvider() {

        // For now the main purpose of this function (and the factory abstraction) is to keep

        // us honest and minimize usage of WebViewClassic internals when binding the proxy.

        if (sProviderInstance != null) return sProviderInstance;



        sProviderInstance = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY);

        if (sProviderInstance == null) {

            if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");

            sProviderInstance = new WebViewClassic.Factory();

        }

        return sProviderInstance;

    }
4.层层嵌套,最后生成的instance是CookieManagerClassic

 

 

  1. @Override 
  2.        public CookieManager getCookieManager() { 
  3.            return CookieManagerClassic.getInstance(); 
  4.        } 
 @Override

        public CookieManager getCookieManager() {

            return CookieManagerClassic.getInstance();

        }
5. getCookie方法 实现在CookieManagerClassic上

 

 

  1. @Override 
  2.   public String getCookie(String url) { 
  3.       return getCookie(url, false); 
  4.   } 
  5.  
  6.   @Override 
  7.   public String getCookie(String url, boolean privateBrowsing) { 
  8.       WebAddress uri; 
  9.       try
  10.           uri = new WebAddress(url); 
  11.       } catch (ParseException ex) { 
  12.           Log.e(LOGTAG, "Bad address: " + url); 
  13.           returnnull
  14.       } 
  15.  
  16.       return nativeGetCookie(uri.toString(), privateBrowsing); 
  17.   } 
  @Override

    public String getCookie(String url) {

        return getCookie(url, false);

    }



    @Override

    public String getCookie(String url, boolean privateBrowsing) {

        WebAddress uri;

        try {

            uri = new WebAddress(url);

        } catch (ParseException ex) {

            Log.e(LOGTAG, "Bad address: " + url);

            return null;

        }



        return nativeGetCookie(uri.toString(), privateBrowsing);

    }
6. nativeGetCookie定义在CookieManager.cpp里, 恩。。。。JNI。。。

 

 

  1. static jstring getCookie(JNIEnv* env, jobject, jstring url, jboolean privateBrowsing) 
  2.     GURL gurl(jstringToStdString(env, url)); 
  3.     CookieOptions options; 
  4.     options.set_include_httponly(); 
  5.     std::string cookies = WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options); 
  6.     return stdStringToJstring(env, cookies); 
static jstring getCookie(JNIEnv* env, jobject, jstring url, jboolean privateBrowsing)

{

    GURL gurl(jstringToStdString(env, url));

    CookieOptions options;

    options.set_include_httponly();

    std::string cookies = WebCookieJar::get(privateBrowsing)->cookieStore()->GetCookieMonster()->GetCookiesWithOptions(gurl, options);

    return stdStringToJstring(env, cookies);

}

7. WebCookieJar.cpp中,定义了从哪里去取得Cookie情报

 

 

  1. WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing) 
  2.     MutexLocker lock(instanceMutex); 
  3.     if (!isFirstInstanceCreated && fileSchemeCookiesEnabled) 
  4.         net::CookieMonster::EnableFileScheme(); 
  5.     isFirstInstanceCreated = true
  6.     scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing); 
  7.     if (!instancePtr->get()) 
  8.         *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing)); 
  9.     return instancePtr->get(); 
WebCookieJar* WebCookieJar::get(bool isPrivateBrowsing)

{

    MutexLocker lock(instanceMutex);

    if (!isFirstInstanceCreated && fileSchemeCookiesEnabled)

        net::CookieMonster::EnableFileScheme();

    isFirstInstanceCreated = true;

    scoped_refptr<WebCookieJar>* instancePtr = instance(isPrivateBrowsing);

    if (!instancePtr->get())

        *instancePtr = new WebCookieJar(databaseDirectory(isPrivateBrowsing));

    return instancePtr->get();

}
  1. static std::string databaseDirectory(bool isPrivateBrowsing) 
  2.     staticconstchar* const kDatabaseFilename = "/webviewCookiesChromium.db"
  3.     staticconstchar* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db"
  4.  
  5.     std::string databaseFilePath = databaseDirectory(); 
  6.     databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename); 
  7.     return databaseFilePath; 
static std::string databaseDirectory(bool isPrivateBrowsing)

{

    static const char* const kDatabaseFilename = "/webviewCookiesChromium.db";

    static const char* const kDatabaseFilenamePrivateBrowsing = "/webviewCookiesChromiumPrivate.db";



    std::string databaseFilePath = databaseDirectory();

    databaseFilePath.append(isPrivateBrowsing ? kDatabaseFilenamePrivateBrowsing : kDatabaseFilename);

    return databaseFilePath;

}
※Android3.0以上是webviewCookiesChromium.db, 以下是WebView.db文件

 

 

8.最后读取Cookie情报发生在cookie_monster.cc。 额,最后调到C++, 去读.db文件,无敌了

 

  1. std::string CookieMonster::GetCookiesWithOptions(const GURL& url, 
  2.                                                  const CookieOptions& options) { 
  3.   base::AutoLock autolock(lock_); 
  4.   InitIfNecessary(); 
  5.  
  6.   if (!HasCookieableScheme(url)) { 
  7.     return std::string(); 
  8.   } 
  9.  
  10.   TimeTicks start_time(TimeTicks::Now()); 
  11.  
  12.   // Get the cookies for this host and its domain(s).  
  13.   std::vector<CanonicalCookie*> cookies; 
  14.   FindCookiesForHostAndDomain(url, options, true, &cookies); 
  15.   std::sort(cookies.begin(), cookies.end(), CookieSorter); 
  16.  
  17.   std::string cookie_line; 
  18.   for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); 
  19.        it != cookies.end(); ++it) { 
  20.     if (it != cookies.begin()) 
  21.       cookie_line += "; "
  22.     // In Mozilla if you set a cookie like AAAA, it will have an empty token  
  23.     // and a value of AAAA.  When it sends the cookie back, it will send AAAA,  
  24.     // so we need to avoid sending =AAAA for a blank token value.  
  25.     if (!(*it)->Name().empty()) 
  26.       cookie_line += (*it)->Name() + "="
  27.     cookie_line += (*it)->Value(); 
  28.   } 
  29.  
  30.   histogram_time_get_->AddTime(TimeTicks::Now() - start_time); 
  31.  
  32.   VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line; 
  33.  
  34.   return cookie_line; 
std::string CookieMonster::GetCookiesWithOptions(const GURL& url,

                                                 const CookieOptions& options) {

  base::AutoLock autolock(lock_);

  InitIfNecessary();



  if (!HasCookieableScheme(url)) {

    return std::string();

  }



  TimeTicks start_time(TimeTicks::Now());



  // Get the cookies for this host and its domain(s).

  std::vector<CanonicalCookie*> cookies;

  FindCookiesForHostAndDomain(url, options, true, &cookies);

  std::sort(cookies.begin(), cookies.end(), CookieSorter);



  std::string cookie_line;

  for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();

       it != cookies.end(); ++it) {

    if (it != cookies.begin())

      cookie_line += "; ";

    // In Mozilla if you set a cookie like AAAA, it will have an empty token

    // and a value of AAAA.  When it sends the cookie back, it will send AAAA,

    // so we need to avoid sending =AAAA for a blank token value.

    if (!(*it)->Name().empty())

      cookie_line += (*it)->Name() + "=";

    cookie_line += (*it)->Value();

  }



  histogram_time_get_->AddTime(TimeTicks::Now() - start_time);



  VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line;



  return cookie_line;

}
#以上#

你可能感兴趣的:(android)