web-dev-qa-db-fra.com

Problème de cookie Android WebView

J'ai un serveur qui envoie à mon application Android un cookie de session à utiliser pour une communication authentifiée J'essaie de charger une WebView avec une URL Pointant sur le même serveur et j'essaie de transmettre la session Cookie pour l'authentification. Je constate que cela fonctionne de manière intermittente, mais je ne sais pas pourquoi. J'utilise le même cookie de session pour effectuer d'autres appels sur mon serveur et ceux-ci n'échouent jamais à l'authentification. J'observe uniquement ce problème lorsque vous essayez de charger une URL dans une WebView, et cela ne se produit pas à chaque fois. Très frustrant.

Vous trouverez ci-dessous le code que j'utilise pour faire cela. Toute aide est la bienvenue. 

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

Merci justingrammens ! Cela a fonctionné pour moi, j'ai réussi à partager le cookie dans mes requêtes DefaultHttpClient et mon activité WebView:

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

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

Merci Android pour avoir ruiné mon dimanche. . . Heres ce qui a corrigé mes applications (après que vous ayez lancé votre webview)

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

  CookieManager cookieManager = CookieManager.getInstance();

  cookieManager.setAcceptThirdPartyCookies( webView, true );

}

Je devrais dire que les réponses ci-dessus vont probablement fonctionner, mais dans ma situation, le moment où Android est allé v5 + mon Webview javascript Android 'apps' est mort.

9
Jody Jacobus Geers

la solution consiste à donner à Android suffisamment de temps pour traiter les cookies. Vous pouvez trouver plus d'informations ici: http://code.walletapp.net/post/46414301269/passing-cookie-to-webview

8
Jan Muller

Je voudrais enregistrer ce cookie de session en tant que préférence et repeupler avec force le gestionnaire de cookies. Il semble que le cookie de session n’ait pas survécu au redémarrage de l’activité

3
Bostone

J'ai passé la plus grande moitié de 3 heures à travailler sur un problème très similaire. Dans mon cas, j’ai reçu un certain nombre d’appels, que j’ai adressés à un service Web en utilisant un DefaulHttpClient, puis je voulais définir la session et tous les autres cookies correspondants dans ma WebView.

Je ne sais pas si cela résoudra votre problème, car je ne sais pas ce que fait votre méthode getCookie(), mais dans mon cas, j’ai dû appeler.

cookieManager.removeSessionCookie();

Tout d'abord, supprimez le cookie de session, puis ajoutez-le à nouveau. J'étais en train de constater que lorsque j'ai essayé de définir le cookie JSESSIONID sans le supprimer au préalable, la valeur sur laquelle je voulais le définir n'était pas enregistrée. Je ne sais pas si cela va vous aider, mais je pensais partager ce que j'avais trouvé.

3
Justin

Rencontré cela aussi aussi. Voici ce que j'ai fait.

Sur mon LoginActivity, dans mon AsyncTask, j'ai les éléments suivants:

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 est une autre classe contenant la variable sessionCookie définie en tant que liste de cookies; et cookieStore définissent comme BasicCookieStore cookieStore;

Ensuite, sur mon fragment, où se trouve ma WebView, j'ai les éléments suivants:

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

dans ma méthode ou juste avant de définir 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
 }

Astuce: Installez firebug sur firefox ou utilisez la console de développeur sur chrome et testez d’abord votre page Web, capturez le cookie et vérifiez le domaine afin de pouvoir le stocker quelque part et d’être sûr que vous définissez correctement le bon domaine.

Éditer: édité CookieStoreHelper.cookies à CookieStoreHelper.sessionCookie

1
Burnok

J'ai une approche différente de celle des autres personnes ici, et c'est une approche garantie de fonctionner sans traiter avec CookieSyncManager (où vous êtes à la merci de la sémantique telle que "Notez que même sync () se produit de manière asynchrone").

Essentiellement, nous naviguons jusqu'au bon domaine, puis nous exécutons le javascript à partir du contexte de la page pour définir des cookies pour ce domaine (de la même manière que la page elle-même). Cette méthode présente deux inconvénients: elle peut entraîner un temps de trajet aller-retour supplémentaire en raison de la demande HTTP supplémentaire que vous devez effectuer; et si votre site n'a pas l'équivalent d'une page vierge, il peut clignoter quelle que soit l'URL que vous avez chargée en premier avant de vous amener au bon endroit.

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

Si vous faites confiance au domaine d'où proviennent les cookies, vous pourrez peut-être vous échapper sans Apache commons, mais vous devez comprendre que cela peut présenter un risque XSS si vous ne faites pas attention.

1
Patrick Horn

Comme par magie, j'ai résolu tous les problèmes de cookies avec cette seule ligne dans onCreate:

CookieHandler.setDefault(new CookieManager());

edit: il a cessé de fonctionner aujourd'hui. :( qu'est-ce que la merde, Android.

1
Chani

Mon code de travail

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

Pour déboguer la requête, "cookieManager.setCookie (....);" Je vous recommande de parcourir le contenu de la base de données webviewCookiesChromium.db (stocké dans "/data/data/my.app.webview/database"). Vous pouvez voir les paramètres appropriés.

Désactivation de "cookieManager.removeSessionCookie ();" et/ou "cookieManager.removeAllCookie ();"

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

Comparez la valeur définie avec celles définies par le navigateur. Ajustez la demande d'installation de cookies avant que le navigateur "flags" ne soit pas installé, pour qu'il corresponde à ce que vous décidez. J'ai trouvé qu'une requête peut être "flags":

// 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"
1
Vadim.Ivanov

Ceci est un morceau de code de travail. 

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

Ici, le httpclient est l'objet DefaultHttpClient que vous avez utilisé dans la demande HttpGet/HttpPost. Aussi, une chose à s'assurer est le nom et la valeur du cookie, il devrait être donné

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

setCookie définira le cookie pour l'URL donnée.

1
droid kid

Quelques commentaires (du moins pour les API> = 21) que j'ai découverts grâce à mon expérience et qui m'ont donné des maux de tête:

  1. Les adresses http et https sont différentes. Définir un cookie pour http://www.example.com diffère de celui de cookie pour https://www.example.com
  2. Une barre oblique à la fin de l'URL peut également faire la différence. Dans mon cas, https://www.example.com/ fonctionne mais https://www.example.com ne fonctionne pas.
  3. CookieManager.getInstance().setCookie effectue une opération asynchrone. Ainsi, si vous chargez immédiatement une URL après l'avoir définie, il n'est pas garanti que les cookies auront déjà été écrits. Pour éviter les comportements inattendus et instables, utilisez CookieManager # setCookie (URL de chaîne, valeur de chaîne, rappel ValueCallback) ( link ) et commencez à charger l'URL après l'appel du rappel.

J'espère que mes deux sous gagneront du temps à certaines personnes pour que vous n'ayez pas à faire face aux mêmes problèmes que moi.

0
giorgos29cm

J'ai rencontré le même problème et il va résoudre ce problème dans toutes les versions d'Android

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
Prinkal Kumar