Android WebViewCookieの問題


89

認証された通信に使用するセッションCookieをAndroidアプリに送信するサーバーがあります。同じサーバーを指すURLを使用してWebViewをロードしようとしていますが、認証のためにセッションCookieを渡そうとしています。断続的に動作するのを観察していますが、理由はわかりません。同じセッションCookieを使用してサーバー上で他の呼び出しを行いますが、これらは認証に失敗することはありません。この問題は、WebViewにURLを読み込もうとしたときにのみ発生し、毎回発生するわけではありません。非常にイライラします。

以下は、これを行うために使用しているコードです。どんな助けでも大歓迎です。

String myUrl = ""http://mydomain.com/"; 
CookieSyncManager.createInstance(this); 
CookieManager cookieManager = CookieManager.getInstance(); 
Cookie sessionCookie =  getCookie(); 
if(sessionCookie != null){ 
    String cookieString = sessionCookie.getName() +"="+sessionCookie.getValue()+"; domain="+sessionCookie.getDomain(); 
    cookieManager.setCookie(myUrl, cookieString); 
    CookieSyncManager.getInstance().sync(); 
} 

WebView webView = (WebView) findViewById(R.id.webview); 
webView.getSettings().setBuiltInZoomControls(true); 
webView.getSettings().setJavaScriptEnabled(true); 
webView.setWebViewClient(new MyWebViewClient()); 
webView.loadUrl(myUrl);

この質問を参照してくださいstackoverflow.com/questions/2566485/…–
neeraj t 2012

回答:


55

justingrammensに感謝します!それは私にとってはうまくいきました、私はDefaultHttpClientリクエストとWebViewアクティビティ内でCookieを共有することができました:

//------- Native request activity
private DefaultHttpClient httpClient;
public static Cookie cookie = null;

//After Login
List<Cookie> cookies = httpClient.getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
    cookie = cookies.get(i);
}

//------- Web Browser activity
Cookie sessionCookie = myapp.cookie;
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
    cookieManager.removeSessionCookie();
    String cookieString = sessionCookie.getName() + "=" + sessionCookie.getValue() + "; domain=" + sessionCookie.getDomain();
    cookieManager.setCookie(myapp.domain, cookieString);
    CookieSyncManager.getInstance().sync();
}   

これは私にとってはうまくいきました。このようにCookieのURLを作成しました。Stringurl=(cookie.isSecure()? "https": "http")+ "://" + cookie.getDomain()+ cookie.getPath();
Heath Borders

投稿に感謝します...アプリのTwitterログアウトを実装するのに役立ちました...;)
rahul 2011

myapp.cookieの代わりに何を書くべきか教えてもらえますか
suraj jain 2012年

キーワードは次のとおりです。StringcookieString= sessionCookie.getName()+ "=" + sessionCookie.getValue()+ "; domain =" + sessionCookie.getDomain(); cookieManager.setCookie(myapp.domain、cookieString);
Zennichimaro 2012年

