Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中CookieManager的底層實現

Android中CookieManager的底層實現

編輯:關於Android編程

          前幾天,項目組有個技術問題,想用本地加載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

                

[java] 
CookieManager.getInstance().getCookie(url); 


2.CookieManager的getInstance()

[java] 
/**
    * 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是個工廠模式,額
[java] 
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
[java] 
@Override 
       public CookieManager getCookieManager() { 
           return CookieManagerClassic.getInstance(); 
       } 

5. getCookie方法 實現在CookieManagerClassic上
[java]
@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。。。
[java] 
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情報
[java] 
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(); 

[java] 
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文件,無敵了

[java] 
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; 

#以上#

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved