web-dev-qa-db-ja.com

HttpURLConnection(Java.net.CookieManager)とWebView(Android.webkit.CookieManager)間のCookieの双方向同期

残念ながら、Android向けのCookieマネージャーは多数あります。 HttpURLConnectionのCookieは_Java.net.CookieManager_によって維持され、WebViewのCookieは_Android.webkit.CookieManager_によって維持されます。これらのCookieリポジトリは独立しており、手動で同期する必要があります。

私のアプリはHttpURLConnectionsWebViewsの両方を使用しています(これはネイティブHTMLハイブリッドです)。当然、両方にすべてのCookieを共有させたいので、全体で透過的なセッションを行います。

具体的に:

  1. CookieがHttpURLConnectionで設定/変更されると、WebViewsにもこの変更が表示されるようにします。
  2. CookieがWebViewで設定/変更されると、次のHttpURLConnectionsにもこの変更が表示されるようにします。

簡単に言えば、私は双方向同期を探しています。または、両方が同じcookieリポジトリを使用するようにすることもできます。両方が同時にアクティブであると想定できます(異なるタブ上など)。

質問:

  1. 両方が同じcookieリポジトリを使用する方法はありますか?

  2. そうでない場合、手動同期を行うために推奨される方法は何ですか?正確に同期するタイミングと方法は?

関連質問:これは 質問 で同様の問題に対処していますが、一方向の同期(HttpURLConnection- > WebView)。

これまでの私の最高のアイデア:手動での同期は避けたいので、両方に同じリポジトリを使用させる方法を考えてみました。多分私は_Java.net.CookieManager_を拡張する独自のコアハンドラーを作成できます。 Java.net.CookieHandler.setDefault()を使用して、コアCookieハンドラーとして設定します。その実装は、_Android.webkit.CookieManager_ハンドラーインスタンスのプロキシになります(すべての関数について、Webkitマネージャーにアクセスします)。

34
talkol

私は自分のアイデアを実装しました。それは実際にはかなりクールです。すべてのリクエストをWebViewsのWebkit Java.net.CookieManagerに転送するAndroid.webkit.CookieManagerの独自の実装を作成しました。つまり、同期は不要で、HttpURLConnectionはsameCookieストレージをWebViewとして使用します。

クラス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);

テスト

私の最初のテストは、これがうまく機能していることを示しています。 WebViewsとHttpURLConnectionの間で共有されるCookieを確認します。問題が発生しないことを願っています。これを試して問題を見つけたら、コメントしてください。

65
talkol