IT story

Android 발리 라이브러리에서 쿠키 사용

hot-time 2021. 1. 5. 19:16
반응형

Android 발리 라이브러리에서 쿠키 사용


com.android.volley 라이브러리를 사용하여 요청에 세션 쿠키를 연결하는 방법을 아는 사람이 있습니까? 웹 사이트에 로그인하면 세션 쿠키가 제공됩니다. 브라우저는 후속 요청과 함께 해당 쿠키를 다시 보냅니다. Volley는 적어도 자동적으로는 그렇게하지 않는 것 같습니다.

감사.


Volley는 실제로 자체적으로 HTTP 요청을하지 않으므로 쿠키를 직접 관리하지 않습니다. 대신 HttpStack의 인스턴스를 사용하여이를 수행합니다. 두 가지 주요 구현이 있습니다.

  • HurlStack : 내부적으로 HttpUrlConnection 사용
  • HttpClientStack : 내부적으로 Apache HttpClient 사용

쿠키 관리는 이러한 HttpStacks의 책임입니다. 그리고 그들은 각각 쿠키를 다르게 처리합니다.

2.3 미만을 지원해야하는 경우 HttpClientStack을 사용해야합니다.

HttpClient 인스턴스를 구성하고 내부에서 사용할 수 있도록 Volley에 전달합니다.

// If you need to directly manipulate cookies later on, hold onto this client
// object as it gives you access to the Cookie Store
DefaultHttpClient httpclient = new DefaultHttpClient();

CookieStore cookieStore = new BasicCookieStore();
httpclient.setCookieStore( cookieStore );

HttpStack httpStack = new HttpClientStack( httpclient );
RequestQueue requestQueue = Volley.newRequestQueue( context, httpStack  );

이 방식과 수동으로 헤더에 쿠키를 삽입하는 것의 장점은 실제 쿠키 관리가 가능하다는 것입니다. 상점의 쿠키는 만료되거나 업데이트되는 HTTP 제어에 적절하게 응답합니다.

한 단계 더 나아가 BasicCookieStore를 하위 클래스로 지정하여 쿠키를 디스크에 자동으로 유지할 수 있습니다.

하나! 이전 버전의 Android를 지원할 필요 가없는 경우 . 이 방법을 사용하십시오.

// CookieStore is just an interface, you can implement it and do things like
// save the cookies to disk or what ever.
CookieStore cookieStore = new MyCookieStore();
CookieManager manager = new CookieManager( cookieStore, CookiePolicy.ACCEPT_ALL );
CookieHandler.setDefault( manager  );

// Optionally, you can just use the default CookieManager
CookieManager manager = new CookieManager();
CookieHandler.setDefault( manager  );

HttpURLConnection은 암시 적으로 CookieManager를 쿼리합니다. HttpUrlConnection은 또한 IMO를 구현하고 작업하기에 더 성능이 뛰어나고 약간 깔끔합니다.


vmirinov가 맞습니다!

문제를 해결 한 방법은 다음과 같습니다.

수업 요청 :

public class StringRequest extends com.android.volley.toolbox.StringRequest {

    private final Map<String, String> _params;

    /**
     * @param method
     * @param url
     * @param params
     *            A {@link HashMap} to post with the request. Null is allowed
     *            and indicates no parameters will be posted along with request.
     * @param listener
     * @param errorListener
     */
    public StringRequest(int method, String url, Map<String, String> params, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, listener, errorListener);

        _params = params;
    }

    @Override
    protected Map<String, String> getParams() {
        return _params;
    }

    /* (non-Javadoc)
     * @see com.android.volley.toolbox.StringRequest#parseNetworkResponse(com.android.volley.NetworkResponse)
     */
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        // since we don't know which of the two underlying network vehicles
        // will Volley use, we have to handle and store session cookies manually
        MyApp.get().checkSessionCookie(response.headers);

        return super.parseNetworkResponse(response);
    }

    /* (non-Javadoc)
     * @see com.android.volley.Request#getHeaders()
     */
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();

        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<String, String>();
        }

        MyApp.get().addSessionCookie(headers);

        return headers;
    }
}

