Android WebView Çerez Sorunu


89

Android uygulamama kimliği doğrulanmış iletişim için kullanılmak üzere bir oturum çerezi gönderen bir sunucum var. Aynı sunucuya işaret eden bir URL'ye sahip bir Web Görünümü yüklemeye çalışıyorum ve kimlik doğrulama için oturum tanımlama bilgisini geçirmeye çalışıyorum. Aralıklı çalıştığını gözlemliyorum ama neden olduğuna dair hiçbir fikrim yok. Sunucumda başka çağrılar yapmak için aynı oturum tanımlama bilgisini kullanıyorum ve bunlar kimlik doğrulamasında asla başarısız olmaz. Bu sorunu yalnızca bir Web Görünümünde bir URL yüklemeye çalışırken gözlemliyorum ve bu her seferinde olmuyor. Çok sinir bozucu.

Bunu yapmak için kullandığım kod aşağıdadır. Herhangi bir yardım çok takdir edilecektir.

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);

Yanıtlar:


55

Teşekkürler justingrammens ! Bu benim için çalıştı, çerezi DefaultHttpClient isteklerim ve WebView etkinliğim içinde paylaşmayı başardım:

//------- 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();
}   

Bu benim için harika çalıştı. Çerez url'mi şu şekilde oluşturdum: String url = (cookie.isSecure ()? "Https": "http") + ": //" + cookie.getDomain () + cookie.getPath ();
Heath Borders

gönderi için teşekkürler ... uygulamam için twitter çıkışını uygulamama yardımcı oldu ...;)
rahul

myapp.cookie
suraj jain

anahtar kelime: String cookieString = sessionCookie.getName () + "=" + sessionCookie.getValue () + "; domain =" + sessionCookie.getDomain (); cookieManager.setCookie (myapp.domain, cookieString);
Zennichimaro

