Is there a way to set a custom cookie on retrofit requests?
Either by using the RequestInterceptor or any other means?
Through the retrofit.RequestInterceptor:
#Override
public void intercept(RequestFacade request) {
request.addHeader("Cookie", "cookiename=cookievalue");
}
You can set a custom RequestInterceptor as follows:
String cookieKey = ...
String cookieValue = ...
RestAdapter adapter = new RestAdapter.Builder()
.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// assuming `cookieKey` and `cookieValue` are not null
request.addHeader("Cookie", cookieKey + "=" + cookieValue);
}
})
.setServer("http://...")
.build();
YourService service = adapter.create(YourService.class);
And to read any cookies set by the server, attach a custom cookie manager like this:
OkHttpClient client = new OkHttpClient();
CustomCookieManager manager = new CustomCookieManager();
client.setCookieHandler(manager);
RestAdapter adapter = new RestAdapter.Builder()
.setClient(new OkClient(client))
...
.build();
where CustomCookieManager could look like this:
public class CustomCookieManager extends CookieManager {
// The cookie key we're interested in.
private final String SESSION_KEY = "session-key";
/**
* Creates a new instance of this cookie manager accepting all cookies.
*/
public CustomCookieManager() {
super.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
}
#Override
public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException {
super.put(uri, responseHeaders);
if (responseHeaders == null || responseHeaders.get(Constants.SET_COOKIE_KEY) == null) {
// No cookies in this response, simply return from this method.
return;
}
// Yes, we've found cookies, inspect them for the key we're looking for.
for (String possibleSessionCookieValues : responseHeaders.get(Constants.SET_COOKIE_KEY)) {
if (possibleSessionCookieValues != null) {
for (String possibleSessionCookie : possibleSessionCookieValues.split(";")) {
if (possibleSessionCookie.startsWith(SESSION_KEY) && possibleSessionCookie.contains("=")) {
// We can safely get the index 1 of the array: we know it contains
// a '=' meaning it has at least 2 values after splitting.
String session = possibleSessionCookie.split("=")[1];
// store `session` somewhere
return;
}
}
}
}
}
}
This is how it's done for retrofit2
Gradle:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
The code:
static final class CookieInterceptor implements Interceptor {
private volatile String cookie;
public void setSessionCookie(String cookie) {
this.cookie = cookie;
}
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (this.cookie != null) {
request = request.newBuilder()
.header("Cookie", this.cookie)
.build();
}
return chain.proceed(request);
}
}
class Creator {
public static MyApi newApi() {
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.create();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new CookieInterceptor())
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(MyApi.URL)
.callFactory(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return retrofit.create(MyApi.class);
}
}
Another way to set a cookie is this way:
#Headers("Cookie: cookiename=cookievalue")
#GET("widget/list")
Call<List<Widget>> widgetList();
And here is a dynamic way:
#GET("user")
Call<User> getUser(#Header("Cookie") String cookie)
I've only just started with RetroFit, but the way it handles cookies does not seem to be on par with the rest of the library. I wound up doing something like this:
// Set up system-wide CookieHandler to capture all cookies sent from server.
final CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);
// Set up interceptor to include cookie value in the header.
RequestInterceptor interceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
for (HttpCookie cookie : cookieManager.getCookieStore().getCookies()) {
// Set up expiration in format desired by cookies
// (arbitrarily one hour from now).
Date expiration = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
String expires = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz")
.format(expiration);
String cookieValue = cookie.getName() + "=" + cookie.getValue() + "; " +
"path=" + cookie.getPath() + "; " +
"domain=" + cookie.getDomain() + ";" +
"expires=" + expires;
request.addHeader("Cookie", cookieValue);
}
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setRequestInterceptor(interceptor) // Set the interceptor
.build();
GitHubService service = restAdapter.create(GitHubService.class);
Related
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.
I am trying to use an Interceptor to add a header when using Retrofit. I think I have created my Interceptor in the right way but I don't know what should I do to call it and connect it with my GET Retrofit method.
This is my Interceptor:
public class HeaderInterceptor
implements Interceptor {
#Override
public Response intercept(Chain chain)
throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader(Constants.VersionHeader.NAME, Constants.VersionHeader.VALUE)
.addHeader("Authorization", "Bearer " + token)
.addHeader("Origin","MY URL")
.build();
Response response = chain.proceed(request);
return response;
}
}
And this is my interface:
public interface CategoryService {
#GET("/v3/projects/{projectId}/categories/")
Call<ArrayList<Category2>> getProjectCategories(#Path("projectId") String projectId);
}
I also have this client which I don't know if I should use it anymore considering that I am using an Interceptor:
public class CategoryClient {
public static final String BASE_URL = "MY URL";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
So I have this GET method getProjectCategories, where I pass the projectID and it returns the contents. What I want to know is how can I call the method using the Interceptor and be able to get the results from the request.
I was able to fix my problem by creating a method called SendNetworkRequest sending the projectId as a parameter, and inside this class I created my OkHttpClient, my Interceptor and my retrofit builder to handle everything that i needed.
private void SendNetworkRequest(String projectID) {
OkHttpClient.Builder okhttpBuilder = new OkHttpClient.Builder();
okhttpBuilder.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request.Builder newRequest = request.newBuilder().header("Authorization", "Bearer " + token);
return chain.proceed(newRequest.build());
}
});
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("MY URL")
.client(okhttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
CategoryService category = retrofit.create(CategoryService.class);
Call<ArrayList<Category2>> call = category.getProjectCategories(projectID, token);
call.enqueue(new Callback<ArrayList<Category2>>() {
#Override
public void onResponse(Call<ArrayList<Category2>> call, Response<ArrayList<Category2>> response) {
listCategories = response.body();
listCategories.remove(response.body().size() - 1);
if (response.body().size() > 0){
add_category_layout.setVisibility(View.VISIBLE);
layout_bar.setVisibility(View.VISIBLE);
message_body.setVisibility(View.INVISIBLE);
message_title.setVisibility(View.INVISIBLE);
edit_image.setVisibility(View.INVISIBLE);
adapter2 = new CategoryAdapter2(getApplicationContext(), listCategories);
recyclerView.setAdapter(adapter2);
recyclerView.setVisibility(View.VISIBLE);
}
}
#Override
public void onFailure(Call<ArrayList<Category2>> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
I was trying to develop a simple POST API call in Android so I made one thinking that the request content-type was a json. Turns out it is expecting a multipart/form-data format and I'm struggling changing my function.
I'd like to know if there is any library to manage this. If not, I'd like to know how to pass my arguments in a multipart format.
#Override
public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {
RequestQueue queue = mRequestQueue;
poiId = "1";
description = "Test post";
final HashMap<String, Object> params = new HashMap<>();
params.put("poiID", poiId);
params.put("description", description);
System.out.println("POI ID " + description);
params.put("tags", tags);
params.put("resource", resource);
RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.POST,
API_POST_URL,
new JSONObject(params),
future, future) {
#Override
public HashMap<String, String> getHeaders() {
System.out.println(PostRepositoryImpl.this.getHeaders());
return PostRepositoryImpl.this.getHeaders();
}
};
queue.add(request);
try {
future.get(TIMEOUT, TIMEOUT_TIME_UNIT); // this will block
}catch (InterruptedException | ExecutionException | TimeoutException e){
e.printStackTrace();
return false;
}
return true;
}
I hardcoded some of the values because I wanted to test with poiID and description
So I want to send these kind of values in my multipart/form-date:
- poiID : String
- description : String
- resource : image
- tags
Is there any way to do this similar to the way I made my json request?
Kind regards
EDIT:
#Override
public boolean post(String poiId, String description, ArrayList<String> tags, Resource resource) {
RequestQueue queue = mRequestQueue;
StringRequest postRequest = new StringRequest(Request.Method.POST, API_POST_URL,
new Response.Listener<String>()
{
#Override
public void onResponse(String response) {
// response
Log.d("Response", response);
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error) {
// error
Log.d("Error.Response", "400");
}
}
) {
#Override
protected HashMap<String, String> getParams()
{
HashMap<String, String> params = new HashMap<String, String>();
params.put("poiID", "Alif");
params.put("description", "http://itsalif.info");
return params;
}
};
queue.add(postRequest);
return true;
}
How do I add the headers?
If it isn't JSON, simply use a StringRequest.
Not sure how to use Future with Volley, so change that accordingly
Then, params are added in an overridden method
Request request = new StringRequest(
Request.Method.POST,
API_POST_URL,
future, future) {
#Override
public HashMap<String, String> getHeaders() {
HashMap<String, String> headers = PostRepositoryImpl.this.getHeaders();
System.out.println(headers);
return headers;
}
#Override
public HashMap<String, String> getParams() {
// TODO: Put your params here
}
};
And for Multipart, see Working POST Multipart Request with Volley and without HttpEntity
Using Retrofit 2, you could do this:
//Lets Suppose this you have this postman or you want to make some request like this
//ServiceCreator (In my case i am using oauth2 so have AccessToken). This is a working and production sample, so you have to make your own changes, but i attach to example all components.
public class APIRestClient {
public static String API_BASE_URL = "http://186.151.238.14/";
private static OkHttpClient.Builder httpClient;
private static Retrofit.Builder builder;
public static Retrofit retrofit;
private static Activity mActivity;
private static AccessToken mToken;
/**
* setupBase URL
* #param _baseActivity
*/
public static void setupBaseUrl(Context _baseActivity){
String tmpBase = SharedPreferenceUtilities.getDomain(_baseActivity);
if (tmpBase != null && tmpBase.length() > 0){
if (tmpBase != API_BASE_URL) {
APIRestClient.API_BASE_URL = tmpBase;
}
}
}
/**
* auth2 Authorization Bearer...token create Service instance
* #param _serviceClass
* #param _baseActivity
* #param <S>
* #return
*/
public static <S> S createService(Class<S> _serviceClass, final Activity _baseActivity) {
AccessToken accessToken = TaskManagementApplication.getInstance().getAccessToken();
if (_baseActivity != null) {
setupBaseUrl(_baseActivity);
}
httpClient = new OkHttpClient.Builder();
httpClient.connectTimeout(30000, TimeUnit.SECONDS)
.readTimeout(30000,TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
httpClient.addNetworkInterceptor(new StethoInterceptor());
}
builder = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
if (accessToken == null){
accessToken = new AccessToken();
accessToken.setAccessToken("");
accessToken.setTokenType("Bearer");
accessToken.setScope("");
accessToken.setRefreshToken("");
accessToken.setClientID("");
accessToken.setClientSecret("");
accessToken.setExpiry(0);
}
if(accessToken != null) {
mActivity = _baseActivity;
mToken = accessToken;
final AccessToken token = accessToken;
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Accept", "application/json")
.header("Content-type", "application/json")
.header("Authorization",
token.getTokenType() + " " + token.getAccessToken())
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
httpClient.authenticator(new Authenticator() {
#Override
public Request authenticate(Route route, Response response) throws IOException {
if(responseCount(response) >= 2) {
// If both the original call and the call with refreshed token failed,
// it will probably keep failing, so don't try again.
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
// We need a new client, since we don't want to make another call using our client with access token
OAuthInterface tokenClient = createAuthService(OAuthInterface.class,mActivity);
Call<AccessToken> call = tokenClient.getRefreshAccessToken(
Grant_type.REFRESH_TOKEN.toString(),
token.getRefreshToken(),
StringUtilities.API_OAUTH_CLIENTID(_baseActivity),
StringUtilities.API_OAUTH_SECRET(_baseActivity),
"");
try {
retrofit2.Response<AccessToken> tokenResponse = call.execute();
if(tokenResponse.code() == 200) {
AccessToken newToken = tokenResponse.body();
mToken = newToken;
SharedPreferenceUtilities.setAccessToken(mActivity,mToken);
TaskManagementApplication.getInstance().setupToken(mToken);
return response.request().newBuilder()
.header("Authorization", newToken.getTokenType() + " " + newToken.getAccessToken())
.build();
} else {
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
} catch(IOException e) {
LoginUtilities.initLogin(_baseActivity,LoginActivity.LOGININTENTRESULT,null);
return null;
}
}
});
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(_serviceClass);
}
/**
* not auth create Service instance
* #param _serviceClass
* #param _context
* #param <S>
* #return
*/
private static int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}
//ApiInterface
public interface StudentInterface
{
public static final String ENVIARTAREAAPI = "api/estudiante/entregatarea";
#Multipart
#POST(ENVIARTAREAAPI)
Call<TareaCalificacion> entregatarea(#Part("Descripcion") RequestBody Descripcion,
#Part("IdTarea") RequestBody IdTarea,
#Part("IdEstudiante") RequestBody IdEstudiante);
}
//ApiCall (in your activity, fragment or wetheaver) this should be used when you execute your api call
RequestBody descripcionRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
mensageEntregaTmp);
RequestBody idTareaRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
String.valueOf(mTarea.getIdTarea()));
RequestBody idEstudianteRequestBody = RequestBody.create(
okhttp3.MediaType.parse("text/plain; charset=utf-8"),
String.valueOf(currUser.getPerfil().getSisId()));
StudentInterface studentInterface = APIRestClient.createService(StudentInterface.class,DetalleTareaActivity.this);
Call<TareaCalificacion> call = studentInterface.entregatarea(
descripcionRequestBody,
idTareaRequestBody,
idEstudianteRequestBody);
call.enqueue(new Callback<TareaCalificacion>() {
#Override
public void onResponse(Call<TareaCalificacion> call, Response<TareaCalificacion> response) {
int statusCode = response.code();
if(statusCode == 200) {
Toast.makeText(getApplicationContext, "Success Request", Toast.LENGTH_SHORT).show();
} else {
//todo some kind of error
}
}
#Override
public void onFailure(Call<TareaCalificacion> call, Throwable t) {
//todo some kind of error
}
});
I have used this to upload photos, so i have to use this sample to do that, thats the reason i did not use Content Type application/json.
Hope that helps how to do.
Some class (pojo) like TareaCalificacion (that is what i expect from the response are just class, that i use with GSON), so TareaCalificacion.java is like:
public class TareaCalificacion {
#SerializedName("sisId")
#Expose
private long sisId;
#SerializedName("sisDescripcion")
#Expose
private String sisDescripcion;
#SerializedName("sisEstado")
#Expose
private String sisEstado;
#SerializedName("sis")
#Expose
private int sis;
#SerializedName("sisUsuario")
#Expose
private String sisUsuario;
#SerializedName("CalificacionObtenida")
#Expose
private double CalificacionObtenida;
#SerializedName("IdEstudiante")
#Expose
private long IdEstudiante;
#SerializedName("IdTarea")
#Expose
private long IdTarea;
#SerializedName("Adjunto")
#Expose
private int Adjunto;
#SerializedName("ObservacionCalificacion")
#Expose
private String ObservacionCalificacion;
#SerializedName("IdCatedratico")
#Expose
private long IdCatedratico;
public TareaCalificacion() {
}
}
Attach some links that could help you if you have doubts:
Retrofit Documentation
Another example using this
Lets me know if that works or if is not clear how to do
Regards.
I'm making service that makes user able to login in LoginActivity, and if login is successful, user can post something in PostActivity. I'm using Restful api.
I found good sharedpreference example on github : https://gist.github.com/nikhiljha/52d45ca69a8415c6990d2a63f61184ff
and
https://gist.github.com/tsuharesu/cbfd8f02d46498b01f1b
AddCookiesInterceptor.java
public class AddCookiesInterceptor implements Interceptor {
public static final String PREF_COOKIES = "PREF_COOKIES";
private Context context;
public AddCookiesInterceptor(Context context) {
this.context = context;
}
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
HashSet<String> preferences = (HashSet<String>) PreferenceManager.getDefaultSharedPreferences(context).getStringSet(PREF_COOKIES, new HashSet<String>());
for (String cookie : preferences) {
builder.addHeader("Cookie", cookie);
}
return chain.proceed(builder.build());
}
}
RecievedCookiesInterceptor.java
public class ReceivedCookiesInterceptor implements Interceptor {
private Context context;
public ReceivedCookiesInterceptor(Context context) {
this.context = context;
}
#Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
HashSet<String> cookies = (HashSet<String>) PreferenceManager.getDefaultSharedPreferences(context).getStringSet("PREF_COOKIES", new HashSet<String>());
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
SharedPreferences.Editor memes = PreferenceManager.getDefaultSharedPreferences(context).edit();
memes.putStringSet("PREF_COOKIES", cookies).apply();
memes.commit();
}
return originalResponse;
}
}
I used this code very well on my LoginActivity like this,
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(new AddCookiesInterceptor(getApplicationContext()));
builder.interceptors().add(new RecievedCookiesInterceptor(getApplicationContext()));
client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(LoginApiService.Login_API_URL)
.build();
loginApiService = retrofit.create(LoginApiService.class);
Call<ResponseBody> getkey = loginApiService.getkey(loginData);
getkey.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.code() == 200) {
startActivity(new Intent(LoginActivity.this, PostActivity.class));
}
}
But in PostActivity, (it's from if (response.code() == 200) startActivity)
I used this like
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(new AddCookiesInterceptor(getApplicationContext()));
#just used AddCookiesInterceptor, Not RecievedCookiesInterceptor
client = builder.build();
Retrofit retrofit = new Retrofit.Builder()
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(PostApiService.Post_API_URL)
.build();
PostApiService = retrofit.create(PostApiService.class);
It give me HTTP/1.1 401 error, I found it means there is problem in Headers.
I write PostApiService like this
public interface PostApiService {
#POST("posts/")
Call<ResponseBody> gettest(#Body TextData textData);}
My question :
I want Header like
key : Authorization //
value : Token e0af91707f0434a1a2a7581dd3f4f483bdd717
Where do i modify?
I know too much codes bothers you maybe, so I have to say i'm very sorry.
I'm trying to implement the Reddit oAuth2 (every app that utilizes Reddit content has to have this implemented) in Android based 'userless' application and I'm following the guidelines.
I registered an app and get the respective client_id.
I'm following this for API guidelines and this for Retrofit in order to properly write the Android code.
Hence, I've coded two approaches to the issue and it seems that neither works. The call in the appropriate Fragment is the same for the two options and it goes as follows:
public void oAuth(){
String bodyString = "grant_type=" + "https://oauth.reddit.com/grants/installed_client"
+ "&device_id=" + UUID.randomUUID().toString();
TypedInput requestBody = new TypedByteArray("application/x-www-form-urlencoded", bodyString.getBytes(Charset.forName("UTF-8")));
RedditAPI.sRedditAuth().redditAuth(requestBody, new Callback<TokenResponse>() {
#Override
public void success(TokenResponse tokenResponse, Response response) {
Log.d("OATH_TAG", "oAuth() | YAY! :)");
}
#Override
public void failure(RetrofitError error) {
Log.d("OATH_TAG", "oAuth() | NOOOOOoooooo.... :(");
}
});
}
OPTION 1:
the Retrofit interface:
public interface RedditAuthInterface {
#POST(Urlz.REDDIT_OATH2_PATH)
void redditAuth(#Body TypedInput body, Callback<TokenResponse> result);
}
//the adapter
public static RedditAuthInterface sRedditAuth() {
if (sRedditAuthInterface == null) {
RestAdapter restAdapter = new RestAdapter
.Builder()
.setClient(getAuthClient())
.setEndpoint(Urlz.BASE_REDDIT_URL)
.build();
sRedditAuthInterface = restAdapter.create(RedditAuthInterface.class);
}
return sRedditAuthInterface;
}
/* support methods */
private static OkClient getAuthClient() {
final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(Static.READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(Static.CONNECT_TIMEOUT, TimeUnit.SECONDS);
/*okHttpClient.setAuthenticator(new Authenticator() {
#Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
String credential = Credentials.basic(BldCnfg.REDDIT_CLIENT_ID, BldCnfg.REDDIT_PASS);
return response.request().newBuilder().header("Authorization", credential).build();
}
#Override
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
return null;
}
});*/
okHttpClient.networkInterceptors().add(OAUTH_INTERCEPTOR);
return new OkClient(okHttpClient);
}
private static final Interceptor OAUTH_INTERCEPTOR = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
String credentials = BldCnfg.REDDIT_CLIENT_ID + ":" + BldCnfg.REDDIT_PASS; // REDDIT_PASS = "" as by API guides
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
originalResponse.header("Authorization", string);
originalResponse.header("Accept", "application/json");
return originalResponse;
}
};
result:
RetrofitError: 401 Unauthorized
OPTION 2:
the Retrofit interface:
public interface RedditAuthInterface {
#POST(Urlz.REDDIT_OATH2_PATH)
void redditAuth(#Body TypedInput body, Callback<TokenResponse> result);
}
//the adapter
public static RedditAuthInterface sRedditAuth() {
if (sRedditAuthInterface == null) {
RestAdapter restAdapter = new RestAdapter
.Builder()
.setClient(getConfuguredClient())
.setRequestInterceptor(getRequestInerceptorPass())
.setEndpoint(Urlz.BASE_REDDIT_URL)
.build();
sRedditAuthInterface = restAdapter.create(RedditAuthInterface.class);
}
return sRedditAuthInterface;
}
/* support methods */
public static RequestInterceptor getRequestInerceptorPass() {
RequestInterceptor rqInter = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
String credentials = BldCnfg.REDDIT_CLIENT_ID + ":" + BldCnfg.REDDIT_PASS; // REDDIT_PASS = "" as by API guides
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", string);
request.addHeader("Accept", "application/json");
}
};
return rqInter;
}
private static OkClient getConfuguredClient() {
final OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(Static.READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(Static.CONNECT_TIMEOUT, TimeUnit.SECONDS);
return new OkClient(okHttpClient);
}
result:
It seems that I'm getting empty response (I only get "*" for scope). The successful response looks like this:
and header like this:
Do you have any ideas what am I doing wrong?
Has anybody done this?
The official Reddit github wiki lacks Android examples (has in almost every other language, though).
I was going through the same problem before and make this library to handel OAuth2 in Android. and the library is an extension for Retrofit that simplifies the process of authenticating against an OAuth 2 provider.
Based on your image with the "empty" response, showing that you got * back as a scope, I suspect that your definition for the access token response is using camel case instead of snake case, so the JSON is not getting loaded properly into the Java object.