및 MyApp :

public class MyApp extends Application {
    private static final String SET_COOKIE_KEY = "Set-Cookie";
    private static final String COOKIE_KEY = "Cookie";
    private static final String SESSION_COOKIE = "sessionid";

    private static MyApp _instance;
  private RequestQueue _requestQueue;
  private SharedPreferences _preferences;

    public static MyApp get() {
        return _instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        _instance = this;
            _preferences = PreferenceManager.getDefaultSharedPreferences(this);
        _requestQueue = Volley.newRequestQueue(this);
    }

    public RequestQueue getRequestQueue() {
        return _requestQueue;
    }


    /**
     * Checks the response headers for session cookie and saves it
     * if it finds it.
     * @param headers Response Headers.
     */
    public final void checkSessionCookie(Map<String, String> headers) {
        if (headers.containsKey(SET_COOKIE_KEY)
                && headers.get(SET_COOKIE_KEY).startsWith(SESSION_COOKIE)) {
                String cookie = headers.get(SET_COOKIE_KEY);
                if (cookie.length() > 0) {
                    String[] splitCookie = cookie.split(";");
                    String[] splitSessionId = splitCookie[0].split("=");
                    cookie = splitSessionId[1];
                    Editor prefEditor = _preferences.edit();
                    prefEditor.putString(SESSION_COOKIE, cookie);
                    prefEditor.commit();
                }
            }
    }

    /**
     * Adds session cookie to headers if exists.
     * @param headers
     */
    public final void addSessionCookie(Map<String, String> headers) {
        String sessionId = _preferences.getString(SESSION_COOKIE, "");
        if (sessionId.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(SESSION_COOKIE);
            builder.append("=");
            builder.append(sessionId);
            if (headers.containsKey(COOKIE_KEY)) {
                builder.append("; ");
                builder.append(headers.get(COOKIE_KEY));
            }
            headers.put(COOKIE_KEY, builder.toString());
        }
    }

}

Volley의 기본 HTTP 전송 코드는 HttpUrlConnection입니다. 설명서를 올바르게 읽고 있는 경우 자동 세션 쿠키 지원을 선택해야합니다.

CookieManager cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);

CookieManager를 사용한 HttpURLConnection이 세션 쿠키를 자동으로 처리해야합니까?를 참조하십시오 .


사람들 onCreate은 당신의 방법으로 이것을 시도 합니다AppController.java

  CookieHandler.setDefault(new CookieManager());

개발자의 시간을 절약 할 수 있기를 바랍니다. 적절한 솔루션을 디버깅하고 검색하는 데 4 시간을 낭비했습니다.


'Set-Cookie'헤더가 여러 개인 경우 @Rastio 솔루션이 작동하지 않습니다. 기본 CookieManager 쿠키 저장소를 래핑하고 쿠키를 추가하기 전에 Gson을 사용하여 SharedPreferences에 저장하여 쿠키를 직렬화했습니다.

다음은 쿠키 저장소 래퍼의 예입니다.

import android.content.Context;
import android.net.Uri;
import android.util.Log;

import com.google.gson.Gson;

import java.net.CookieManager;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.net.URI;
import java.util.List;

/**
 * Class that implements CookieStore interface. This class saves to SharedPreferences the session
 * cookie.
 *
 * Created by lukas.
 */
public class PersistentCookieStore implements CookieStore {

    private CookieStore mStore;
    private Context mContext;
    private Gson mGson;

    public PersistentCookieStore(Context context) {
        // prevent context leaking by getting the application context
        mContext = context.getApplicationContext();
        mGson = new Gson();

        // get the default in memory store and if there is a cookie stored in shared preferences,
        // we added it to the cookie store
        mStore = new CookieManager().getCookieStore();
        String jsonSessionCookie = Prefs.getJsonSessionCookie(mContext);
        if (!jsonSessionCookie.equals(Prefs.DEFAULT_STRING)) {
            HttpCookie cookie = mGson.fromJson(jsonSessionCookie, HttpCookie.class);
            mStore.add(URI.create(cookie.getDomain()), cookie);
        }
    }

