In my Android app, each activity is filled with data from an xml file which is somewhere on the web. The website providing these files has a login mechanism, that works with cookies.
I know how to make a HTTP Request to the login page and receive a cookie. What I don't know is, how I can store it to re-use it in both other activities AND when the app is started the next time. The cookie is valid for a year, so the user of my app should log in once and then never again for a whole year.
How do I do that? I googled a lot, but either I used the wrong keywords or there are no simple solutions on the internet. I hope somebody here can help me.
Best regards and thanks in advance, Jan Oliver
Use a CookieSyncManager to store your cookie value. It can persist across application starts.
Beware of using CookieSyncManager inside of WebViewClient#shouldInterceptRequest on KitKat. It will deadlock.
EDIT
CookieSyncManager was deprecated in API 21:
This class was deprecated in API level 21. The WebView now
automatically syncs cookies as necessary. You no longer need to create
or use the CookieSyncManager. To manually force a sync you can use the
CookieManager method flush() which is a synchronous replacement for
sync().
It looks like Android is using the default in memory implementation so you will need to create your own persistent cookie store.
This Java Tutorial outlines creating your own persistent store taking advantage of the default implementation.
http://download.oracle.com/javase/tutorial/networking/cookies/custom.html
The sample has two todo's for storage (read/write) For storage I would just use SharedPreferences to store just the session cookie that you need and not persist any others.
The sample uses a shutdown hook which is not what you want in Android. In place of run() and the hook I would just have a new public method persist() that saves what you want, though that requires that you persist() the store by hand.
Given that you only have one or two cookies that matter you could save them in the add(...)
After you make your http call, you can grab the cookies like this
List<Cookie> cookies = httpclient.getCookieStore().getCookies();
if (cookies.isEmpty()) {
Log.d(TAG,"no cookies received");
} else {
for (int i = 0; i < cookies.size(); i++) {
if(cookies.get(i).getName().contentEquals("PHPSESSID")) {
PHPSESSID = cookies.get(i).getValue();
}
}
}
To send them back:
nameValuePairs.add(new BasicNameValuePair("PHPSESSID",phpsessid));
httppost.setEntity(new UrlEncodedFormEntity(aList));
aList is all your nameValuePairs
LoopJ has a built in persistent cookie store that can be used with or without the loopj framework
https://github.com/loopj/android-async-http/blob/master/library/src/main/java/com/loopj/android/http/PersistentCookieStore.java
I wrote a simple class named CookieHelper and I've provided an example of how to use this class to help all users that facing the same problem :
https://github.com/augustopicciani/HttpClient-save-cookies-to-file
Related
I am working on a android web application and based on if a secure cookie exists I want to do something. Unfortunately when I use the following line of code I only get a list of unsecure cookies.
String cookies = cookieManager.getCookie(siteName)
Does anyone know how I can get a list of all secure cookies for a specific domain?
You can retrieve secure cookies by using a url that starts with "https://".
String cookies = cookieManager.getCookie("https://example.com");
Returns all cookies (including secure only ones). Logic for getting cookies can be read at: https://github.com/adobe/chromium/blob/master/net/cookies/cookie_monster.cc#L1780 .
To resolve the issue I added the following before I created the webView
CookieManager.setAcceptFileSchemeCookies(true);
see CookieManager.setAcceptFileSchemeCookies(boolean accept)
I am using Spring for Android in a project and I need to manage the cookie store/manager. I am able to add cookies to any request by using an implementation of ClientHttpRequestInterceptor, but I would like to remove some of these when sending a request.
To be more specific, the problem I am facing is that, for Froyo, the implementation specific in Spring (with DefaultHttpClient) adds automatically to headers the cookies from CookieStore - that even if I am setting explicitly the headers. But I would like to manage these cookies myself (either remove some of them, or update their values). While for Gingerbread above (Spring implementation is done with HttpURLConnection) the cookies are added only if I am doing it myself - however I am not that sure as I don't see Spring setting any CookieHandler, but the bottom line is that I don't see them when performing a request or I can see them updated. So the issue is more specific to Froyo.
The work-around is to reset the connection factory; something like:
protected void resetCookieStoreForTemplate(RestTemplate template) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.FROYO) {
template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
}
}
Underneath, that seems to recreate the DefaultHttpClient and will use a new CookieStore. But that seems to me a bit ugly.
To wrap up, my question would be: does Spring for Android provide some method to expose some API for Cookie management? Just the way RestTemplate exposes some abstractions for connectivity, connection factory, message converters and so on, I would be very happy to have some abstraction for cookie management.
I've not used Spring myself but from what I've read about it, it follows the official advice and switches HTTP clients based on API version (which is quite clever, if seriously over-engineered for my liking). When using HTTPUrlConnection, as you mentioned, Spring probably doesn't change the CookieHandler. You should be seeing in-memory cookie handling, so everything should work for requests in the same app run but the cookies would be wiped when you close the app. Can you confirm this is what you're seeing?
If so, all you have to do is create a new CookieManager instance, passing it a custom CookieStore and null for the CookiePolicy to use the default.
It's unfortunate that a persistent store isn't built-in but it's not particularly difficult to write one either.
Edit: See here for a CookieStore that uses SharedPreferences (haven't tested it myself).
The ClientHttpRequestInterceptor class is a good approach when you need to pass common headers for all requests such as setting up content type, authorization etc. As far as I understood you want to pass some cookie values for specific request.
You could also achieve this via HttpEntity and HttpHeaders class.
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "name=" + value);
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity response = restTemplate.exchange(
"http://server/service?...",
HttpMethod.GET,
requestEntity,
Response.class);
Spring rest template does not provide any off the self solution for managing cookies. The class CookieHandler is provided by Apache not part of spring. Rest template is just a basic solution for managing request response with compare to spring core.
i have login to a site through WebView. then i have get cookie which is set by the webview at login time. then i have tried to set the cookie later. please see my code:
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
Log.e("checkPost 1", cookie);
cookieManager.setCookie("https://************", cookie);
Log.e("checkPost 2", cookieManager.getCookie("https://*************"));
CookieSyncManager.getInstance().sync();
Log.e("checkPost 3", cookieManager.getCookie("https://*************"));
in checkPost 1 printed cookie shows that it is fine. but in checkPost 2 and after sync() it by CookieSyncManager.getInstance().sync(); statement, the checkPost 3 shows that most of the cookie is vanished. what is the problem ? i need to set the cookie. but i could not find a way spending about 2 days.
Edit:
in android documentation it says that:
public void setCookie (String url, String value)
Sets a cookie for the given URL. Any existing cookie with the same
host, path and name will be replaced with the new cookie. The cookie
being set must not have expired and must not be a session cookie,
otherwise it will be ignored.
is there any way to force CookieManager set session cookie via setCookie() ?
i think the problem is, may be i am trying to set session cookie
i don't know there is any answer or not for my question. but for my purpose i have use another way to solve my problem. it's a long process, but it works. i have given up the idea to save session cookie in CookieManager (which is not possible by the document of Android Developer site). So, what i have done is: i have converted the session cookie in string and save them in memory. for later use i just take the string from memory and convert it back to session cookie.
Edit:
(For negative voters) I have told in my answer that the process is too long, like 4-5 classes. and this project was my first project in android so the codes are too messy. all the class is full of too much code. so it is impossible to post it here. i have told the process i have used. so why negative vote?
i have converted the session in my own way and build the string to session in reverse way.
if there is any way i would post the answer. it take me about 15~20 days to build the classes and algorithms. so why not you do some Google and find a better way, or just simply build your own algorithm and process like mine. i have told the key part here, you just need to find a way to implement it into code. Thanks
I am trying to pull HTML data out of a WebView. I've seen this done a thousand times and I've even gotten it to work myself. However, my new project leads to an interesting situation: I need to login to a site through a WebView and then pull the HTML. Obviously, the Socket method doesn't work, because in order for a webpage to be returned you need the cookie for authentication. I've also tried the JavascriptInterface trick, but that didn't work either. I'm thinking the best way to achieve this is to use HttpGet with CookieManager? Does anyone know how I can get raw HTML code from a WebView with an auth cookie? Thanks!
EDIT: I did some JS injection and didn't see any cookies... so it might not be a cookie issue? But the links that you get redirected to are generic, like mainPage?a=1 and infoPage. You cannot simply copy/paste the links into another browser you have to be logged in to view these links. For those of you who are web experts, you may know an easy solution.
WebView isn't really meant for getting HTML for programmatic use, the idea is that it's just a direct window to a URL for user interaction.
To get what you want, you can use a java.net.HttpURLConnection with a CookieManager, it's worked fine for me on Android and it's suggested in the Android SDK docs:
// in an activity's onCreate:
cookieManager = new CookieManager();
CookieHandler.setDefault(cookieManager);
// later on
void getAPage(URL url) {
HttpURLConnection huc = (HttpURLConnection) url.openConnection();
System.out.println("hello from huc, response code is: " + huc.getResponseCode());
// huc.getInputStream() gives you the content.
}
The CookieManager will persist all cookies through the lifetime of the application without you having to do anything extra. You can make posts with HttpURLConnection too.
I am new to android. I am creating an application in which user authentication is needed, but to authorize application user needs to login first. After that the data can be received. I just wanna know is there any procedure to login to a remote website if there is no login api available for that.
i am waiting for the reply.
Thanks,
Arun
May be you can talk to your website with a REST interface ? I dont know. but may be you can try to use kind of HttpClient objects to dialog with the website. You can use HttpGet to make a request via the GET_METHOD. There are other method to use. Well, if you seach a bit on the web about these objects/method you should see some examples. Hope its help you.
Use HTTPClient to do this, it gives you access to cookies and caching mechanisms, so it's all you need to implement this.