1
CookieSyncManager şu anda kullanımdan kaldırıldı :(
Misha Akopov

18

Pazar günümü mahvettiğin için teşekkürler Android. . . Uygulamalarımı düzelten şey burada (web görünümünüzü başlattıktan sonra)

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

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Yukarıdaki cevapların muhtemelen işe yarayacağını söylemeliyim ama benim durumumda Android v5'e gittiğinde + android webview javascript 'uygulamalarım' öldü.


1
Oh! Günümü kurtardın!
Le Minh

14

Çözüm: Webview CookieSyncManager

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");

ne alıyorsun?, cookiesadece şunu alıyorum: PHPSESSID=ljfakdjfklasdfaj!, bu yeterli mi?
Francisco Corrales Morales

6
MySession burada nedir?
Kullanıcı3


3

Bu oturum çerezini bir tercih olarak kaydeder ve çerez yöneticisini onunla zorla yeniden doldururum. Oturum çerezinin Aktivite yeniden başlatılmasından sağ çıkmadığı anlaşılıyor


Uygulamamın, sunucu çağrılarımda hiçbir zaman kimlik doğrulamasında başarısız olmayan birçok WebView olmayan arama yaptığını eklemeliyim. Yalnızca bir Web Görünümünde bir URL yüklemeye çalıştığımda bu sorunu fark ediyorum. "Cookie sessionCookie = getCookie ();" uygulamanın DB'sinden sunucumla tüm mesajlar için kullandığım oturum tanımlama bilgisini alıyor.
nannerpus

HttpClient kullanıyorsanız, bunun için kendi Çerez deposu vardır, bu nedenle müşterinin tek bir örneğini tutarsanız, çereziniz hayatta kalır, ancak web görünümünüz tarafından kullanılanla hiçbir ilgisi olmayabilir
Bostone

Sizi doğru anladıysam, CookieManager'ın CookieManager.getInstance () tarafından döndürüldüğünü söylüyorsunuz; Web Görünümlerinin kullanmadığı HttpClient örnekleri tarafından kullanılan tanımlama bilgilerini etkileyecektir. Bu doğruysa, tanımlama bilgilerini Web Görünümlerine açıkça nasıl aktarabileceğimi biliyor musunuz? Ayrıca, CookieManager belgelerine bakmak, belki de "cookieManager.setAcceptCookie (true)" olarak adlandırmamak bana sorunlara neden oluyor? Yardımın için teşekkürler, gerçekten minnettarım.
nannerpus

3

3 saatin büyük kısmını çok benzer bir sorun üzerinde çalışarak geçirdim. Benim durumumda, a kullanarak bir web hizmetine yaptığım bir dizi görüşme oldu DefaulHttpClientve ardından oturumu ve diğer tüm ilgili çerezleri benim içinde ayarlamak istedim WebView.

getCookie()Yönteminizin ne işe yaradığını bilmediğim için bunun sorununuzu çözüp çözmeyeceğini bilmiyorum , ama benim durumumda gerçekten aramak zorunda kaldım.

cookieManager.removeSessionCookie();

Önce oturum tanımlama bilgisini kaldırın ve ardından yeniden ekleyin. JSESSIONIDÇerezi kaldırmadan ayarlamaya çalıştığımda, ayarlamak istediğim değerin kaydedilmediğini fark ettim. Bunun belirli bir soruna yardımcı olup olmayacağından emin değilim, ancak bulduklarımı paylaşacağımı düşündüm.


neden olmasın CookieManager.getInstance().removeAllCookie ();?
Francisco Corrales Morales

2

Bir süre araştırdıktan sonra, bu çözüme ulaşmamı sağlayan bazı parçaları topladım. Bu CookieSyncManager kullanımdan kaldırıldığında, bugünlerde Kotlin'de bir web görünümü için belirli bir çerez ayarlamanın en iyi yolu bu olabilir, başka hiçbir şeye ihtiyacınız olmamalıdır.

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

Buradaki diğer insanlardan farklı bir yaklaşımım var ve bu, CookieSyncManager ile uğraşmadan çalışmayı garantileyen bir yaklaşımdır (burada "sync () bile eşzamansız olarak gerçekleşir" gibi anlambilimin insafına kalırsınız).

Esasen, doğru etki alanına göz atarız, ardından o etki alanı için çerezleri ayarlamak üzere sayfa bağlamından javascript çalıştırırız (sayfanın kendisinin yapacağı gibi). Yöntemin iki dezavantajı, yapmanız gereken fazladan http talebi nedeniyle fazladan bir gidiş-dönüş süresi getirebilmesidir; ve sitenizde boş bir sayfa eşdeğeri yoksa, sizi doğru yere götürmeden önce yüklediğiniz URL'yi yanıp sönebilir.

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

Tanımlama bilgilerinin geldiği etki alanına güveniyorsanız, apache commons olmadan kurtulabilirsiniz, ancak dikkatli olmazsanız bunun bir XSS riski oluşturabileceğini anlamalısınız.


1

Bu çalışan bir kod parçasıdır.

    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();
    }
}

Burada httpclient, HttpGet / HttpPost isteğinde kullandığınız DefaultHttpClient nesnesidir. Ayrıca emin olunması gereken bir şey de çerez adı ve değeridir.

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

setCookie, verilen URL için çerezi ayarlayacaktır.


Bir not olarak: CookieManager.setCookie
John Doe

anlamadım ... açıklayabilir misin?
droid kid

1

OnCreate'deki bu tek satırla tüm çerez sorunlarımı sihirli bir şekilde çözdüm:

CookieHandler.setDefault(new CookieManager());

düzenleme: bugün çalışmayı durdurdu. :( ne bok, android.


yani, herhangi bir güncelleme var mı? neden çalışmayı bıraktı? çözdün mü?
Francisco Corrales Morales

1

Bununla da karşılaştı. İşte yaptığım şey.

LoginActivity'de, AsyncTask'ımın içinde aşağıdakilere sahibim:

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();

// CookieStoreHelper.sessionCookie, List çerezleri olarak tanımlanan sessionCookie değişkenini içeren başka bir sınıftır; ve cookieStore, BasicCookieStore cookieStore olarak tanımlanır;

Ardından, WebView'umun bulunduğu Fragment'ımda aşağıdakilere sahibim:

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

yöntemimin içinde veya WebViewClient () 'i ayarlamadan hemen önce

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
 }