    @Override
    public void add(URI uri, HttpCookie cookie) {
        if (cookie.getName().equals("sessionid")) {
            // if the cookie that the cookie store attempt to add is a session cookie,
            // we remove the older cookie and save the new one in shared preferences
            remove(URI.create(cookie.getDomain()), cookie);
            Prefs.saveJsonSessionCookie(mContext, mGson.toJson(cookie));
        }

        mStore.add(URI.create(cookie.getDomain()), cookie);
    }

    @Override
    public List<HttpCookie> get(URI uri) {
        return mStore.get(uri);
    }

    @Override
    public List<HttpCookie> getCookies() {
        return mStore.getCookies();
    }

    @Override
    public List<URI> getURIs() {
        return mStore.getURIs();
    }

    @Override
    public boolean remove(URI uri, HttpCookie cookie) {
        return mStore.remove(uri, cookie);
    }

    @Override
    public boolean removeAll() {
        return mStore.removeAll();
    }
}

그런 다음 CookieManager에 설정된 쿠키 저장소를 사용하려면 그게 다입니다!

CookieManager cookieManager = new CookieManager(new PersistentCookieStore(mContext),
    CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);

게시물을 알고 조금 낡았지만 최근의 문제를 겪었고, 로그인 한 사용자의 세션을 서버간에 공유해야했고, 서버 측 솔루션은 쿠키를 통해 클라이언트 측에서 제공 할 값을 요구하기 시작했습니다. 우리가 찾은 한 가지 해결책은 아래 링크 에서 찾은 것을 인스턴스화하기 전에 RequestQueue메서드의 코드 스 니펫 인 객체에 매개 변수를 추가 하고 문제를 해결하는 것이 었습니다. 방법은 확실하지 않지만 작동하기 시작했습니다.getRequestQueueRequestQueue

http://woxiangbo.iteye.com/blog/1769122 방문

public class App extends Application {

    public static final String TAG = App.class.getSimpleName();

    private static App         mInstance;

    public static synchronized App getInstance() {
        return App.mInstance;
    }

    private RequestQueue mRequestQueue;

    public <T> void addToRequestQueue( final Request<T> req ) {
        req.setTag( App.TAG );
        this.getRequestQueue().add( req );
    }

    public <T> void addToRequestQueue( final Request<T> req, final String tag ) {
        req.setTag( TextUtils.isEmpty( tag ) ? App.TAG : tag );
        this.getRequestQueue().add( req );
    }

    public void cancelPendingRequests( final Object tag ) {
        if ( this.mRequestQueue != null ) {
            this.mRequestQueue.cancelAll( tag );
        }
    }

    public RequestQueue getRequestQueue() {

        if ( this.mRequestQueue == null ) {


            DefaultHttpClient mDefaultHttpClient = new DefaultHttpClient();

            final ClientConnectionManager mClientConnectionManager = mDefaultHttpClient.getConnectionManager();
            final HttpParams mHttpParams = mDefaultHttpClient.getParams();
            final ThreadSafeClientConnManager mThreadSafeClientConnManager = new ThreadSafeClientConnManager( mHttpParams, mClientConnectionManager.getSchemeRegistry() );

            mDefaultHttpClient = new DefaultHttpClient( mThreadSafeClientConnManager, mHttpParams );

            final HttpStack httpStack = new HttpClientStack( mDefaultHttpClient );

            this.mRequestQueue = Volley.newRequestQueue( this.getApplicationContext(), httpStack );
        }

        return this.mRequestQueue;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        App.mInstance = this;
    }
}

// 토큰 값 설정

ObjectRequest.setHeader( "Cookie", "JSESSIONID=" + tokenValueHere );

이 방법을 사용하여 쿠키와 함께 Volley를 사용하여 다음을 수행합니다.

  1. Apache 2 라이선스에 따라 매우 잘 테스트 된 코드 만 사용하십시오.
  2. 동시에 원하는만큼 요청하십시오.
  3. 쿠키가 기기에 유지되는지 확인
  4. 바퀴를 재발 명 할 필요가 없음

