課題
Androidとサーバーで通信(HTTPベース)するとき、サーバーの都合でどうしてもAndroidクライアント側でCookieセットしてほしいという要望があり、OkHttp3( http://square.github.io/okhttp/ )でAndroid側からsetCookieする方法を考えてみました。
利用したライブラリ okhttp/3.6.0
前置き
すでに解決案があるかとおもい探してみると類似の話題がいくつかありますが、私の求めているものと微妙に違っていた(or 解決しきれていなかった)ので自分でつくることにしました。
-
set cookie を強制する例としては、 interceptで上書きする手法等
http://stackoverflow.com/questions/35743291/add-cookie-to-client-request-okhttp/43014982#43014982 -
OkHttp3のcookieハンドリングと永続化
https://github.com/franmontiel/PersistentCookieJar
解決策
OkHttp3CookieHelper というヘルパークラスをつくりました。
以下のようにすると、クライアント側で独自のクッキーを強制的にセットします。
もちろん、サーバーから発行されたその他のクッキーもハンドリングされます。
永続化の仕組みは必要になったらいれます。当面オンメモリで問題なさそうです。
以下のコードは特にプラットフォーム依存していないのでPure JavaでもAndroidでも動作します。
サンプルコード
String url = "https://example.com/webapi";
OkHttp3CookieHelper cookieHelper = new OkHttp3CookieHelper();
cookieHelper.setCookie(url, "cookie_name", "cookie_value");
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(cookieHelper.cookieJar())
.build();
Request request = new Request.Builder()
.url(url)
.build();
※ヘルパークラスはgraldeで**compile 'org.riversun:okhttp3-cookie-helper:1.0.1'**でロードできます。
ヘルパークラスのソースコード
public class OkHttp3CookieHelper {
private final Map<String, List<Cookie>> mServerCookieStore = new ConcurrentHashMap<String, List<Cookie>>();
private Map<String, List<Cookie>> mClientCookieStore = new ConcurrentHashMap<String, List<Cookie>>();
private final CookieJar mCookieJar = new CookieJar() {
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> serverCookieList = mServerCookieStore.get(url.host());
if (serverCookieList == null) {
serverCookieList = new ArrayList<Cookie>();
}
final List<Cookie> clientCookieStore = mClientCookieStore.get(url.host());
if (clientCookieStore != null) {
serverCookieList.addAll(clientCookieStore);
}
return serverCookieList != null ? serverCookieList : new ArrayList<Cookie>();
}
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> unmodifiableCookieList) {
mServerCookieStore.put(url.host(), new ArrayList<Cookie>(unmodifiableCookieList));
}
};
public void setCookie(String url, Cookie cookie) {
final String host = HttpUrl.parse(url).host();
List<Cookie> cookieListForUrl = mClientCookieStore.get(host);
if (cookieListForUrl == null) {
cookieListForUrl = new ArrayList<Cookie>();
mClientCookieStore.put(host, cookieListForUrl);
}
putCookie(cookieListForUrl, cookie);
}
public void setCookie(String url, String key, String value) {
final HttpUrl httpUrl = HttpUrl.parse(url);
setCookie(url, Cookie.parse(httpUrl, key + "=" + value));
}
public void setCookie(HttpUrl httpUrl, String key, String value) {
setCookie(httpUrl.host(), Cookie.parse(httpUrl, key + "=" + value));
}
public CookieJar cookieJar() {
return mCookieJar;
}
private void putCookie(List<Cookie> storedCookieList, Cookie newCookie) {
Cookie oldCookie = null;
for (Cookie storedCookie : storedCookieList) {
// create key for comparison
final String oldCookieKey = storedCookie.name() + storedCookie.path();
final String newCookieKey = newCookie.name() + newCookie.path();
if (oldCookieKey.equals(newCookieKey)) {
oldCookie = storedCookie;
break;
}
}
if (oldCookie != null) {
storedCookieList.remove(oldCookie);
}
storedCookieList.add(newCookie);
}
}
公開先
コードは以下にて公開
github
gradle
compile 'org.riversun:okhttp3-cookie-helper:1.0.1'
maven
<dependency>
<groupId>org.riversun</groupId>
<artifactId>okhttp3-cookie-helper</artifactId>
<version>1.0.1</version>
</dependency>