1
CookieSyncManagerは現在非推奨です:(
Misha Akopov 2016

18

私の日曜日を台無しにしてくれたAndroidに感謝します。。。これが私のアプリを修正したものです(あなたがあなたのウェブビューを初期化した後)

if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

上記の答えはおそらくうまくいくと言うべきですが、私の状況では、Androidがv5 +になった瞬間、私のandroid webview javascript'apps 'が停止しました。


1
ああ !あなたは私の日を救った!
ル・ミン

14

解決策:WebviewCookieSyncManager

CookieSyncManager cookieSyncManager = CookieSyncManager.createInstance(mWebView.getContext());
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
cookieManager.removeSessionCookie();
cookieManager.setCookie("http://xx.example.com","mid="+MySession.GetSession().sessionId+" ; Domain=.example.com");
cookieSyncManager.sync();

String cookie = cookieManager.getCookie("http://xx.example.com");

Log.d(LOGTAG, "cookie ------>"+cookie);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.setWebViewClient(new TuWebViewClient());
mWebView.loadUrl("http://xx.example.com");

あなたは何から得cookieますか?、私は次のようになります:PHPSESSID=ljfakdjfklasdfaj!、それで十分ですか?
フランシスココラレスモラレス2014年

6
ここでのMySessionとは何ですか?
user3 2015年


3

そのセッションCookieを設定として保存し、Cookieマネージャーに強制的に再入力します。アクティビティが再開されない場合のセッションCookieのようです


私のアプリは、認証に失敗することのないサーバー呼び出しで他の多くの非WebViewを作成することを追加する必要があります。WebViewにURLを読み込もうとした場合にのみ、この問題に気付きます。"Cookie sessionCookie = getCookie();" サーバーとのすべてのメッセージに使用するセッションCookieをアプリのDBから取得しています。
nannerpus 2009年

HttpClientを使用している場合は、独自のCookieストアがあるため、クライアントの単一インスタンスを保持している場合、Cookieは存続しますが、Webビューで使用されているものとは関係がない可能性があります
Bostone

私があなたを正しく理解しているなら、あなたはCookieManagerがCookieManager.getInstance()によって返されると言っています。WebViewsが使用しないHttpClientのインスタンスによって使用されるCookieに影響します。これが本当なら、CookieをWebViewに明示的に渡す方法を知っていますか?また、CookieManagerのドキュメントを見ると、おそらく「cookieManager.setAcceptCookie(true)」を呼び出さないと問題が発生しますか?助けてくれてありがとう、本当に感謝しています。
nannerpus 2009年

3

私は3時間の半分以上を、非常によく似た問題に取り組んできました。私の場合、を使用してWebサービスに対して多くの呼び出しを行いDefaulHttpClient、セッションとそれに対応する他のすべてのCookieをに設定したいと思いましたWebView

あなたのgetCookie()メソッドが何をするのかわからないので、これがあなたの問題を解決するかどうかはわかりませんが、私の場合は実際に呼び出す必要がありました。

cookieManager.removeSessionCookie();

最初にセッションCookieを削除してから、再度追加します。JSESSIONID最初にCookieを削除せずにCookieを設定しようとすると、設定したい値が保存されていないことがわかりました。これが特定の問題に役立つかどうかはわかりませんが、私が見つけたものを共有したいと思いました。


なぜCookieManager.getInstance().removeAllCookie ();ですか?
フランシスココラレスモラレス

2

しばらく調査した後、私はこの解決策にたどり着くためのいくつかのピースを集めました。そのCookieSyncManagerが非推奨になったら、これがKotlinのWebビューに特定のCookieを設定するための最良の方法である可能性があり、他に何も必要ないはずです。

private fun setCookie(){
    val webView = WebView(this) // this = context
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()

    val domain = "https://www.yourdomain.com/"

    webView.webViewClient = WebViewClient()
    webView.settings.javaScriptEnabled = true

    cookieManager.setCookie(domain,"$cookieKey=$cookieValue")
    cookieManager.setAcceptThirdPartyCookies(webView, true)

    webView.loadUrl(domain)
}

1

私はここで他の人とは異なるアプローチをとっています。これは、CookieSyncManagerを処理しなくても機能することが保証されているアプローチです(「sync()でさえ非同期で発生することに注意してください」などのセマンティクスに翻弄されます)。

基本的に、正しいドメインを参照し、ページコンテキストからjavascriptを実行して、そのドメインのCookieを設定します(ページ自体と同じ方法)。この方法の2つの欠点は、追加のhttpリクエストを行う必要があるため、余分なラウンドトリップ時間が発生する可能性があることです。また、サイトに空白ページに相当するものがない場合は、適切な場所に移動する前に、最初にロードしたURLがフラッシュされる可能性があります。

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.http.cookie.Cookie;
import android.annotation.SuppressLint;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class WebViewFragment {
    private static final String BLANK_PAGE = "/blank.html"

    private CookieSyncManager mSyncManager;
    private CookieManager mCookieManager;

    private String mTargetUrl;
    private boolean mInitializedCookies;
    private List<Cookie> mAllCookies;

    public WebViewFragment(Context ctx) {
        // We are still required to create an instance of Cookie/SyncManager.
        mSyncManager = CookieSyncManager.createInstance(ctx);
        mCookieManager = CookieManager.getInstance();
    }

    @SuppressLint("SetJavaScriptEnabled") public void loadWebView(
                String url, List<Cookie> cookies, String domain) {
        final WebView webView = ...

        webView.setWebViewClient(new CookeWebViewClient());
        webView.getSettings().setJavaScriptEnabled(true);

        mInitializedCookies = false;
        mTargetUrl = url;
        mAllCookies = cookies;
        // This is where the hack starts.
        // Instead of loading the url, we load a blank page.
        webView.loadUrl("http://" + domain + BLANK_PAGE);
    }

    public static String buildCookieString(final Cookie cookie) {
        // You may want to add the secure flag for https:
        // + "; secure"
        // In case you wish to convert session cookies to have an expiration:
        // + "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
        // Note that you cannot set the HttpOnly flag as we are using
        // javascript to set the cookies.
        return cookie.getName() + "=" + cookie.getValue()
                    + "; path=" + cookie.getPath()
                    + "; domain=" + cookie.getDomain()
    };

    public synchronized String generateCookieJavascript() {
        StringBuilder javascriptCode = new StringBuilder();
        javascriptCode.append("javascript:(function(){");
        for (final Cookie cookie : mAllCookies) {
            String cookieString = buildCookieString(cookie);
            javascriptCode.append("document.cookie=\"");
            javascriptCode.append(
                     StringEscapeUtils.escapeJavascriptString(cookieString));
            javascriptCode.append("\";");
        }
        // We use javascript to load the next url because we do not
        // receive an onPageFinished event when this code finishes.
        javascriptCode.append("document.location=\"");
        javascriptCode.append(
                StringEscapeUtils.escapeJavascriptString(mTargetUrl));
        javascriptCode.append("\";})();");
        return javascriptCode.toString();
    }

    private class CookieWebViewClient extends WebViewClient {
        @Override public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!mInitializedCookies) {
                mInitializedCookies = true;
                // Run our javascript code now that the temp page is loaded.
                view.loadUrl(generateCookieJavascript());
                return;
            }
        }
    }
}

