The answer of @CommonsWare is the one I'd use. However, it looks like KitKat is having some bugs when that's done (When you create a CookieManager
with custom CookieStore
which you need if you want persistent Cookies).
Given the fact that regardless of the implementation of the CookieStore
that is used, Volley would throw a NullpointerException
, I had to create my own CookieHandler
... use it if you find it helpful.
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;
}
}
This answer hasn't been thoroughly tested. I used JSON to serialize Cookies, because well, that class don't implement Serializable
and it's final.
HttpUrlConnection
,HttpClient
), not Volley itself. Have you tried using one of those directly? – CondyleHttpUrlConnection
, in particular, has been around for ~15 years, and there are plenty of examples of how to use it. – CondyleNetworkResponse.headers
field and then attach it to every subsequent request by overridingRequest.getHeaders
method – Haver