Android清除单个域名的cookie

今天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;
    }

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio中,可以通过AlertDialog来创建一个带有单个复选框的对话框。首先,我们需要创建一个AlertDialog.Builder对象,并设置它的标题和消息。然后,使用setMultiChoiceItems()方法来设置复选框的选项和默认选中的状态。接下来,我们可以通过调用setPositiveButton()和setNegativeButton()方法来设置对话框的确认按钮和取消按钮。最后,调用create()方法来创建AlertDialog对象并显示出来。 以下是一个示例代码: AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("请选择"); builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { // 处理复选框的点击事件 } }); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 处理确认按钮的点击事件 } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 处理取消按钮的点击事件 } }); AlertDialog dialog = builder.create(); dialog.show(); 在onClick()方法中,我们可以处理复选框的点击事件,并根据需要执行相应的操作。在确认按钮和取消按钮的点击事件中,我们可以处理用户的确认或取消操作。最后,调用create()方法创建AlertDialog对象,并调用show()方法显示出对话框。这样,就实现了一个带有单个复选框的AlertDialog。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值