The Android implementation clears the cookie of a single domain name

  • 2021-11-30 01:20:11
  • OfStack

Today, PM puts forward a requirement: When users exit the current web page, only cookie related to the domain name visited by the web page will be cleared, and cookie of other domain names will be retained.

After checking API of CookieManager for 1 time, it was found that only removeAllCookie (), and API of cookie, a separate domain name, was not cleared. . . Think about it, too. After using browsers for so many years, when have you seen this function?

Since the system does not provide an interface, it can only find its own way to clear it.

First of all, we should find out where Cookie exists.

In/data/data/ < package > /app_webview directory, found an Cookies file, although it does not have. db extension, but in fact it is an sqlite database! Go in and look at 1, and the data is stored in the cookies table inside:


sqlite> .tables
cookies meta  
sqlite> .dump cookies
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE cookies (creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,host_key TEXT NOT NULL,name TEXT NOT NULL,value TEXT NOT NULL,path TEXT NOT NULL,expires_utc INTEGER NOT NULL,secure INTEGER NOT NULL,httponly INTEGER NOT NULL,last_access_utc INTEGER NOT NULL, has_expires INTEGER NOT NULL DEFAULT 1, persistent INTEGER NOT NULL DEFAULT 1,priority INTEGER NOT NULL DEFAULT 1,encrypted_value BLOB DEFAULT '',firstpartyonly INTEGER NOT NULL DEFAULT 0);
INSERT INTO "cookies" VALUES(13122904895970126,'.hm.baidu.com','HMACCOUNT','1E0666871DC4BB45','/',13792186776970126,0,0,13122906283432123,1,1,1,X'',0);
INSERT INTO "cookies" VALUES(13122905170226445,'.facebook.com','reg_fb_ref','https%3A%2F%2Fm.facebook.com%2F%3Frefsrc%3Dhttps%253A%252F%252Fwww.facebook.com%252F','/',0,0,1,13122905170226445,0,0,1,X'',0);
INSERT INTO "cookies" VALUES(13122905170227182,'.facebook.com','reg_fb_gate','https%3A%2F%2Fm.facebook.com%2F%3Frefsrc%3Dhttps%253A%252F%252Fwww.facebook.com%252F','/',0,0,1,13122905170227182,0,0,1,X'',0);
INSERT INTO "cookies" VALUES(13122905170227393,'.facebook.com','m_ts','1478103992','/',0,0,0,13122905170227393,0,0,1,X'',0);
INSERT INTO "cookies" VALUES(13122905172258460,'.facebook.com','datr','uxMaWFe4eAqp6W2_dDu2MpA1','/',13185977172258460,0,1,13122905172258460,1,1,1,X'',0);
INSERT INTO "cookies" VALUES(13122905172508865,'.facebook.com','fr','0EhMpmXi6717eJE6Y..BYGhO4.Dd.AAA.0.0.BYGhO7.AWUFjMmY','/',13130681172508865,0,1,13122905172508865,1,1,1,X'',0);
CREATE INDEX domain ON cookies(host_key);
CREATE INDEX is_transient ON cookies(persistent) where persistent != 1;
COMMIT;

What is stored here is actually all the information contained in the Set-Cookie field in the HTTP header. Taking facebook as an example, it is actually:

Set-Cookie: m_ts=1478103992; datr=uxMaWFe4eAqp6W2_dDu2MpA1; fr=OEhMpmXi6717eJE6Y; path=/; domain=.facebook.com

As long as we erase this information, webview will not have a valid cookie the next time it sends a request. The most direct idea is to call the setCookie () method of CookieManager and empty or set these fields to expire. I searched StackOverflow for 1 time and found a post to discuss similar ideas. I tried it for 1 time and found it still couldn't. . .

Original link: http://stackoverflow.com/questions/2834180/how-to-remove-using-cookiemanager-for-a-specific-domain/11621738 # 11621738

Let's talk about 1 pile of pits encountered:

1. In the same domain name, the parameters of cookie band are different in http and https. For example, http://www. facebook. com and https://www. facebook. com have completely different parameters obtained through CookieManager. getCookie (). This problem bothered me for more than an hour, because I found that some parameters could not be cleared anyway. . .

2. There is a pile of domain names beginning with "." in the Cookies table, such as ". facebook. com" in the table, and one of its parameters cannot be deleted with complete domain names. For example, if you call CookieManager.setCookie () for http://www.facebook.com to clear the field information, you will find that there is one more record of "www.facebook.com" in the table, but the original record of ". facebook.com" still exists and the field information has not been cleared.

3. Using a domain name that begins with ".", such as ". facebook. com", you can't get the full parameter list when you call CookieManager. getCookie ().

4. Different websites will add a number of records to the Cookies table. Take facebook as an example, there may be three records in the table: "www. facebook. com", ". www. facebook. com" and ". facebook. com".

Finally, let's say the conclusion. After many twists and turns, we finally found a usable method, and the pro-test 5.1/6.0 platform is available. In fact, it is also very simple and rude, that is, to roll out all the records mentioned in Article 4 above, and would rather kill 1,000 by mistake than let go of one. . .

Attach the code (note that the domain parameter is the full domain name with the protocol, such as https://www.baidu.com):


private static void deleteCookiesForDomain(Context context, String domain) {
    CookieManager cookieManager = CookieManager.getInstance();
    if (cookieManager == null) return;
 
    /* http://code.google.com/p/android/issues/detail?id=19294 */
    if (Build.VERSION.SDK_INT < 11) {
      /* Trim leading '.'s */
      if (domain.startsWith(".")) domain = domain.substring(1);
    }
 
    String cookieGlob = cookieManager.getCookie(domain);
    if (cookieGlob != null) {
      String[] cookies = cookieGlob.split(";");
      for (String cookieTuple : cookies) {
        String[] cookieParts = cookieTuple.split("=");
        HashSet<String> domainSet = getDomainSet(domain);
        for (String dm : domainSet) {
          /* Set an expire time so that this field will be removed after calling sync() */
          cookieManager.setCookie(dm, cookieParts[0] + "=; Expires=Wed, 31 Dec 2015 23:59:59 GMT");
        }
      }
      cookieManager.sync();
    }
  }
 
  private static HashSet<String> getDomainSet(String domain) {
    HashSet<String> domainSet = new HashSet<>();
    String host = Uri.parse(domain).getHost();
 
    domainSet.add(host);
    domainSet.add("." + host);
    // exclude domain like "baidu.com"
    if (host.indexOf(".") != host.lastIndexOf(".")) {
      domainSet.add(host.substring(host.indexOf('.')));
    }
 
    return domainSet;
  }

Related articles: