Подтвердить что ты не робот

Двухсторонняя синхронизация файлов cookie между HttpURLConnection (java.net.CookieManager) и WebView (android.webkit.CookieManager)

К сожалению, существует множество менеджеров файлов cookie для Android. Куки для HttpURLConnection поддерживаются java.net.CookieManager, а файлы cookie для WebView поддерживаются android.webkit.CookieManager. Эти хранилища файлов cookie являются отдельными и требуют ручной синхронизации.

Мое приложение использует как HttpURLConnections, так и показывает WebViews (это гибрид native-HTML). Естественно, я хочу, чтобы обойти все файлы cookie - так что у меня будет прозрачный сеанс.

Более конкретно:

  • Когда cookie устанавливается/изменен в HttpURLConnection, я хочу, чтобы WebViews также видел это изменение.
  • Когда cookie установлен/изменен в WebView, я хочу, чтобы следующие HttpURLConnections также увидели это изменение.

Проще говоря - я ищу двухстороннюю синхронизацию. Или еще лучше, чтобы они использовали один и тот же репозиторий файлов cookie. Вы можете предположить, что оба они активны в одно и то же время (например, на разных вкладках).

Вопросы:

  • Есть ли способ заставить оба использовать один и тот же репозиторий файлов cookie?

  • Если нет, рекомендуется ли использовать ручную синхронизацию? Когда нужно точно синхронизировать и как?

Связанный с этим вопрос: Этот question решает аналогичную проблему, но реализует только одностороннюю синхронизацию (HttpURLConnection → WebView).

Моя лучшая идея до сих пор: Я действительно хочу избежать ручной синхронизации, поэтому я попытался подумать, как заставить оба использовать один и тот же репозиторий. Может быть, я могу создать свой собственный обработчик ядра, который расширяет java.net.CookieManager. Я поставлю его в качестве основного обработчика файлов cookie, используя java.net.CookieHandler.setDefault(). Его реализация будет прокси-сервером экземпляра обработчика android.webkit.CookieManager (для каждой функции я просто получаю доступ к менеджеру webkit).

4b9b3361

Ответ 1

Я реализовал свою собственную идею. Это на самом деле довольно круто. Я создал свою собственную реализацию java.net.CookieManager, которая пересылает все запросы веб-страницам WebViews android.webkit.CookieManager. Это означает, что синхронизация не требуется, и HttpURLConnection использует то же хранилище файлов cookie, что и WebViews.

Класс WebkitCookieManagerProxy:

import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class WebkitCookieManagerProxy extends CookieManager 
{
    private android.webkit.CookieManager webkitCookieManager;

    public WebkitCookieManagerProxy()
    {
        this(null, null);
    }

    public WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy)
    {
        super(null, cookiePolicy);

        this.webkitCookieManager = android.webkit.CookieManager.getInstance();
    }

    @Override
    public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException 
    {
        // make sure our args are valid
        if ((uri == null) || (responseHeaders == null)) return;

        // save our url once
        String url = uri.toString();

        // go over the headers
        for (String headerKey : responseHeaders.keySet()) 
        {
            // ignore headers which aren't cookie related
            if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;

            // process each of the headers
            for (String headerValue : responseHeaders.get(headerKey))
            {
                this.webkitCookieManager.setCookie(url, headerValue);
            }
        }
    }

    @Override
    public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException 
    {
        // make sure our args are valid
        if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");

        // save our url once
        String url = uri.toString();

        // prepare our response
        Map<String, List<String>> res = new java.util.HashMap<String, List<String>>();

        // get the cookie
        String cookie = this.webkitCookieManager.getCookie(url);

        // return it
        if (cookie != null) res.put("Cookie", Arrays.asList(cookie));
        return res;
    }

    @Override
    public CookieStore getCookieStore() 
    {
        // we don't want anyone to work with this cookie store directly
        throw new UnsupportedOperationException();
    }
}

И используйте его, выполнив это при инициализации вашего приложения:

android.webkit.CookieSyncManager.createInstance(appContext);
// unrelated, just make sure cookies are generally allowed
android.webkit.CookieManager.getInstance().setAcceptCookie(true);

// magic starts here
WebkitCookieManagerProxy coreCookieManager = new WebkitCookieManagerProxy(null, java.net.CookiePolicy.ACCEPT_ALL);
java.net.CookieHandler.setDefault(coreCookieManager);

Тестирование

Мое начальное тестирование показывает, что это хорошо работает. Я вижу файлы cookie, общие между WebViews и HttpURLConnection. Надеюсь, у меня не возникнут проблемы. Если вы попробуете это и обнаружите какие-либо проблемы, прокомментируйте.