내 서버는 쿠키를 사용하여 인증하고 분명히 쿠키가 장치에 유지되도록하고 싶었습니다. 그래서 내 솔루션은 Android 용 Asynchronous Http Client 에서 PersistentCookieStoreSerializableCookie 클래스 를 사용하는 것이 었습니다 .

먼저, 동시 요청 을 활성화하려면 Android 용 Apache HttpClient v4.3 포트가 필요합니다. 시스템과 함께 제공되는 포트는 오래되었습니다. 여기에 더 많은 정보가 있습니다 . 저는 Gradle을 사용하므로 다음과 같이 가져 왔습니다.

dependencies {
    compile group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.3'
}

RequestQueue를 얻는 함수 (응용 프로그램을 확장하는 클래스에서) :

private RequestQueue mRequestQueue;
private CloseableHttpClient httpClient;

...

public RequestQueue getRequestQueue() {
    if (mRequestQueue == null) {
        httpClient = HttpClients.custom()
            .setConnectionManager(new PoolingHttpClientConnectionManager())
            .setDefaultCookieStore(new PersistentCookieStore(getApplicationContext()))
            .build();
        mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new HttpClientStack(httpClient));
    }
    return mRequestQueue;
}

이것이 내가 요청을 대기열에 넣는 방법입니다.

public <T> void addToRequestQueue(Request<T> req, String tag) {
    req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
    getRequestQueue().add(req);
}

그게 다야!


gingerbread + Android 버전 :

쿠키 세션을 유지하는 또 다른 쉬운 방법은 APPLICATION 클래스로 확장 된 클래스에 다음 줄을 추가하는 것입니다.

CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

Loopj 라이브러리를 사용하여 이미 애플리케이션 구현을 시작한 경우 이전 연결을 닫지 않는 등 다양한 오류가 발생하기 때문에 Volley.newRequestQUeue ()에서 새 HttpClient 인스턴스를 사용할 수 없음을 알 수 있습니다.

다음과 같은 오류 :

java.lang.IllegalStateException: No wrapped connection

Invalid use of SingleClientConnManager: connection still allocated.

이제 때로는 모든 이전 API 호출을 리팩터링하고 volley를 사용하여 다시 작성하는 데 시간이 걸리지 만 volley와 loopj를 동시에 사용하고 모든 것을 volley로 작성할 때까지 둘 사이에 쿠키 저장소를 공유 할 수 있습니다 (loopj 대신 volley 사용, 훨씬 낫습니다 :)).

이것은 loopj에서 volley와 HttpClient 및 CookieStore를 공유하는 방법입니다.

// For example you initialize loopj first
private static AsyncHttpClient client = new AsyncHttpClient();
sCookieStore = new PersistentCookieStore(getSomeContextHere());
client.setTimeout(DEFAULT_TIMEOUT);
client.setMaxConnections(12);
client.setCookieStore(sCookieStore);
client.setThreadPool(((ThreadPoolExecutor) Executors.newCachedThreadPool()));

public static RequestQueue getRequestQueue(){
    if(mRequestQueue == null){

    HttpClient httpclient = KkstrRestClient.getClient().getHttpClient();

    ((AbstractHttpClient) httpclient).setCookieStore( ApplicationController.getCookieStore() );

    HttpStack httpStack = new HttpClientStack(httpclient);

    mRequestQueue = Volley.newRequestQueue(getContext(), httpStack);
    }

    return mRequestQueue;
}

이것은 나에게 일어 났고 loopj를 사용하기 시작했습니다. 50,000 줄의 코드와 loopj가 항상 예상대로 작동하지 않는다는 사실을 발견 한 후 Volley로 전환하기로 결정했습니다.


@CommonsWare의 대답은 내가 사용할 것입니다. 그러나 완료되면 KitKat에 버그 가있는 것 같습니다 ( 영구 쿠키를 원하는 경우 필요한 CookieManager사용자 지정 CookieStore만들 때 ). CookieStore사용되는 의 구현에 관계없이 Volley가를 던질 수 있다는 사실을 감안할 때 NullpointerException나만의 고유 한 파일을 만들어야 CookieHandler했습니다. 도움이되면 사용하십시오.

