从Web视图中删除特定域名的所有Cookie

8

我想要移除一个域名下的所有cookies,有没有方法可以做到这一点?

我所知道的唯一方法是使用removeAllCookies。

谢谢。


2
你正在使用 WebView 吗? - Shree Krishna
是的,我正在使用webView。 - nahum
5个回答

10
根据文档,我们没有一种方法可以删除单个cookie。 但是我们可以使用一个有趣的方法,通过setCookie()来清除一个网站的cookie。如下所示,

public abstract void setCookie (String url, String value)

为给定的URL设置一个cookie。任何具有相同主机、路径和名称的现有cookie都将被新cookie替换。如果cookie已过期,则设置的cookie将被忽略。

所以,解决方案是,如this答案中所述,我们需要手动清理每个主机键的每个cookie。例如:- facebook
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "locale=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "datr=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "s=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "csm=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "fr=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "lu=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "c_user=;Max-Age=0");
android.webkit.CookieManager.getInstance().setCookie(".facebook.com", "xs=;Max-Age=0");

你需要设置Max-Age=0来真正删除cookie,否则你只是清除了它的值。 - undefined

5
首先,我建议您查看管理WebView使用的Cookie的CookieManager类。虽然有一个清除cookie的方法removeAllCookie(),但该方法在API级别21中已被弃用,因此您可以使用removeAllCookeis(callback)方法。如果您不需要知道操作何时完成或是否删除了任何cookie,则可以将null作为回调传递,并且在这种情况下,从没有Looper的线程调用该方法是安全的。
要在Lollipop或更高版本中清除cookie,请使用:
CookieManager.getInstance().removeAllCookies(null);
CookieManager.getInstance().flush();

并在休息时,
CookieSyncManager cookieSyncMngr=CookieSyncManager.createInstance(context);
cookieSyncMngr.startSync();
CookieManager cookieManager=CookieManager.getInstance();
cookieManager.removeAllCookie();
cookieManager.removeSessionCookie();
cookieSyncMngr.stopSync();
cookieSyncMngr.sync();

4
< p > Let'sRefactorAnT的答案对我找到最终解决方案很有帮助。因此,基本上我们需要逐个清理每个cookie。但对我而言,仅设置"value=""value=; Domain=my.domain.com"并不起作用。我想这是页面的问题,我对该页面没有控制权(它在读取cookies时打印崩溃堆栈)。因此,对我来说,最终解决方案是删除cookies,而不是清空它们。当然,我们没有任何API来删除特定的cookie,但我们可以使用'Set-Cookie' HTTP响应头格式的Max-Age参数。我的最终代码如下(Kotlin,在生产代码中我当然会将字符串放入常量中 ;)):

val domain = myPageUri.host
CookieManager.getInstance().apply {
   getCookie(domain)
      .split("; ")
      .filter { it.isNotNullOrBlank() }
      .forEach {
         val newCookieValue = it.substringBefore("=") + "=; Max-Age=-1"
         setCookie(domain, newCookieValue)
      }
}

substringBefore(character: String) 是我们在 String 上的扩展函数,它返回从开头到第一次出现 character 的子字符串。


在我的情况下,除非我还指定正确的 ; Path=<path> 值,否则它不起作用,而这是您无法使用 CookieManager 获得的。您可以使用 WebViewClient 拦截请求,但在我的情况下这没有意义,所以我可能会删除所有可能路径的 cookie:url.toHttpUrl().encodedPathSegments.scan("/") { prefix, segment -> "$prefix$segment/" } - arekolek
我添加了我的代码 https://dev59.com/uZTfa4cB1Zd3GeqPLRCU#75928902 - arekolek

2
@Let'sRefactor的回答方向正确,但实际上并不起作用,因为正如文档所述,我们必须使用“Set-Cookie”HTTP响应头格式:

value - String:cookie字符串,使用“Set-Cookie”HTTP响应头格式

我编写了以下代码来从任何特定域中删除cookie:

public static void deleteCookies(String url) {
    CookieManager cookieManager = CookieManager.getInstance();
    try {
        String domainName = Utils.getDomainName(url);
        String cookiesString = cookieManager.getCookie(url);
        String[] cookies = cookiesString.split("; ");
        for (String cookie : cookies) {
            if (Strings.isNullOrEmpty(cookie))
                continue;
            int equalCharIndex = cookie.indexOf('=');
            if (equalCharIndex == -1)
                continue;
            String cookieString = cookie.substring(0, equalCharIndex) + '='
                    + "; Domain=" + domainName;
            cookieManager.setCookie(url, cookieString);
        }
    } catch (URISyntaxException e) {
        Log.e("TAG", "Message", e);
    }
}

以下代码可获取不带子域名的域名:
public static String getDomainName(@NotNull String url) throws URISyntaxException {
    URI uri = new URI(url);
    String domain = uri.getHost();
    domain = domain.startsWith("www.") ? domain.substring(4) : domain;
    try {
        //Try to get the domain without subdomain. Ex: mobile.twitter.com would returns twitter.com
        //Note: InternetDomainName is from Guava library
        return InternetDomainName.from(domain).topPrivateDomain().toString();
    } catch (IllegalStateException e) {
        Log.e("getDomainName()", "Illegal url");
    }
    return domain;
}

0

其他答案对我没有用,因为它们没有为 cookie 设置正确的路径。

对我有效的方法似乎是:

import android.webkit.CookieManager
import okhttp3.HttpUrl.Companion.toHttpUrl

fun CookieManager.removeCookies(url: String) {
    val cookies = getCookie(url) ?: return

    // Android SDK will not tell us what path was used to set the cookie, so we remove the cookie for all possible paths
    val paths = url.toHttpUrl().encodedPathSegments.scan("/") { prefix, segment -> "$prefix$segment/" }

    val keys = cookies.split(";")
            .map { it.substringBefore("=", missingDelimiterValue = "").trim() }
            .filter { it.isNotEmpty() }
            .distinct()

    keys.forEach { key ->
        paths.forEach {
            // Max-Age effectively removes the cookie
            setCookie(url, "$key=; Path=$it; Max-Age=-1")
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接