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;
}
#以上#
posted @ 2012-12-01 21:09 zhangyoushugz 阅读(...) 评论(...) 编辑 收藏