-
-
Save nikhiljha/52d45ca69a8415c6990d2a63f61184ff to your computer and use it in GitHub Desktop.
// By Nikhil Jha | |
// License MIT | |
// DON'T ADD THIS FILE TO YOUR OTHER CLASSES | |
// THIS IS AN EXAMPLE TO TEACH YOU HOW TO MAKE REQUESTS WITH THE MAGIC COOKIES | |
OkHttpClient client = new OkHttpClient(); | |
OkHttpClient.Builder builder = new OkHttpClient.Builder(); | |
builder.addInterceptor(new AddCookiesInterceptor(context)); // VERY VERY IMPORTANT | |
builder.addInterceptor(new ReceivedCookiesInterceptor(context)); // VERY VERY IMPORTANT | |
client = builder.build(); | |
Retrofit retrofit = new Retrofit.Builder() | |
.baseUrl("my-base") // REQUIRED | |
.client(client) // VERY VERY IMPORTANT | |
.addConverterFactory(GsonConverterFactory.create()) | |
.build(); // REQUIRED | |
Your.ThingyClass = retrofit.create(Your.ThingyClass.class); | |
Call<...> call = yourclass.somecall(new yourclass(example, example)); |
thanks a ton bro !!
Really helpful.
Bro, u just saved me with 36-44 lines from AddCookiesInterceptor class. Thank you very much!
i have a problem....when i enter wrong password this code return the old cookie
Thank you!
Thank you very much!
Hi,
I have a problem with this in AddCookiesInterceptor.java :
for (String cookie : preferences) { builder.addHeader("Cookie", cookie); }
I used Log.v to see that it works or not. it shows everything in the log but my request does not have the cookies.
even I change it to something like this:
int i =0; for (String cookie : preferences) { builder.addHeader("header"+i, cookie); Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp i++; }
to see what is happening and again I don't get these values in my header.
could you help me how to solve this problem?
other things work perfectly and thank you for your detailed files.
Thank you so muuuuuch! For some reason, answer from SO https://stackoverflow.com/a/36865953/2098493 didn't work for me and also https://github.com/franmontiel/PersistentCookieJar.
Your solution persists server request cookie even if app is destroyed! :) I'm so happy. Finally found the right one.
Update:
For some reason, this solution has issues with a nodejs project using passport. The socket.handshake.session
does not store passport user even if user is already logged in. I had to use another persistent cookie store solution.
Now, this is what really worked for my project. https://gist.github.com/lezorich/8f3f3a54f07515881581.
A thing I wanted to add is if you are using this for jsessionid
's then you could also add a separate time string to the sharedpreferences every time you save a cookie and just check if the time passed is smaller than the expiry time of the token that way you can avoid a lot of unnecessary logins.
EDIT: Like this
Perfect, Thanks a lot
अच्छे से काम किया कर भाई
Kotlin version, with helper method to create OkHttp client and Retrofit instance. May be useful ;)
CookieStore.kt
import android.content.Context
import android.preference.PreferenceManager
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import java.io.IOException
private val cookiesKey = "appCookies"
class SendSavedCookiesInterceptor(private val context: Context) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val builder = chain.request().newBuilder()
val preferences = PreferenceManager
.getDefaultSharedPreferences(context)
.getStringSet(cookiesKey, HashSet()) as HashSet<String>
preferences.forEach {
builder.addHeader("Cookie", it)
}
return chain.proceed(builder.build())
}
}
class SaveReceivedCookiesInterceptor(private val context: Context) : Interceptor {
@JvmField
val setCookieHeader = "Set-Cookie"
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val originalResponse = chain.proceed(chain.request())
if (!originalResponse.headers(setCookieHeader).isEmpty()) {
val cookies = PreferenceManager
.getDefaultSharedPreferences(context)
.getStringSet(cookiesKey, HashSet()) as HashSet<String>
originalResponse.headers(setCookieHeader).forEach {
cookies.add(it)
}
PreferenceManager
.getDefaultSharedPreferences(context)
.edit()
.putStringSet(cookiesKey, cookies)
.apply()
}
return originalResponse
}
}
fun OkHttpClient.Builder.setCookieStore(context: Context) : OkHttpClient.Builder {
return this
.addInterceptor(SendSavedCookiesInterceptor(context))
.addInterceptor(SaveReceivedCookiesInterceptor(context))
}
RetrofitHelper.kt
private val httpConnectTimeoutSeconds = 10
private val httpWriteTimeoutSeconds = 10
private val httpReadTimeoutSeconds = 10
val userAgent = "Your User Agent"
fun newHttpClient(context: Context): OkHttpClient {
val loggingInterceptor = HttpLoggingInterceptor { Log.d("OkHttp", it) }
loggingInterceptor.level = if (BuildConfig.DEBUG)
HttpLoggingInterceptor.Level.BODY // debug log level
else
HttpLoggingInterceptor.Level.NONE // release log level
return OkHttpClient.Builder()
.followRedirects(true)
.followSslRedirects(true)
.retryOnConnectionFailure(true)
.setCookieStore(context)
.addInterceptor(loggingInterceptor)
.addNetworkInterceptor { chain ->
val request = chain.request().newBuilder()
.header("User-Agent", userAgent)
.build()
chain.proceed(request)
}
.cache(null)
.connectTimeout(httpConnectTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.writeTimeout(httpWriteTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.readTimeout(httpReadTimeoutSeconds.toLong(), TimeUnit.SECONDS)
.build()
}
fun <T> newRetrofit(context: Context, baseUrl: String, service: Class<T>): T {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(newHttpClient(context))
.build()
return retrofit.create(service)
}
Then, for example in your application subclass, you can write:
class App: Application() {
val apiClient by lazy {
newRetrofit(this, "https://www.yourserver.com/api", YourAPI::class.java)
}
override fun onCreate() {
super.onCreate()
Log.i("App start", "App initialization")
// Do some other initializations
}
}
Thanks @gotev. Very useful classes.
Hi, it is kinda old so reply here. But I have one question. Do I have to call AddCookiesInterceptor and ReceiveCookiesInterceptor every time I have a query?
@makiabuan the interceptors needs to be added once in the http client. Make sure that all requests are using the same okhttp client.
You do not need to call anything. The interceptor does the work by itself.
Thank you very much, This work for me.
Lifesaver !! Thank you.
Anyone has problem on Android Pie with these interceptors? It seems that they are not triggered on Android 9, on other versions it works perfectly..
It seems that the problem was in CertificateFactory.getInstance("X.509", "BC"), X.509 is not found for Android 9. CertificateFactory.getInstance("X509") is the fix.
Thanks, Worked for me
Thanks Bro, its working.. :)
Great help. Thanks Bro.
yo bro thanks ,,, its working, you saved my ass :D
Great help. Thanks
I'm using hilt and am struggling to make 'context' available. Any suggestions?
I got it. My problem was trying to use @ApplicationContext as is (@ApplicationContext context: ApplicationContext). It works fine if you leave it as Context (@ApplicationContext context: Context)
I've pulled everything together for a Hilt-based solution at https://stackoverflow.com/questions/67950681/using-cookies-with-retrofit-and-hilt-and-recommended-architecture
Thanks.