Retrofit does not cache my response - kotlin

I have tried through almost every videos, articles and stackoverflow answer but I am not being able to cache the response in Retrofit.
I have retrofit setup is like this :
private val gson = GsonBuilder()
.setLenient()
.create()!!
private val CACHE_CONTROL = "Cache-Control"
private var cacheSize: Long = 10 * 1024 * 1024 // 10 MB
private var cache = Cache(File(applicationContext.cacheDir, "http-cache"), cacheSize)
private val offlineCacheInterceptor = Interceptor { chain ->
var request = chain.request()
Log.i("datatest", "Internet is availiable : ${isOnline(applicationContext)}")
if (!isOnline(applicationContext)) {
val cacheControl = CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build()
request = request.newBuilder()
.cacheControl(cacheControl)
.build()
}
chain.proceed(request)
}
private val networkInterceptor = Interceptor { chain ->
val response = chain.proceed(chain.request())
val cacheControl = CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build()
response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.build()
}
private val httpClient = OkHttpClient.Builder()
.addInterceptor(offlineCacheInterceptor)
.addNetworkInterceptor(networkInterceptor)
.cache(cache)
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(gson))
.client(httpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
But when I try to call the retrofit APIs with my phone in Airplane mode
I get the following error :
Unable to resolve host "my_url": No address associated with hostname
What am I doing wrong in the cache setup?
I think there is a stupid mistake I have done but haven't seen by myself.

Related

Create bearer authorization header in Kotlin Using OkHttp

I use OkHttp3 in Kotlin as a HTTP client and send Authorization Token Bearer header in request and return the result.
this is my code, but when run it the app closed :
RetrofitInstance.kt
class OAuthInterceptor(
private val tokenType: String,
private val acceessToken: String,
private val branchid : Int,
private val currency : Int,):Interceptor {
override fun intercept(chain: Interceptor.Chain): okhttp3.Response
{
var request = chain.request()
request = request.newBuilder()
.addHeader("Authorization", "$tokenType $acceessToken")
.addHeader("branchId", "$branchid")
.addHeader("currencyId", "$currency")
.build()
return chain.proceed(request)
}
}
class RetrofitInstance {
companion object {
private val client = OkHttpClient.Builder()
.addInterceptor(OAuthInterceptor(
"Bearer",
"YourToken",
123,
1)
)
.build()
val BASE_URL = "https://url"
fun getRetrofitInstance(): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client).addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.build()
}
}
}
AlbumService.Kt
interface AlbumService {
#GET("users")
suspend fun getAlbums() : Response<Albums>
}
Album.kt
class Albums : ArrayList<dataapi>()
AlbumItem.kt
data class dataapi(
#SerializedName("address")
val address: String,
)

Okhttp interceptor not working showing 401(Unauthenticated) response

OKHTTP Interceptor not working It gives me 401 Response(Unauthenticated/UnAuthorized)
Here is my Interceptor Class
InterceptorClass
class NetworkInterceptor(context: Context) : Interceptor {
private val applicationContext = context.applicationContext
private val sharedPreferenceData = SharedPreferenceData(applicationContext)
override fun intercept(chain: Interceptor.Chain): Response {
if (!isConnectionAvailable()) {
throw NoConnectionException("Error! Connecting to the network")
} else {
val requestBuilder = chain.request().newBuilder()
val token = sharedPreferenceData.getString("token", "")
requestBuilder.addHeader("Authorization", "Bearer $token")
Log.e("Token", "intercept: $token")
return chain.proceed(requestBuilder.build())
}
}
#Suppress("DEPRECATION")
fun isConnectionAvailable(): Boolean {
val cm =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm.activeNetworkInfo.also {
return it != null && it.isConnected
}
}
}
Here is the network instance class
object NetworkInstance {
fun getApi(context: Context): DataApi {
val gsonBuilder = GsonBuilder()
gsonBuilder.setLenient()
val gson = gsonBuilder.create()
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient
.Builder()
.addInterceptor(logging)
.addInterceptor(NetworkInterceptor(context))
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.addInterceptor(logging)
.build()
val retrofit = Retrofit
.Builder()
.client(client)
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
return retrofit.create(DataApi::class.java)
}
}
The issue was because of my Stupidity. I have added BASE_URL inside build.gradle which generates a Static Final variable inside BuildCondig.java which can't be altered. While Adding header BASE_URL can't be changed.

Kotlin Retrofit ignore https certifcate