public class MyCookieHandler extends CookieHandler {

private static final String VERSION_ZERO_HEADER = "Set-cookie";

private static final String VERSION_ONE_HEADER = "Set-cookie2";
private static final String COOKIE_HEADER = "Cookie";

private static final String COOKIE_FILE = "Cookies";
private Map<String, Map<String, HttpCookie>> urisMap;

private Context context;

public MyCookieHandler(Context context) {

    this.context = context;
    loadCookies();

}

@SuppressWarnings("unchecked")
private void loadCookies() {
    File file = context.getFileStreamPath(COOKIE_FILE);
    if (file.exists())
        try {

            FileInputStream fis = context.openFileInput(COOKIE_FILE);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    fis));
            String line = br.readLine();
            StringBuilder sb = new StringBuilder();
            while (line != null) {
                sb.append(line);
                line = br.readLine();
            }
            Log.d("MyCookieHandler.loadCookies", sb.toString());
            JSONObject jsonuris = new JSONObject(sb.toString());
            urisMap = new HashMap<String, Map<String, HttpCookie>>();
            Iterator<String> jsonurisiter = jsonuris.keys();

            while (jsonurisiter.hasNext()) {
                String prop = jsonurisiter.next();
                HashMap<String, HttpCookie> cookiesMap = new HashMap<String, HttpCookie>();
                JSONObject jsoncookies = jsonuris.getJSONObject(prop);
                Iterator<String> jsoncookiesiter = jsoncookies.keys();
                while (jsoncookiesiter.hasNext()) {
                    String pprop = jsoncookiesiter.next();
                    cookiesMap.put(pprop,
                            jsonToCookie(jsoncookies.getJSONObject(pprop)));
                }
                urisMap.put(prop, cookiesMap);

            }

        } catch (Exception e) {

            e.printStackTrace();
        }
    else {
        urisMap = new HashMap<String, Map<String, HttpCookie>>();
    }
}

@Override
public Map<String, List<String>> get(URI arg0,
        Map<String, List<String>> arg1) throws IOException {
    Log.d("MyCookieHandler.get",
            "getting Cookies for domain: " + arg0.getHost());
    Map<String, HttpCookie> cookies = urisMap.get(arg0.getHost());
    if (cookies != null)
        for (Entry<String, HttpCookie> cookie : cookies.entrySet()) {
            if (cookie.getValue().hasExpired()) {
                cookies.remove(cookie.getKey());
            }
        }

    if (cookies == null || cookies.isEmpty()) {
        Log.d("MyCookieHandler.get", "======");
        return Collections.emptyMap();
    }
    Log.d("MyCookieHandler.get",
            "Cookie : " + TextUtils.join("; ", cookies.values()));
    Log.d("MyCookieHandler.get", "======");
    return Collections.singletonMap(COOKIE_HEADER, Collections
            .singletonList(TextUtils.join("; ", cookies.values())));
}

@Override
public void put(URI uri, Map<String, List<String>> arg1) throws IOException {
    Map<String, HttpCookie> cookies = parseCookies(arg1);
    Log.d("MyCookieHandler.put",
            "saving Cookies for domain: " + uri.getHost());

    addCookies(uri, cookies);
    Log.d("MyCookieHandler.put",
            "Cookie : " + TextUtils.join("; ", cookies.values()));
    Log.d("MyCookieHandler.put", "======");

}

private void addCookies(URI uri, Map<String, HttpCookie> cookies) {
    if (!cookies.isEmpty()) {
        if (urisMap.get(uri.getHost()) == null) {
            urisMap.put(uri.getHost(), cookies);
        } else {
            urisMap.get(uri.getHost()).putAll(cookies);
        }
        saveCookies();
    }
}