Hızlı İpucu: Firebug'ı firefox'a yükleyin veya chrome üzerinde geliştirici konsolunu kullanın ve önce web sayfanızı test edin, Cookie'yi yakalayın ve bir yerde saklayabilmek için etki alanını kontrol edin ve doğru etki alanını doğru şekilde ayarladığınızdan emin olun.

Düzenleme: CookieStoreHelper.cookies'i CookieStoreHelper.sessionCookie olarak düzenledi


1

Çalışma kodum

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

Sorguda hata ayıklamak için "cookieManager.setCookie (....);" WebviewCookiesChromium.db veritabanının içeriğine bakmanızı tavsiye ederim ("/data/data/my.app.webview/database" de saklanır) Burada doğru ayarları görebilirsiniz.

"CookieManager.removeSessionCookie ();" nin devre dışı bırakılması ve / veya "cookieManager.removeAllCookie ();"

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

Ayarlanan değeri, tarayıcı tarafından belirlenenlerle karşılaştırın. "İşaretler" tarayıcı yüklenene kadar tanımlama bilgilerinin kurulum talebini, sizin karar verdiğiniz şeye uyacak şekilde ayarlayın. Bir sorgunun "işaretler" olabileceğini buldum:

// 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 görünümünde mağaza çerezi için yukarıdaki kodu kullandım, ancak lütfen bana yol hakkında bilgi verin. buradaki yol nedir?
Mehul Tankı

@MehulTank Yol parametresi bir belge konumunu belirtir. Tanımlama bilgisi sunucuya yalnızca yolun geçerli veya ana belge konumuyla eşleşmesi durumunda gönderilir.
Roland van der Linden

1

Deneyimlerimden öğrendiğim ve başımı ağrıtan birkaç yorum (en azından API'ler> = 21 için):

  1. httpve httpsurl'ler farklıdır. İçin bir çerez ayarlamak, bir çerez ayarlamaktan http://www.example.comfarklıdırhttps://www.example.com
  2. URL'nin sonundaki eğik çizgi de bir fark yaratabilir. Benim durumumda https://www.example.com/çalışıyor ama https://www.example.comçalışmıyor.
  3. CookieManager.getInstance().setCookiezaman uyumsuz bir işlem gerçekleştiriyor. Dolayısıyla, bir URL'yi ayarladıktan hemen sonra yüklerseniz, çerezlerin önceden yazılmış olacağı garanti edilmez. Beklenmedik ve kararsız davranışları önlemek için, CookieManager # setCookie'yi (Dize url'si, Dize değeri, ValueCallback geri araması) ( bağlantı ) kullanın ve geri arama çağrıldıktan sonra url'yi yüklemeye başlayın.

Umarım iki sentim bazı insanlardan biraz zaman kazandırır, böylece benim gibi aynı sorunlarla yüzleşmek zorunda kalmazsınız.


ne kadar farklı bir çerez ayarlama olduğu example.com için çerez kaydetme farklıdır example.com ?
softmarshmallow

0

Aynı sorunla karşılaştım ve bu sorunu tüm android sürümlerinde çözecek

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

Normal URL yerine alt alan adlarının kullanılmasının daha iyi olabileceğini unutmayın. Yani, .example.comyerine ayarlayın https://example.com/.

Jody Jacobus Geers ve diğerleri sayesinde yazdıklarım:

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

Ham url'nizi kullanmayın

Onun yerine:

cookieManager.setCookie(myUrl, cookieString); 

şu şekilde kullanın:

cookieManager.setCookie("your url host", cookieString); 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.