Проблема с файлом cookie в WebView Android - PullRequest
80 голосов
/ 31 октября 2009

У меня есть сервер, который отправляет моему приложению для Android файл cookie сеанса, который будет использоваться для аутентифицированное общение. Я пытаюсь загрузить WebView с URL указывая на тот же сервер, и я пытаюсь пройти в сеансе куки для аутентификации. Я наблюдаю, что это работает с перерывами, но я понятия не имею, почему. Я использую тот же файл cookie сеанса, чтобы делать другие вызовы на моем сервере, и они никогда не терпят неудачу при аутентификации. Я наблюдаю эту проблему только при попытке загрузить URL в WebView, и это происходит не каждый раз. Очень расстраивает.

Ниже приведен код, который я использую для этого. Любая помощь будет оценена.

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

Ответы [ 14 ]

1 голос
/ 02 апреля 2013

У меня здесь другой подход, отличающийся от других, и этот подход гарантированно работает, не имея отношения к CookieSyncManager (где вы находитесь во власти семантики, такой как «Обратите внимание, что даже sync () происходит асинхронно»).

По сути, мы переходим к правильному домену, затем выполняем javascript из контекста страницы, чтобы установить куки для этого домена (так же, как и сама страница). Два недостатка этого метода заключаются в том, что может потребоваться дополнительное время приема-передачи из-за дополнительного 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, если вы не будете осторожны.

0 голосов
/ 29 октября 2018

Я столкнулся с той же проблемой, и она решит эту проблему во всех версиях 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 голосов
/ 24 октября 2018

Пара комментариев (по крайней мере, для API> = 21), которые я узнал из своего опыта и доставил мне головную боль:

  1. http и https URL разные. Установка cookie для http://www.example.com отличается от установки cookie для https://www.example.com
  2. Косая черта в конце URL также может иметь значение. В моем случае https://www.example.com/ работает, но https://www.example.com не работает.
  3. CookieManager.getInstance().setCookie выполняет асинхронную операцию. Таким образом, если вы загрузите URL-адрес сразу после его установки, это не гарантирует, что файлы cookie будут уже записаны. Чтобы предотвратить непредвиденное и нестабильное поведение, используйте CookieManager # setCookie (строковый URL-адрес, строковое значение, обратный вызов ValueCallback) ( ссылка ) и начните загрузку URL-адреса после вызова обратного вызова.

Я надеюсь, что мои два цента сэкономят некоторое время у некоторых людей, поэтому вам не придется сталкиваться с такими же проблемами, как я.

0 голосов
/ 12 мая 2015

Не используйте ваш сырой URL

Вместо:

cookieManager.setCookie(myUrl, cookieString); 

используйте это так:

cookieManager.setCookie("your url host", cookieString); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...