Поддержание сеанса cookie в Android

Хорошо, у меня есть приложение для Android, в котором есть форма, два EditText, spinner и кнопка входа. Пользователь выбирает услугу со счетчика, вводит имя пользователя и пароль и нажимает логин. Данные отправляются через POST, возвращается ответ, обрабатывается, запускается новый WebView, загружается строка html, сгенерированная из ответа, и у меня есть домашняя страница любой выбранной пользователем службы.

Это все хорошо и хорошо. Теперь, когда пользователь нажимает на ссылку, информация для входа не может быть найдена, и страница просит пользователя снова войти в систему. Мой сеанс регистрации куда-то куда-то удаляется, и я не уверен, как передать информацию из класса, который контролирует основную часть моего приложения, в класс, который только запускает активность веб-просмотра.

Обработчик onClick из формы login:

private class FormOnClickListener implements View.OnClickListener {

    public void onClick(View v) {

        String actionURL, user, pwd, user_field, pwd_field;

        actionURL = "thePageURL";
        user_field = "username"; //this changes based on selections in a spinner
        pwd_field = "password"; //this changes based on selections in a spinner
        user = "theUserLogin";
        pwd = "theUserPassword";

        List<NameValuePair> myList = new ArrayList<NameValuePair>();
        myList.add(new BasicNameValuePair(user_field, user)); 
        myList.add(new BasicNameValuePair(pwd_field, pwd));

        HttpParams params = new BasicHttpParams();
        DefaultHttpClient client = new DefaultHttpClient(params);
        HttpPost post = new HttpPost(actionURL);
        HttpResponse response = null;
        BasicResponseHandler myHandler = new BasicResponseHandler();
        String endResult = null;

        try { post.setEntity(new UrlEncodedFormEntity(myList)); } 
        catch (UnsupportedEncodingException e) { e.printStackTrace(); } 

        try { response = client.execute(post); } 
        catch (ClientProtocolException e) { e.printStackTrace(); } 
        catch (IOException e) { e.printStackTrace(); }  

        try { endResult = myHandler.handleResponse(response); } 
        catch (HttpResponseException e) { e.printStackTrace(); } 
        catch (IOException e) { e.printStackTrace(); }

        List<Cookie> cookies = client.getCookieStore().getCookies();
        if (!cookies.isEmpty()) {
            for (int i = 0; i < cookies.size(); i++) {
                cookie = cookies.get(i);
            }
        }

       Intent myWebViewIntent = new Intent(MsidePortal.this, MyWebView.class);
       myWebViewIntent.putExtra("htmlString", endResult);
       myWebViewIntent.putExtra("actionURL", actionURL);
       startActivity(myWebViewIntent);
    }
}

И вот класс WebView, который обрабатывает отображение ответа:

public class MyWebView extends android.app.Activity {

    private class MyWebViewClient extends WebViewClient {

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.web);

        MyWebViewClient myClient = new MyWebViewClient();
        WebView webview = (WebView)findViewById(R.id.mainwebview);
        webview.getSettings().setBuiltInZoomControls(true); 
        webview.getSettings().setJavaScriptEnabled(true); 
        webview.setWebViewClient(myClient);

        Bundle extras = getIntent().getExtras();
        if(extras != null) 
        {
            // Get endResult
            String htmlString = extras.getString("htmlString");
            String actionURL = extras.getString("actionURL");

            Cookie sessionCookie = MsidePortal.cookie;
            CookieSyncManager.createInstance(this);
            CookieManager cookieManager = CookieManager.getInstance();
            if (sessionCookie != null) {
                cookieManager.removeSessionCookie();
                String cookieString = sessionCookie.getName()
                        + "=" + sessionCookie.getValue()
                        + "; domain=" + sessionCookie.getDomain();
                cookieManager.setCookie(actionURL, cookieString);
                CookieSyncManager.getInstance().sync();
            }  

            webview.loadDataWithBaseURL(actionURL, htmlString, "text/html", "utf-8", actionURL);}
        }
    }
}

У меня был смешанный успех в реализации этого решения для файлов cookie. Кажется, что работает для одной службы, в которую я вхожу, что я знаю, хранит файлы cookie на сервере (старые, архаичные, но он работает, и они не хотят его изменять). Служба, которую я пытаюсь сейчас, требует от пользователя сохранения cookie на локальном компьютере, и он не работает с этой настройкой.

Любые предложения?

Ответы

Ответ 1

Вам нужно сохранить cookie от одного вызова другому. Вместо создания нового DefaultHttpClient используйте этот конструктор:

private Object mLock = new Object();
private CookieStore mCookie = null;
/**
 * Builds a new HttpClient with the same CookieStore than the previous one.
 * This allows to follow the http session, without keeping in memory the
 * full DefaultHttpClient.
 * @author Régis Décamps <[email protected]>
 */