private void saveCookies() {
    try {
        FileOutputStream fos = context.openFileOutput(COOKIE_FILE,
                Context.MODE_PRIVATE);

        JSONObject jsonuris = new JSONObject();
        for (Entry<String, Map<String, HttpCookie>> uris : urisMap
                .entrySet()) {
            JSONObject jsoncookies = new JSONObject();
            for (Entry<String, HttpCookie> savedCookies : uris.getValue()
                    .entrySet()) {
                jsoncookies.put(savedCookies.getKey(),
                        cookieToJson(savedCookies.getValue()));
            }
            jsonuris.put(uris.getKey(), jsoncookies);
        }
        fos.write(jsonuris.toString().getBytes());
        fos.close();
        Log.d("MyCookieHandler.addCookies", jsonuris.toString());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static JSONObject cookieToJson(HttpCookie cookie) {
    JSONObject jsoncookie = new JSONObject();
    try {
        jsoncookie.put("discard", cookie.getDiscard());
        jsoncookie.put("maxAge", cookie.getMaxAge());
        jsoncookie.put("secure", cookie.getSecure());
        jsoncookie.put("version", cookie.getVersion());
        jsoncookie.put("comment", cookie.getComment());
        jsoncookie.put("commentURL", cookie.getCommentURL());
        jsoncookie.put("domain", cookie.getDomain());
        jsoncookie.put("name", cookie.getName());
        jsoncookie.put("path", cookie.getPath());
        jsoncookie.put("portlist", cookie.getPortlist());
        jsoncookie.put("value", cookie.getValue());

    } catch (JSONException e) {

        e.printStackTrace();
    }

    return jsoncookie;
}

private static HttpCookie jsonToCookie(JSONObject jsonObject) {
    HttpCookie httpCookie;
    try {
        httpCookie = new HttpCookie(jsonObject.getString("name"),
                jsonObject.getString("value"));
        if (jsonObject.has("comment"))
            httpCookie.setComment(jsonObject.getString("comment"));
        if (jsonObject.has("commentURL"))
            httpCookie.setCommentURL(jsonObject.getString("commentURL"));
        if (jsonObject.has("discard"))
            httpCookie.setDiscard(jsonObject.getBoolean("discard"));
        if (jsonObject.has("domain"))
            httpCookie.setDomain(jsonObject.getString("domain"));
        if (jsonObject.has("maxAge"))
            httpCookie.setMaxAge(jsonObject.getLong("maxAge"));
        if (jsonObject.has("path"))
            httpCookie.setPath(jsonObject.getString("path"));
        if (jsonObject.has("portlist"))
            httpCookie.setPortlist(jsonObject.getString("portlist"));
        if (jsonObject.has("secure"))
            httpCookie.setSecure(jsonObject.getBoolean("secure"));
        if (jsonObject.has("version"))
            httpCookie.setVersion(jsonObject.getInt("version"));
        return httpCookie;
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return null;

}

private Map<String, HttpCookie> parseCookies(Map<String, List<String>> map) {
    Map<String, HttpCookie> response = new HashMap<String, HttpCookie>();

    for (Entry<String, List<String>> e : map.entrySet()) {
        String key = e.getKey();
        if (key != null
                && (key.equalsIgnoreCase(VERSION_ONE_HEADER) || key
                        .equalsIgnoreCase(VERSION_ZERO_HEADER))) {
            for (String cookie : e.getValue()) {
                try {
                    for (HttpCookie htpc : HttpCookie.parse(cookie)) {
                        response.put(htpc.getName(), htpc);
                    }
                } catch (Exception e1) {

                    Log.e("MyCookieHandler.parseCookies",
                            "Error parsing cookies", e1);
                }
            }

        }
    }
    return response;

}
}

이 답변은 철저히 테스트되지 않았습니다. 저는 JSON을 사용하여 쿠키를 직렬화했습니다. 왜냐하면 해당 클래스는 구현되지 않고 Serializable최종 이기 때문 입니다.


내 프로젝트 CookieManager에서 android.webkit.CookieManager. Volley가 쿠키를 자동으로 처리하도록하려면 아래와 같이 핸들러를 설정해야합니다.

CookieManager cookieManager = 새로운 java.net.CookieManager (); CookieHandler.setDefault (cookieManager);

ReferenceURL : https://stackoverflow.com/questions/16680701/using-cookies-with-android-volley-library

반응형