Cookieの送信元のドメインを信頼している場合は、Apache Commonsなしで逃げることができるかもしれませんが、注意しないとXSSリスクが発生する可能性があることを理解する必要があります。


1

これは実用的なコードです。

    private void setCookie(DefaultHttpClient httpClient, String url) {
    List<Cookie> cookies = httpClient.getCookieStore().getCookies();
    if (cookies != null) {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);

        for (int i = 0; i < cookies.size(); i++) {
            Cookie cookie = cookies.get(i);
            String cookieString = cookie.getName() + "=" + cookie.getValue();
            cookieManager.setCookie(url, cookieString);
        }
        CookieSyncManager.getInstance().sync();
    }
}

ここで、httpclientは、HttpGet / HttpPostリクエストで使用したDefaultHttpClientオブジェクトです。また、確認する必要があるのは、Cookieの名前と値です。指定する必要があります。

String cookieString = cookie.getName() + "=" + cookie.getValue();

setCookieは、指定されたURLのCookieを設定します。


注:CookieManager.setCookieを使用してセッションCookieを保存することはできません
John Doe

聞き取れませんでした...説明できますか?
ドロイドキッド

1

onCreateのこの1行で、すべてのCookieの問題を魔法のように解決しました。

CookieHandler.setDefault(new CookieManager());

編集:それは今日動作を停止しました。:(なんてくだらない、アンドロイド。


だから、更新はありますか?なぜそれが機能しなくなったのですか?、あなたはそれを解決しましたか?
フランシスココラレスモラレス

1

これにも遭遇しました。これが私がしたことです。

LoginActivityのAsyncTask内には、次のものがあります。

CookieStoreHelper.cookieStore = new BasicCookieStore();
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, CookieStoreHelper.cookieStore);

HttpResponse postResponse = client.execute(httpPost,localContext);
CookieStoreHelper.sessionCookie = CookieStoreHelper.cookieStore.getCookies();

// WHERE CookieStoreHelper.sessionCookieは、リストCookieとして定義された変数sessionCookieを含む別のクラスです。およびcookieStoreはBasicCookieStorecookieStoreとして定義されます。

次に、WebViewが配置されているフラグメントに次のものがあります。

//DECLARE LIST OF COOKIE
List<Cookie> sessionCookie;

私のメソッド内またはWebViewClient()を設定する直前

WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);

sessionCookie = CookieStoreHelper.cookieStore.getCookies();
CookieSyncManager.createInstance(webView.getContext());
CookieSyncManager.getInstance().startSync();
CookieManager cookieManager = CookieManager.getInstance();
CookieManager.getInstance().setAcceptCookie(true);
if (sessionCookie != null) {
   for(Cookie c:  sessionCookie){
      cookieManager.setCookie(CookieStoreHelper.DOMAIN, c.getName() + "=" + c.getValue());
   }
   CookieSyncManager.getInstance().sync();

 }

 webView.setWebViewClient(new WebViewClient() {
    //AND SO ON, YOUR CODE
 }

クイックヒント:Firefoxにfirebugをインストールするか、Chromeで開発者コンソールを使用して最初にWebページをテストし、Cookieをキャプチャしてドメインをチェックし、どこかに保存して、正しいドメインを正しく設定していることを確認します。

編集:CookieStoreHelper.cookiesをCookieStoreHelper.sessionCookieに編集しました


1

私の作業コード

public View onCreateView(...){
    mWebView = (WebView) view.findViewById(R.id.webview);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);

        ...
        ...
        ...

    CookieSyncManager.createInstance(mWebView.getContext());
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setAcceptCookie(true);
    //cookieManager.removeSessionCookie(); // remove
    cookieManager.removeAllCookie(); //remove
    // Recommended "hack" with a delay between the removal and the installation of "Cookies"
    SystemClock.sleep(1000);

    cookieManager.setCookie("https://my.app.site.com/", "cookiename=" + value + "; path=/registration" + "; secure"); // ;
    CookieSyncManager.getInstance().sync();

    mWebView.loadUrl(sp.getString("url", "") + end_url);

    return view;
}