private HttpClient getHttpClient() {
        final DefaultHttpClient httpClient = new DefaultHttpClient();
        synchronized (mLock) {
                if (mCookie == null) {
                        mCookie = httpClient.getCookieStore();
                } else {
                        httpClient.setCookieStore(mCookie);
                }
        }
        return httpClient;
}

И сохраните класс Builder как поле вашего приложения.

Ответ 2

Вы можете хранить куки файлы в общих предпочтениях и загружать их по мере необходимости в других действиях.

Или попробуйте эту идею из аналогичного вопроса.

Ответ 3

Использовать это в URL-адресе Вход в систему

    List<Cookie> cookies = client.getCookieStore().getCookies();
    if (!cookies.isEmpty()) {
        for (int i = 0; i < cookies.size(); i++) {
            cookie = cookies.get(i);
        }
    }

    Cookie sessionCookie = cookie;

    if (sessionCookie != null) {
        String cookieString = sessionCookie.getName() + "="
                + sessionCookie.getValue() + "; domain="
                + sessionCookie.getDomain();
        cookieManager
                .setCookie("www.mydomain.com", cookieString);
        CookieSyncManager.getInstance().sync();
    }

Ответ 4

У меня есть эта знакомая проблема несколько недель назад, потому что вы создаете новый DefaultHttpClient каждый раз, когда вы нажимаете кнопку. попробуйте создать один DefaultHttpClient и используя тот же DefaultHttpClient для каждого запроса, который вы пытаетесь отправить. он решил мою проблему

Ответ 5

dunno, если вам все еще нужен ответ, но снова здесь появляется дополнительная информация, которая может помочь

если вы хотите сохранить файлы cookie sync'ed

// ensure any cookies set by the dialog are saved
CookieSyncManager.getInstance().sync();

и если вы хотите очистить файлы cookie

public static void clearCookies(Context context) {
        // Edge case: an illegal state exception is thrown if an instance of 
        // CookieSyncManager has not be created.  CookieSyncManager is normally
        // created by a WebKit view, but this might happen if you start the 
        // app, restore saved state, and click logout before running a UI 
        // dialog in a WebView -- in which case the app crashes
        @SuppressWarnings("unused")
        CookieSyncManager cookieSyncMngr = 
            CookieSyncManager.createInstance(context);
        CookieManager cookieManager = CookieManager.getInstance();
        cookieManager.removeAllCookie();
    }

Ответ 6

Когда запускается любое новое действие (поэтому я предполагаю, что это то же самое, когда вы запускаете новый веб-просмотр), он эффективно запускает новую программу с нуля. Это новое действие не будет иметь доступа к данным из любой предыдущей деятельности (если только эти данные не будут переданы путем присоединения к намерению).

2 возможных решения:

1) putExtra может использоваться только для передачи примитивных данных, поэтому, чтобы передать что-то более сложное, вам нужно либо

  • a) Оберните более сложную структуру в классе, который реализует Удобный интерфейс, который может быть сохранен дополнительно.

    b) Оберните более сложную структуру в классе, который реализует Сериализуемый интерфейс, который может быть сохранен дополнительно.

Любой из этих подходов довольно сложный и справедливый бит работы.

2) Лично я предпочитаю подход, предложенный rds. Чтобы уточнить, когда rds говорит:

сохраните класс Builder как поле вашего приложения.

Я думаю, что он означает расширение класса приложения. Все хранящиеся там объекты доступны во всем мире для всех видов деятельности. В этой статье очень четко объясняется, как это сделать: http://www.screaming-penguin.com/node/7746 Вы можете игнорировать материал об AsyncTask (хотя я уверен, что вам это понадобится в какой-то момент) и просто сосредоточьтесь на части расширения класса приложения.

Ответ 7

Вы использовали эту строку -

    if (sessionCookie != null) {
        cookieManager.removeSessionCookie();
    }

Чтобы каждый раз получать новый файл cookie.

Похоже, вы прошли через ту же проблему, что и я, проверьте ссылку ниже -

removeSessionCookie() проблема android (code.google., com)

говорится, что removeSessionCookie() реализуется в потоке, поэтому всякий раз, когда он вызывается; начинается поток, и после вызова setCookie(url, cookieString); он удаляет новый cookie, который вы только что установили. Поэтому для некоторых устройств он хорошо работает, поскольку removeSessionCookie() уже выполнен, а для некоторых он удаляет файл cookie, и мы получаем эту проблему.

Я предлагаю удалить этот removeSessionCookie();, поскольку вы устанавливаете только один файл cookie, поэтому он не будет конфликтовать с другими файлами cookie. Ваш код будет работать без проблем.

Ответ 8

Sever использует идентификатор сеанса, хранящийся в файлах cookie, чтобы идентифицировать определенного пользователя. Каждый язык имеет другое имя sessionID в заголовках http. Вы можете использовать какой-либо сетевой инструмент или браузер, чтобы узнать, как называется имя sessionID.

И иначе, я буду угадывать, facebook и твиттер, вы удалите весь код, связанный с сеансом, на сервере используется токен доступа для идентификации пользователя.

Как я понял?