1

I am working on an android app using Dagger2 + Retrofit + RxAndroid + OkHttp3 + New architecture components. Min sdk = 16.

Issue : When running the app on API 16, the Url generation is not correct. Url is missing the @QueryMap parameters I am passing via Retrofit. The same is working fine when I am testing the app on api levels 21+.

Correct url - on api 21+ - "http://api.apixu.com/v1/forecast.json?q=IDR&days=10&key=apikey"

url generated on api 16/19 - "http://api.apixu.com/v1/forecast.json"

Retrofit Interface -

@GET("forecast.json")
fun fetchWeatherDetails(
    @QueryMap hashMap: @NotNull HashMap<String, String>
): @NotNull Observable<ApiResponse>

Retrofit Builder -

val httpClient = getOkHttpClient()
    return Retrofit.Builder()
        .baseUrl(apiBaseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(httpClient)
        .build()

OkHttpClient -

val builder = OkHttpClient.Builder()
    builder
        .cache(cache)
        .connectTimeout(60, TimeUnit.SECONDS)
        .readTimeout(60, TimeUnit.SECONDS)
        .followRedirects(true)
        .followSslRedirects(true)

    val httpLoggingInterceptor = HttpLoggingInterceptor()

    if (BuildConfig.DEBUG) {
        httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
    } else {
        httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.NONE
    }

    builder.addInterceptor(HeaderInterceptor())
        .addInterceptor(httpLoggingInterceptor)
    return builder.build()

Its been more than 2 days since I am stuck in this issue. Any help would be appreciated.

Update : Api query Code is working fine on API 21+.

Failed on API-16 & API-19.

Pranav Bhoraskar
  • 115
  • 1
  • 13
  • Your issue is weird, can't say anything but one suggestion, try to using query rather then QueryMap. May fix your issue. – Jaykishan Sewak Mar 20 '19 at 09:52
  • Tried. With @Query - Same issue. When passed the entire url - it was working fine. The issue I believe is simple - url being parsed on api23+ but not on api 16. I was wondering if it has anything to do with backward compatibility for api level 16. – Pranav Bhoraskar Mar 20 '19 at 09:54

3 Answers3

1

It's obvious that your URL didn't encoded, to do so you need to insure that it's get encoded on all platforms using @QueryMap(encoded = true).

If it doesn't success I'm afraid that you need to do that manually using custom interceptor to encode such characters like ? which equal to %3F, e.g:

@Override
    Response intercept(Interceptor.Chain chain) throws IOException {
        Request request = chain.request()
        def string = request.url().toString()
        string = string.replace("%26", "&")
        string = string.replace("%3D", "=")
        string = string.replace("%3F", "?")

        Request newRequest = new Request.Builder()
            .url(string)
            .build()

        return chain.proceed(newRequest)
    }

References:

Ibrahim Ali
  • 1,237
  • 9
  • 20
  • So why is it working in api level 23+ and not in api level 16? That is the main question. The retrofit is querying the url properly and displaying results as expected in api23+. But when I am running it on api16 -> gives error. And in the log I can see that the url which is queried is not parsed properly. – Pranav Bhoraskar Mar 20 '19 at 09:43
  • @PranavBhoraskar I believe there is a support drop 16+ i.e: annotation or some of external API's, which will be hard to fix with existence of API **29**. – Ibrahim Ali Mar 20 '19 at 10:12
1

Man, read the OkHttp Requirements section: https://github.com/square/okhttp#requirements It literally mentions only 3.12.x branch supports Android 2.3+ (API level 9+) and Java 7+. It was duo to lack support for TLS 1.2 for device < API 21. If you really wanna support anything that under API 21 then update your OkHttp version to 3.12.x which will be still available til December 31, 2020.

Yen
  • 11
  • 1
0

Finally!! I solved the issue. Solution - Trick was to use Interceptor. With checks for correct SDK VERSION and interceptor, finally I got my thing running.

internal class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {    
var request = chain.request()    
val url = request.url().newBuilder()
            .addQueryParameter("key", API_KEY)
            .addQueryParameter("q", QUERY_PARAMETER)
            .addQueryParameter("days", DAYS)
            .build()
request = request.newBuilder().url(url).build()
return chain.proceed(request)
  }
}

OkHttpClient needed SDK_VERSION check -

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
   builder.addInterceptor(HeaderInterceptor())
}

So catch here for me was - @QueryMap(in retrofit) worked fine to build the url for SDK-21+. For SDKs<21 I used interceptor as mentioned above for building the url.

I thank you all for the help on this matter. I believe someone out there would find this helpful!!

Pranav Bhoraskar
  • 115
  • 1
  • 13