Android实现清除单个域名的cookie
作者:TurkeyCock 发布时间:2021-10-09 01:57:52
今天PM提了个需求:用户退出当前网页时,只清除该网页访问的域名相关的cookie,保留其他域名的cookie。
查了一下CookieManager的API,发现只有removeAllCookie(),没有清除单独域名cookie的API。。。想想也是,用了这么多年的浏览器,啥时候见过这功能?
既然系统没有提供接口,那就是只能自己想办法去清了。
首先要搞清楚Cookie存在哪里吧?
在/data/data/<package>/app_webview目录下,找到一个Cookies文件,虽然它没有.db扩展名,但是其实它就是一个sqlite数据库!进去看一下,数据都存在里面的cookies表里:
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;
这里面存储的其实就是HTTP头里的Set-Cookie字段包含的所有信息,以facebook为例,拼起来其实就是:
Set-Cookie: m_ts=1478103992; datr=uxMaWFe4eAqp6W2_dDu2MpA1; fr=OEhMpmXi6717eJE6Y; path=/; domain=.facebook.com
只要我们把这些信息清除掉,webview下次发请求的时候就没有有效cookie了。最直接的想法,调用CookieManager的setCookie()方法,把这些字段清空或者设置为过期不就行了?在StackOverflow上搜了一下,找到一个帖子讨论类似的思想,试了一下发现还是不行。。。
原文链接:http://stackoverflow.com/questions/2834180/how-to-remove-cookies-using-cookiemanager-for-a-specific-domain/11621738#11621738
下面说一说遇到的一堆坑吧:
1. 同一个域名,http跟https两种情况下cookie带的参数是不一样的。举个例子,http://www.facebook.com跟https://www.facebook.com,通过CookieManager.getCookie()获取 的参数是完全不一样的。这个问题困扰了我一个多小时,因为我发现有些参数死活清不掉。。。
2. Cookies表里有一堆以“.”开头的域名,比如表里的那个“.facebook.com”,它的一些参数用完全域名删不掉。比如针对http://www.facebook.com调用CookieManager.setCookie()清除字段信息,你会发现表里多了一项"www.facebook.com"的记录,而原来的".facebook.com"的记录仍然存在而且字段信息没有被清除。
3. 使用以“.”开头的域名,比如".facebook.com",调用CookieManager.getCookie()时获取不到全的参数列表。
4. 不同的网站会在Cookies表里增加多项记录,以facebook为例,表里可能会存"www.facebook.com"、".www.facebook.com"、".facebook.com"这3种记录。
最后说结论吧,几经周折,总算找到一个能用的方法,亲测5.1 / 6.0平台可用。其实也很简单粗暴,就是把上面第4条提到的那几种记录统统撸一遍,宁可错杀一千,也不放过一个。。。
附上代码(注意domain参数是带上协议的全域名,比如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;
}
来源:https://blog.csdn.net/TurkeyCock/article/details/53091103


猜你喜欢
- 一.SQLite的介绍1.SQLite简介SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入 
- 周末这天手痒,正好没事干,想着写一个分页的例子出来给大家分享一下。这个案例分前端和后台两部分,前端使用面向对象的方式写的,里面用到了一些回调
- Android 文件读写操作方法总结在Android中的文件放在不同位置,它们的读取方式也有一些不同。本文对android中对资源文件的读取
- Android 自带的资源字符串资源:定义字符串资源在 <string.xml >;在JAVA 中 使用字符串资源,通过 get
- 项目结构这个是在网上找的资源,出处记不得了,记录一下。程序的总体结构,很简单的:核心代码代码如下:ArrComparator.java类im
- Spring3中加强了注解的使用,其中计划任务也得到了增强,现在创建一个计划任务只需要两步就完成了:创建一个Java类,添加一个无参无返回值
- 常用的类:@ConditionalOnProperty(name = "use.redis.session.store"
- 1. Mybatis的@param注解自定义对象也用@param注解注:使用@param注解,mapper.xml 不加parameterT
- idea如何设置系统环境变量背景最近在接入阿里云的短信服务,在使用阿里云短信服务的SDK过程中想看看SDK中HttpUtil 中public
- 1.什么是逆向工程mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的
- SlidingDrawer效果想必大家也见到过,它就是1.5模拟器上进入应用程序列表的效果。下面是截图一、简介 SlidingDr
- 一、概述当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing等等。一般情况下,我们知道View类有个View
- Escape: public static string Escape(string str) { StringBuilder sb = n
- 本文以实例形式简单讲述了引用类型转换的几种常见方式,如:子类转换成父类,父类转换成子类,以及不是子父级关系类之间的转换。现分述如下,供大家参
- 本文实例讲述了C#实现将字符串转换成日期格式的方法。分享给大家供大家参考。具体实现方法如下:string s = "2012011
- 通常我们在进行数据绑定的时候,常用的数据源有DataSet、DataTable、BindingList<T>、还有强类型数据源。
- 声明类定义类:class MyClass { // 字段、构造函数和 // 方法声明}
- 前言 图片加水印:Springboot 图片需要添加水印,怎么办? 1秒就实现那么word文档替换文字、插入图片,当然也是1秒钟了
- 1. 什么是XGBoostXGBoost是陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广
- 线程组线程组可以批量管理线程和线程组对象。一级关联例子如下,建立一级关联。public class MyThread43 implement