Kotlin Retrofit ignore https certifcate.
I tried this Android ignore self signed certificate and converted to Kotlin. Its not working.
How can i ignore https (SSL) certificate.
My OkHttp is
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
object OwnRetrofitClient {
private val authInterceptor = Interceptor { chain ->
val newUrl = chain.request().url
.newBuilder()
.build()
val newRequest = chain.request()
.newBuilder()
.addHeader("Authorization", "bearer " + AppPreferences.token)
.url(newUrl)
.build()
chain.proceed(newRequest)
}
private val client =
OkHttpClient().newBuilder()
.addInterceptor(authInterceptor)
.connectTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(90, TimeUnit.SECONDS)
.build()
private fun retrofit(baseUrl: String = "https:some.com/api") =
Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
fun apiService(): ApiService {
return retrofit().create(ApiService::class.java)
}
}```
The example you refer to, uses java built-in HttpsUrlConnection. In okhttp, you need to add the X509TrustManager, the HostnameVerifier and the SSLSocketFactory to OkHttpClient.Builder (see https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/-builder/ssl-socket-factory/)

How to add Api_KEY into interceptor using okhttp

I have this service where I want to put the token as an interception in the okhttp instead of passing as a parameter with #Header("MY_API_KEY")
This is my code regarding the service
/**
* Provides the [PHService]
*/
fun provideService(): PHService {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PHService::class.java)
}
How can I add an interceptor for header authorization in here?
add like this
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "MY_API_KEY"); // <-- this is the important line
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
httpClient.connectTimeout(30, TimeUnit.SECONDS);
httpClient.readTimeout(30, TimeUnit.SECONDS);
httpClient.addNetworkInterceptor(logging);
OkHttpClient client = httpClient.build();
in kotlin its like
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor { chain ->
val original = chain.request()
// Request customization: add request headers
val requestBuilder = original.newBuilder()
.header("Authorization", "MY_API_KEY") // <-- this is the important line
val request = requestBuilder.build()
chain.proceed(request)
}
httpClient.connectTimeout(30, TimeUnit.SECONDS)
httpClient.readTimeout(30, TimeUnit.SECONDS)
httpClient.addNetworkInterceptor(logging)
val okHttpClient=httpClient.build()
In case you wish to add an api_key and an app_id in your requests as a query parameter using retrofit and OkHttp interceptors in kotlin. You can follow the following steps. This is useful so you dont have to pass the keys in every request in each query:
const val E_BASE_URL = "https://api.example.com"
const val API_ID = "YourApiID"
const val API_KEY = "YourApiKey"
//Here you add your url interceptor
//"app_id" and "app_key" might be different, depending on your API
val api_interceptor = Interceptor {
val originalRequest = it.request()
val newHttpUrl = originalRequest.url.newBuilder()
.addQueryParameter("app_id", API_ID)
.addQueryParameter("app_key", API_KEY)
.build()
val newRequest = originalRequest.newBuilder()
.url(newHttpUrl)
.build()
it.proceed(newRequest)
}
//Add the logger interceptor optional:
val logger = HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BASIC) }
//Build your OkHttpClient - here you add the api_interceptor and logger
val clientHTTP = OkHttpClient().newBuilder()
.addNetworkInterceptor(logger) //optional
.addNetworkInterceptor(api_interceptor)
.build()
//Build your json converter - in this example MOSHI
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
//FINALLY build your retrofit
val retrofitE = Retrofit.Builder()
.client(clientHTTP)
.baseUrl(E_BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
//You can now declare your interfaces with your REST methods as usual, for example GET which will return your object
interface RecipesService {
#GET("search")
suspend fun getRecipes(
#Query("q") recipe: String,
): RecipeResponse
}
//Finally you create your object (Singleton in Java) which generates your service via lazy delegate
object RecipesAPI {
val retrofitService: RecipesService by lazy {
retrofitE.create(RecipesService::class.java)
}
}
For this example, you need to import following dependencies in the latest version:
com.squareup.retrofit2:retrofit
com.squareup.moshi:moshi-kotlin
com.squareup.retrofit2:converter-moshi
com.squareup.okhttp3:logging-interceptor

Which way is better between companion object and fun without a class in Kotlin?

I know there isn't a static function in Kotlin, so I write two code in OkHttpService.kt and my.kt
I don't know which is better, could you tell me? Thanks!
OkHttpService.kt
class OkHttpService {
companion object {
fun httpGet(username: String, callback: Callback) {
val fetchRepoUrl = "https://api.github.com/users/$username/repos?page=1&per_page=20"
val client = OkHttpClient()
val request = Request.Builder()
.url(fetchRepoUrl)
.build()
client.newCall(request).enqueue(callback)
}
}
}
my.kt
fun OkHttpService_httpGet(username: String, callback: Callback) {
val fetchRepoUrl = "https://api.github.com/users/$username/repos?page=1&per_page=20"
val client = OkHttpClient()
val request = Request.Builder()
.url(fetchRepoUrl)
.build()
client.newCall(request).enqueue(callback)
For scoping use a regular object, not companion:
object OkHttpService{
fun httpGet(username: String, callback: Callback) {
val fetchRepoUrl = "https://api.github.com/users/$username/repos?page=1&per_page=20"
val client = OkHttpClient()
val request = Request.Builder()
.url(fetchRepoUrl)
.build()
client.newCall(request).enqueue(callback)
}
}