i want to say that i use the okhttp caching with Retrofit but cache file not created while i write the right code because i create a sample app where is working done but when i use same code in my project i am not understood why not create cache file.
Here is my code :
private Context context;
private PrefManager prefManager;
private String BEARER = "Bearer ";
private String APP_JSON = "application/json";
private String OUTPUT_ACCEPT = "Accept";
private String AUTHERIZATION = "Authorization";
private int CACHE_SIZE_BYTES = 10 * 1024 * 1024;
private String TAG = OkHttpClientModule.class.getSimpleName();
#Provides
public OkHttpClient okHttpClient(Cache cache, Interceptor interceptor, StethoInterceptor stethoInterceptor, HttpLoggingInterceptor httpLoggingInterceptor) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(interceptor);
builder.cache(cache);
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.writeTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(30, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
builder.addNetworkInterceptor(stethoInterceptor);
builder.interceptors().add(httpLoggingInterceptor);
}
OkHttpClient client = builder.build();
return client;
}
#Provides
public PrefManager getManager(Context context) {
return new PrefManager(context);
}
#Provides
public StethoInterceptor getSteltho() {
return new StethoInterceptor();
}
#Provides
public Cache cache(File cacheFile) {
Cache cache = null;
try {
cache = new Cache(cacheFile, CACHE_SIZE_BYTES);
Log.e("TAG", " cache created " + cache.directory().getPath());
} catch (Exception e) {
e.printStackTrace();
Log.e("TAG", " cache exception " + e.getLocalizedMessage());
}
return cache;
}
#Provides
#RandomUserApplicationScope
public File file(#ApplicationContext Context ctx) {
this.context = ctx;
File file = new File(ctx.getCacheDir(), "httpcache");
return file;
}
#Provides
public Interceptor getIntercepter() {
final String mAuth = "";//Credentials.basic(BaseRequest.AUTH_USERNAME, BaseRequest.AUTH_PASSWORD);
Interceptor headerAuthorizationInterceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
if (!NetworkUtils.isConnected(context)) {
Log.e(TAG, "response from cache ");
Request request = chain.request();
CacheControl cacheControl = new
CacheControl.Builder().maxStale(1,
TimeUnit.DAYS).build();
request = request.newBuilder().cacheControl(cacheControl).build();
String rawJson = chain.proceed(request).body().string();
Log.e(BuildConfig.APPLICATION_ID, String.format("req response cache raw JSON response is: %s", rawJson));
return chain.proceed(request);
} else {
Log.e(TAG, "response from network");
CacheControl cacheControl = new CacheControl.Builder().maxAge(1, TimeUnit.HOURS).build();
prefManager = new PrefManager(context);
String token = prefManager.getPreference(AppConstant.HEADER_TOKEN);
Request.Builder request = chain.request().newBuilder();
request.addHeader(OUTPUT_ACCEPT, APP_JSON);
request.addHeader(AUTHERIZATION, BEARER + token);
request.header(CACHE_CONTROL, cacheControl.toString());
//request.cacheControl(CacheControl.FORCE_CACHE);
Response response = chain.proceed(request.build());
return response;
}
}
};
return headerAuthorizationInterceptor;
}
#Provides
public HttpLoggingInterceptor httpLoggingInterceptor() {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return httpLoggingInterceptor;
}
And i am check cache file in File explorer but showing here
You can create a Context in your MainActivity, like below:
public static Context mContext;
In your onCreate(), you can add:
mContext = getApplicationContext();
Then, in a separate file, example RetrofitCachingInstance:
public class RetrofitCachingInstance {
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control",
String.format(Locale.ENGLISH, "max-age=%d", 60))
.build();
};
private static Retrofit retrofit;
private static final String BASE_URL = "YOUR_JSON_URL";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
OkHttpClient.Builder client = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client.addInterceptor(loggingInterceptor);
client.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR);
client.addInterceptor(provideOfflineCacheInterceptor());
client.cache(getCache(MainActivity.mContext));
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
// using Gson for deserialization in this case
.build();
}
return retrofit;
}
private static Interceptor provideOfflineCacheInterceptor() {
return chain -> {
try {
return chain.proceed(chain.request());
} catch (Exception e) {
CacheControl cacheControl = new CacheControl.Builder()
.onlyIfCached()
.maxStale(2, TimeUnit.DAYS)
// accept cached responses up to 2 days old, else hit network request again
.build();
Request offlineCachingRequest = chain.request().newBuilder()
.removeHeader("Pragma")
.cacheControl(cacheControl)
.build();
return chain.proceed(offlineCachingRequest);
}
};
}
private static Cache getCache(Context context) {
int cacheSize = 10 * 1024 * 1024; // Cache size is only 10 MB maximum
return new Cache(MainActivity.mContext.getCacheDir(), cacheSize);
}
}
This should work. Hope this is helpful.
Related
When i wil check the whole code into activity then its work fine when past into fragment i'm getting this error
public class ServiceGenerator {
private static final String TAG = "ServiceGenerator";
public static final String HEADER_CACHE_CONTROL = "Cache-Control";
public static final String HEADER_PRAGMA = "Pragma";
private static ServiceGenerator instance;
public static ServiceGenerator getInstance(){
if(instance == null){
instance = new ServiceGenerator();
}
return instance;
}
private static final long cacheSize = 5 * 1024 * 1024; // 5 MB
private static Retrofit retrofit(){
return new Retrofit.Builder()
.baseUrl(Config.BASE_URL)
.client(okHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
private static OkHttpClient okHttpClient(){
return new OkHttpClient.Builder()
.cache(cache())
.addInterceptor(httpLoggingInterceptor()) // used if network off OR on
.addNetworkInterceptor(networkInterceptor()) // only used when network is on
.addInterceptor(offlineInterceptor())
.build();
}
private static Cache cache(){
return new Cache(new File(MyApplication.getInstance().getCacheDir(),"someIdentifier"), cacheSize);
}
/**
* This interceptor will be called both if the network is available and if the network is not available
* #return
*/
private static Interceptor offlineInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Log.d(TAG, "offline interceptor: called.");
Request request = chain.request();
// prevent caching when network is on. For that we use the "networkInterceptor"
if (!MyApplication.hasNetwork()) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
/**
* This interceptor will be called ONLY if the network is available
* #return
*/
private static Interceptor networkInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Log.d(TAG, "network interceptor: called.");
Response response = chain.proceed(chain.request());
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(5, TimeUnit.SECONDS)
.build();
return response.newBuilder()
.removeHeader(HEADER_PRAGMA)
.removeHeader(HEADER_CACHE_CONTROL)
.header(HEADER_CACHE_CONTROL, cacheControl.toString())
.build();
}
};
}
private static HttpLoggingInterceptor httpLoggingInterceptor ()
{
HttpLoggingInterceptor httpLoggingInterceptor =
new HttpLoggingInterceptor( new HttpLoggingInterceptor.Logger()
{
#Override
public void log (String message)
{
Log.d(TAG, "log: http log: " + message);
}
} );
httpLoggingInterceptor.setLevel( HttpLoggingInterceptor.Level.BODY);
return httpLoggingInterceptor;
}
public static WebServices getApi(){
return retrofit().create(WebServices.class);
}
}
Locat
java.lang.NullPointerException: Attempt to invoke virtual method
'java.io.File
com.client.bw.aali.com.activities.cache.MyApplication.getCacheDir()'
on a null object reference
at com.client.bw.aali.com.activities.cache.ServiceGenerator.cache(ServiceGenerator.java:61)
at com.client.bw.aali.com.activities.cache.ServiceGenerator.okHttpClient(ServiceGenerator.java:53)
at com.client.bw.aali.com.activities.cache.ServiceGenerator.retrofit(ServiceGenerator.java:46)
at com.client.bw.aali.com.activities.cache.ServiceGenerator.getApi(ServiceGenerator.java:134)
at com.client.bw.aali.com.activities.listView.fragments.ListViewFragment.setAdapter(ListViewFragment.java:141)
at com.client.bw.aali.com.activities.listView.fragments.ListViewFragment.onCreateView(ListViewFragment.java:98)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)
I have a class to handle token refreshes once they expire. The code is below:
public class TokenAuthenticator implements Authenticator {
#Nullable
#Override
public synchronized Request authenticate(#NonNull Route route, #NonNull Response response) throws IOException {
ApiInterface apiInterface = ApiClient.getClient().create(ApiInterface.class);
Call<User> call = apiInterface.refreshTokens(new ClientRequest(Songa.getContext().getString(R.string.client_id),
App.getContext().getString(R.string.client_secret),
App.getContext().getString(R.string.grant_type), getRAGUser().getRefreshToken()));
User ragUser = call.execute().body();
if (ragUser != null) {
Gson gson = new Gson();
String user = gson.toJson(ragUser);
PrefUtils.putString(Constants.USER, user);
long tokenExpiryPeriod = System.currentTimeMillis() + Long.parseLong(ragUser.getExpiryPeriod());
PrefUtils.putLong(Constants.TOKEN_EXPIRY_PERIOD, tokenExpiryPeriod);
return response.request().newBuilder().header("Authorization", "Bearer " + ragUser.getAccessToken()).build();
} else {
if (responseCount(response) >= 3) {
Log.e("TokenAuthenticator", String.valueOf(responseCount(response)));
//we have failed 3 times; log the user out
EventBus.getDefault().post(new LogoutEvent());
return null;
}
}
return null;
}
private int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}
My intention is that once a token expires, the authenticator should retry a maximum of three times before giving up and logging out the user. However, the code below executes each request three times, even with a valid token.
I've always assumed that the Authenticator class only steps in when the token expires but from my logs, I can see that it is called every time a new request is made.
The following is the code from my Retrofit client:
public class RestClient {
private static final String BASE_URL = "https://my.base.url/api/v3/";
private static String token = "Bearer " + getAccessToken();
private static Retrofit retrofit = null;
public RestClient() {
}
public static Retrofit getClient() {
if (retrofit == null) {
TokenAuthenticator tokenAuthenticator = new TokenAuthenticator();
Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(1);
Gson gson = new GsonBuilder()
.setExclusionStrategies(new ExclusionStrategy() {
#Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getDeclaringClass().equals(RealmObject.class);
}
#Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}).create();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.authenticator(tokenAuthenticator)
.addInterceptor(loggingInterceptor)
.addInterceptor(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.addHeader("Authorization", token)
.addHeader("Content-Type", "application/json")
.build();
return chain.proceed(request);
})
.addInterceptor(loggingInterceptor)
.dispatcher(dispatcher)
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.client(okClient)
.build();
}
return retrofit;
}
}
Is there a better way of implementing token authentication with my requirements; 3 retries before logout?
I'm trying to change the baseUrl of an android app dynamically but the url doesn't changed.
I'm taking the reference of David's answer from here,the OkHttp Approach Dagger + Retrofit dynamic URL and Set dynamic base url using Retrofit 2.0 and Dagger 2, but still no luck.
Initially the app point to the urls "https://imd.com/yeddydemo/wpApp/",which is our app base url.
After doing some googling i have written the following code to change the app base url points to https://imd.com/rahudemo/wpApp/ but it doesn't works correctly:
Can anyone please point out where i'm doing wrong.Thanks in Advance:)
Method to change the base url:
public void changeUrlConfiguration(String name){
NetComponent netComponent = DaggerNetComponent.builder()
.apiModule(new ApiModule("https://imd.com/rahudemo/wpApp/"))
.appModule(new AppModule((ImdPoApp)homeActivity.getApplication()))
.storageModule(new StorageModule((ImdPoApp)homeActivity.getApplication()))
.build();
ApiStories service = netComponent.retrofit().create(ApiStories.class);
HostSelectionInterceptor interceptor = netComponent.interceptor();
interceptor.setHost("https://imd.com/rahudemo/wpApp/","8WAtp8nUEOrzSu67t9tGITEo");
}
Interceptor class
public final class HostSelectionInterceptor implements Interceptor {
private volatile String host;
private String authKey;
public void setHost(String host,String authKey) {
this.host = host;
this.authKey=authKey;
new ApiModule(host);
}
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
HttpUrl newUrl = HttpUrl.parse(host);
request = request.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(request);
}
}
ApiModule
#Module
public class ApiModule {
String mBaseUrl;
HostSelectionInterceptor sInterceptor;
public ApiModule(String mBaseUrl) {
this.mBaseUrl = mBaseUrl;
}
#Provides
#Singleton
Cache provideHttpCache(Application application) {/*..*/}
#Provides
#Singleton
Gson provideGson() {/*..*/}
#Provides
#Singleton
OkHttpClient provideOkhttpClient(Cache cache, HostSelectionInterceptor hostSelectionInterceptor) {
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addInterceptor(chain -> {
Request request = chain.request();
Request.Builder builder = request.newBuilder().addHeader("Authkey", "8WAtp8nUEOrzSu67t9tGITEo");
return chain.proceed(builder.build());
});
client.addInterceptor(hostSelectionInterceptor);
client.cache(cache);
return client.build();
}
#Provides
#Singleton
HostSelectionInterceptor provideInterceptor() {
if (sInterceptor == null) {
sInterceptor = new HostSelectionInterceptor();
}
return sInterceptor;
}
#Provides
#Singleton
Retrofit provideRetrofit(OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(mBaseUrl)
.client(okHttpClient)
.build();
}
}
In your method pass the base url want to change to newbaseurl
public void changeUrlConfiguration(String name, String newbaseurl){
NetComponent netComponent = DaggerNetComponent.builder()
.apiModule(new ApiModule(newbaseurl))
.appModule(new
AppModule((ImdPoApp)homeActivity.getApplication()))
.storageModule(new StorageModule((ImdPoApp)homeActivity.getApplication()))
.build();
ApiStories service = netComponent.retrofit().create(A
piStories.class);
HostSelectionInterceptor interceptor = netComponent.interceptor();
interceptor.setHost(newbaseurl,"8WAtp8nUEOrzSu67t9tGITEo");
}
By Changing my interceptor & ChangeUrlConfiguration method as below i can able to change the BaseUrl
Interceptor method
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String host = this.host;
if (host != null) {
HttpUrl newUrl = request.url().newBuilder()
.removePathSegment(0).removePathSegment(0).removePathSegment(0).addPathSegments(host).addPathSegment("wpApp").addEncodedPathSegment("api.php")
.build();
request = request.newBuilder()
.url(newUrl).addHeader("Authkey", "8WAtp8nU")
.build();
} else {
request = request.newBuilder().addHeader("Authkey", "8WAtp8nU")
.build();
}
try {
return chain.proceed(request);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
changeUrlConfiguration
public void changeUrlConfiguration(String constituencyName){
String newbaseurl="https://imdstar.com/rahuldemo/wpApp/";
hostSelectionInterceptor.setHost(newbaseurl,"8WAtp8nUEOrzSu67t9tGITEzIdgr6huIpXqo");
}
I am connecting to webService like bellow :
private CompositeDisposable mCompositeDisposable;
PublicApi publicApi = retrofitApi.getClient("https://xxx.xxx.xxx", context, 1);
mCompositeDisposable.add(publicApi.language("getLanguages")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(language -> responseLanguage(language, resultListener), language -> errorLanguage(language, resultListener)));
And get the result like bellow :
private void responseLanguage(Languages languages, RemoteDataSource.ResultListener<Languages> resultListener) {
}
private void errorLanguage(Throwable error, RemoteDataSource.ResultListener<Languages> resultListener) {
error.printStackTrace();
}
How can I check response origin like bellow link :
Retrofit 2 — Check Response Origin (Network, Cache, or Both)
I need to know the result is from cache or webservice(online) because I am caching the result like bellow :
public class RetrofitApi {
private static PublicApi retrofit = null;
private Context context;
public PublicApi getClient(String url, Context context, Integer value) {
OkHttpClient okHttpClient;
this.context = context;
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
if (value == 1) {
//For get Log see D/OkHttp
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
File httpCacheDirectory = new File(this.context.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
okHttpClient = builder.
addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
.addInterceptor(OFFLINE_INTERCEPTOR)
.addInterceptor(logging)
.cache(cache)
.build();
} else {
okHttpClient = new OkHttpClient.Builder()
.addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
.addInterceptor(OFFLINE_INTERCEPTOR)
.addInterceptor(logging)
.cache(cache)
.build();
}
} else {
okHttpClient = builder.build();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
retrofit = new Retrofit.Builder()
.baseUrl(url)
.client(okHttpClient)
//.client(httpClient.build())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build().create(PublicApi.class);
return retrofit;
}
private Interceptor REWRITE_RESPONSE_INTERCEPTOR = chain -> {
Response originalResponse = chain.proceed(chain.request());
String cacheControl = originalResponse.header("Cache-Control");
if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) {
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + 60)
.build();
} else {
return originalResponse;
}
};
private Interceptor OFFLINE_INTERCEPTOR = chain -> {
Request request = chain.request();
if (!Utils.isNetworkAvailable(context)) {
int maxStale = 60 * 60 * 24 * 2; // tolerate 2-days stale
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return chain.proceed(request);
};
}
You can wrap your expected object at PublicApi interface with Retrofit's Response object, when using RxJava with RxJavaCallAdapaterFactory:
#GET
Response<Languages> language(String param);
Response is a wrapper around a request response that contains various information about the response, this is the same object in your mentioned article, that is returned in non-RxJava enqueue() request when using Call<>.
then in the subscriber you will get an Response<Languages> object and you will be able to check whether it is cached object using response.raw().cacheResponse() / response.raw().networkResponse() as described in the aforementioned tutorial.
I am trying to add basic authentication (username and password) to a Retrofit OkHttp client. This is the code I have so far:
private static Retrofit createMMSATService(String baseUrl, String user, String pass) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
I am using Retrofit 2.2 and this tutorial suggests using AuthenticationInterceptor, but this class is not available.
Where is the correct place to add the credentials? Do I have to add them to my interceptor, client or Retrofit object? And how do I do that?
Find the Solution
1.Write a Interceptor class
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
2.Finally, add the interceptor to an OkHttp client
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createService(serviceClass, authToken);
}
return createService(serviceClass, null);
}
public static <S> S createService(
Class<S> serviceClass, final String authToken) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor =
new AuthenticationInterceptor(authToken);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
}
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
AuthenticationInterceptor.java
public class AuthenticationInterceptor implements Interceptor {
private String authToken;
public AuthenticationInterceptor(String token) {
this.authToken = token;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization", authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
Usage
Retrofit 2
Interface
public interface LoginService {
#POST("/login")
Call<User> basicLogin();
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
call.enqueue(new Callback<User >() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// user object available
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Retrofit 1.9
Interface
public interface LoginService {
#POST("/login")
void basicLogin(Callback<User> cb);
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
loginService.basicLogin(new Callback<User>() {
#Override
public void success(User user, Response response) {
// user object available
}
#Override
public void failure(RetrofitError error) {
// handle errors, too
}
});
More information see here.
add header interceptor
public class HeaderInterceptor implements Interceptor {
private PreferencesRepository mPrefs;
private String mAuth;
public HeaderInterceptor(PreferencesRepository p) {
mPrefs = p;
}
#Override
public Response intercept(Chain chain) throws IOException {
mAuth = (mPrefs.getAuthToken() != null)?mPrefs.getAuthToken():"";
Request r = chain.request()
.newBuilder()
.addHeader("Accept", "application/json")
// authorization token here
.addHeader("Authorization", "Bearer" + mAuth)
.build();
return chain.proceed(r);
}
}
add cacheinterceptor (optional)
public class CacheInterceptor implements Interceptor {
Context mContext;
public CacheInterceptor(Context context) {
this.mContext = context;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.method().equals("GET")) {
if (DeviceUtils.isConnected(mContext)) {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "only-if-cached")
.build();
} else {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "public, max-stale=2419200")
.build();
}
}
Response originalResponse = chain.proceed(request);
return originalResponse.newBuilder()
.header(Constant.CACHE_CONTROL, "max-age=600")
.build();
}
}
implement it
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(mContext.getCacheDir(), "http"), SIZE_OF_CACHE);
new OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(new HeaderInterceptor(u))
.cache(cache)
.addNetworkInterceptor(new CacheInterceptor(mContext))
.connectTimeout(Constant.CONNECTTIMEOUT, TimeUnit.SECONDS)
.readTimeout(Constant.READTIMEOUT, TimeUnit.SECONDS)
.writeTimeout(Constant.WRITETIMEOUT, TimeUnit.SECONDS)
.build();
Of course using auth interceptor is correct way (as explained in other answers). Although, if you need basic authentication only for single call, then auth header can be added directly in Retrofit request:
import okhttp3.Credentials
// Create credentials
val login = "some login"
val password = "some password"
// Below code will create correct Base64 encoded Basic Auth credentials
val credentials = Credentials.basic(login, password)
// Then in your Retrofit API interface
interface MyApi {
#POST("get_user")
fun getUser(#Header("Authorization") credentials: String): ResponseBody
}