クエリをデバッグするには、「cookieManager.setCookie(....);」データベースwebviewCookiesChromium.db(「/ data / data / my.app.webview / database」に保存されている)の内容を確認することをお勧めします。そこに正しい設定が表示されます。

「cookieManager.removeSessionCookie();」を無効にする および/または「cookieManager.removeAllCookie();」

//cookieManager.removeSessionCookie();
// and/or
//cookieManager.removeAllCookie();"

設定値とブラウザで設定した値を比較してください。「フラグ」ブラウザがインストールされなくなる前に、Cookieのインストール要求を調整して、ユーザーが決定した内容に適合させます。クエリが「フラグ」になる可能性があることがわかりました。

// You may want to add the secure flag for https:
+ "; secure"
// In case you wish to convert session cookies to have an expiration:
+ "; expires=Thu, 01-Jan-2037 00:00:10 GMT"
// These flags I found in the database:
+ "; path=/registration"
+ "; domain=my.app.site.com"

WebビューでCookieを保存するために上記のコードを使用していますが、パスについて教えてください。ここのパスは何ですか?
メフルタンク2018

@MehulTank pathパラメーターは、ドキュメントの場所を指定します。パスが現在または親ドキュメントの場所と一致する場合にのみ、Cookieがサーバーに送信されます。
Roland van

1

私の経験から見つけて頭痛の種となったいくつかのコメント(少なくともAPI> = 21の場合):

  1. httphttpsURLが異なります。のCookieの設定は、のCookieの設定とhttp://www.example.comは異なります。https://www.example.com
  2. URLの末尾にスラッシュを付けることも違いを生む可能性があります。私の場合はhttps://www.example.com/機能しますが、https://www.example.com機能しません。
  3. CookieManager.getInstance().setCookie非同期操作を実行しています。そのため、設定した直後にURLを読み込んだ場合、Cookieが既に書き込まれているとは限りません。予期しない不安定な動作を防ぐには、CookieManager#setCookie(String url、String value、ValueCallback callback)(link)を使用し、コールバックが呼び出された後にURLの読み込みを開始します。

私の2セントで何人かの人々の時間を節約できれば、私と同じ問題に直面する必要がなくなります。


どのように異なるのためにクッキーを設定されてexample.comがのCookieの設定と異なるexample.comを
softmarshmallow

0

私は同じ問題に直面しました、そしてそれはすべてのアンドロイドバージョンでこの問題を解決します

private void setCookie() {
    try {
        CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.setAcceptCookie(true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cookieManager.setCookie(Constant.BASE_URL, getCookie(), value -> {
                String cookie = cookieManager.getCookie(Constant.BASE_URL);
                CookieManager.getInstance().flush();
                CustomLog.d("cookie", "cookie ------>" + cookie);
                setupWebView();
            });
        } else {
            cookieManager.setCookie(webUrl, getCookie());
            new Handler().postDelayed(this::setupWebView, 700);
            CookieSyncManager.getInstance().sync();
        }

    } catch (Exception e) {
        CustomLog.e(e);
    }
}

0

通常のURLの代わりにサブドメインを使用する方がよい場合があることに注意してください。したがって、の.example.com代わりに設定しますhttps://example.com/

Jody Jacobus Geersと他の人たちに感謝します:

if (savedInstanceState == null) {
    val cookieManager = CookieManager.getInstance()
    cookieManager.acceptCookie()
    val domain = ".example.com"
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        cookieManager.setCookie(domain, "token=$token") {
            view.webView.loadUrl(url)
        }
        cookieManager.setAcceptThirdPartyCookies(view.webView, true)
    } else {
        cookieManager.setCookie(domain, "token=$token")
        view.webView.loadUrl(url)
    }
} else {
    // Check whether we're recreating a previously destroyed instance.
    view.webView.restoreState(savedInstanceState)
}

-4

生のURLを使用しないでください

の代わりに:

cookieManager.setCookie(myUrl, cookieString); 

次のように使用します。

cookieManager.setCookie("your url host", cookieString); 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.