Android Share cookie with Webview and Volley request - android

I have searched through a lot of answers and implemented one which helped me with maintaining cookies in volley request.
Code which helped me is following
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
That code has helped me maintain same session with all volley request.
Right after this code I open a webview in onCreate method. Webview has different session and not shared with volley request.
How can I make sure that both has same session.
Following is my onCreate method
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webview);
/* Dialog view */
LinearLayout linearLayoutProgressBar = findViewById(R.id.linearLayoutProgressBar);
// Creates instance of the manager.
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setSaveFormData(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
WebViewClientImpl webViewClient = new WebViewClientImpl(this, linearLayoutProgressBar);
webView.setWebViewClient(webViewClient);
webAppInterface = new WebAppInterface(this, webView);
webView.addJavascriptInterface(webAppInterface, "Android");
webView.loadUrl(AppConstants.mobileUrl);
//GetLocation function fetches the location and sends it to server.
//So first webview is opened and then data is sent to server.
getLocation();
}
Thank you

Another solution is to use CookieManager. The issue is that there are many CoockieManager depending on the context used. With Volley it is java.net.CookieManager and with WebView it is android.webkit.CookieManager. Both are not compatible with each other.
The solution I found here is to create your own CookieManager extended from java.net.CookieManager. The goal is to send the request to the android.webkit.CookieManagerin the same time. Like this, both are synchronized.
Juste create the following class as is :
public class WebkitCookieManagerProxy extends CookieManager
{
private android.webkit.CookieManager webkitCookieManager;
public WebkitCookieManagerProxy()
{
this(null, null);
}
public WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy)
{
super(null, cookiePolicy);
this.webkitCookieManager = android.webkit.CookieManager.getInstance();
}
#Override
public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException
{
// make sure our args are valid
if ((uri == null) || (responseHeaders == null)) return;
// save our url once
String url = uri.toString();
// go over the headers
for (String headerKey : responseHeaders.keySet())
{
// ignore headers which aren't cookie related
if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;
// process each of the headers
for (String headerValue : responseHeaders.get(headerKey))
{
this.webkitCookieManager.setCookie(url, headerValue);
}
}
}
#Override
public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException
{
// make sure our args are valid
if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");
// save our url once
String url = uri.toString();
// prepare our response
Map<String, List<String>> res = new java.util.HashMap<String, List<String>>();
// get the cookie
String cookie = this.webkitCookieManager.getCookie(url);
// return it
if (cookie != null) res.put("Cookie", Arrays.asList(cookie));
return res;
}
#Override
public CookieStore getCookieStore()
{
// we don't want anyone to work with this cookie store directly
throw new UnsupportedOperationException();
}
}
And finally, call once only, early in your code and before any https request :
WebkitCookieManagerProxy coreCookieManager = new WebkitCookieManagerProxy(null, java.net.CookiePolicy.ACCEPT_ALL);
java.net.CookieHandler.setDefault(coreCookieManager);
After looking for a solution for a long time, I found it here: Two way sync for cookies between HttpURLConnection (java.net.CookieManager) and WebView (android.webkit.CookieManager)

From Volley Request, you have to take a cookie and store in shared preference.
then you can set the same cookie with your web view settings.
To retrieve cookie details from volley refer this link
To set the cookie to web view URL like
CookieManager cookieManager = CookieManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.setAcceptThirdPartyCookies(webView, true);
} else {
cookieManager.setAcceptCookie(true);
}
cookieManager.setCookie(url, ${cookie});
webView.load(url);

Related

Xamarin OnPageFinished --- getting cookies

I am overriding this method for my WebView. And I am using the proper domain. When debugging using an Android simulator I only see a partial list of all of the cookies. The one in particular I'm requiring the value of isn't listed. Any suggestions? Source code below.
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
_cookieManager.Flush();
string customerId = null;
var cookies = _cookieManager.GetCookie(Constants.DCH_DOMAIN);
Log.Info(TAG, string.Format("Cookies retrieved as {0}.", cookies));
if (cookies != null)
{
string[] tempList = cookies.Split(';');
foreach (var pair in tempList)
{
if (pair.Contains("wishlist_customer_id"))
{
string[] tempPair = pair.Split('=');
customerId = tempPair[1];
if (customerId != null)
{
Log.Info(TAG, string.Format("Customer ID retrieved as {0}.", customerId));
PCLStorage(customerId);
}
}
}
}
UPDATE There is another domain that stores cookies as part of this web session. No different in path, HTML, same site, secure, etc. between the four cookies. I'll attach what Chrome on my workstation looks like, showing these four cookies. Then I'll attach what my Android simulator's device log looks like, where I output the cookie collection based on the subclassed WebViewClient. Only two of the four cookies appear to be there. I inserted a SystemClock.Sleep(5000) before retrieving the cookies, in order to give them a chance to fully populate as well.
Chrome session
WebViewClient session
you should do cookied synchronization before load url to ensure complete cookie data like :
_cookieManager.flush ();
webView.loadUrl(url);
then get cookies int the OnPageFinished method :
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
string customerId = null;
var cookies = _cookieManager.GetCookie(url);
Log.Info(TAG, string.Format("Cookies retrieved as {0}.", cookies));
if (cookies != null)
{
string[] tempList = cookies.Split(';');
foreach (var pair in tempList)
{
if (pair.Contains("wishlist_customer_id"))
{
string[] tempPair = pair.Split('=');
customerId = tempPair[1];
if (customerId != null)
{
Log.Info(TAG, string.Format("Customer ID retrieved as {0}.", customerId));
PCLStorage(customerId);
}
}
}
}
Thanks to Leo Zhu the issue has been resolved. Apparently before I load the WebView URL I needed to flush the CookieManager instance. This resulted in all of the cookies for this particular resource to appear and be available for querying. Hope that this might help anyone else who runs into a similar challenge!

How to set cookie in android WebView client

I want to call one specific url via WebView. The page can only be called after user already logged in. I use AsyncHttpClient library to perform login call. Once after successfully logged in , loading url via WebView doesn't seem recognise the proper headers esp cookie. My suspect is that cookies are not sync correctly between HttpClient and WebView's HttpClient . Any idea why ? . Here is how i use WebView
final WebView webView = (WebView) content.findViewById(R.id.web_travel_advisory);
String url = "http://mydomainurl.com/get_data_after_login";
webView.setWebViewClient(new WebViewClient());
CookieSyncManager.createInstance(getActivity());
CookieSyncManager.getInstance().startSync();
CookieManager.getInstance().setAcceptCookie(true);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(url);
Appreciate ur help .
Ohh after several hours, i finally figured it out to get it worked. Firstly CookieSyncManager is deprecated on later version of android since api 21 according to doc. So decided not to use it anymore. Secondly CookieManager is used to store cookie for WebView.
Final code
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
List<Cookie> cookies = WSHelper.cookieStore.getCookies();
cookieManager.removeAllCookie();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().contains("session")){
String cookieString = cookie.getName() + "=" + cookie.getValue() + "; Domain=" + cookie.getDomain();
cookieManager.setCookie(cookie.getDomain(), cookieString);
Log.d("CookieUrl",cookieString + " ");
}
}
}
webView.loadUrl(url);
The key changes to solution is: use cookie.getDomain() instead of explicit domain.
cookieManager.setCookie(cookie.getDomain(), cookieString);
Try this code, after few changes works for me:
public class WebViewActivity extends Activity{
private SharedPreferences mPreferences;
String token="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webviewpage);
mPreferences = getSharedPreferences("CurrentUser", MODE_PRIVATE);
}
public void LaunchWebView(View view) {
WebView myWebView = (WebView) findViewById(R.id.myWebView);
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setSaveFormData(false);
CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().startSync();
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
CookieManager.getInstance().setAcceptThirdPartyCookies(myWebView, true);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String token2= mPreferences.getString("auth_token","");
HashMap<String, String> map = new HashMap<String, String>();
map.put("x-auth-token", token);
myWebView.getSettings().setAppCacheEnabled(true);
myWebView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view,String url) {
view.loadUrl(url);
return true;
}
});
myWebView.loadUrl("YOUR_URL", map);
}
}
My problem was slightly different, but answer from #Tixeon gave me the key to solve it. I was composing my Cookie and adding it to the WebView request, but I discovered that Android was overriding my Cookie and sending its own Cookie.
So first of all, I had to remove all cookies from the array, then compose my own Cookie. This is the sample code:
// Note that my project has minSdkVersion 21, so I can directly use methods only available in Lollipop
private fun loadUrlInWebView(url: String) {
webView.settings.apply {
builtInZoomControls = false
javaScriptEnabled = true
useWideViewPort = true
loadWithOverviewMode = true
setSupportMultipleWindows(false)
}
CookieManager.getInstance().apply {
setAcceptThirdPartyCookies(webView, true) // My minSdkVersion is 21
removeAllCookies { value ->
Log.d("Cookies", "Removed all cookies from CookieManager")
}
}
webView.apply {
isVerticalScrollBarEnabled = true
isHorizontalScrollBarEnabled = true
loadUrl(
url,
mutableMapOf(
"Cookie" to "ThisIsMyCookieWithMyValues",
"Accept" to "*/*",
"Accept-Encoding" to "gzip, deflate",
"Cache-Control" to "no-cache",
"Content-type" to "application/x-www-form-urlencoded"
)
)
}
}
Now the request contains my Cookie and not the default one provided by Android, and my session in WebView is working. Hope this helps someone else
Latest way to set cookies using cookieManager
val siteCookies = CookieManager.getInstance().getCookie(“https://www.dummyurl.com”)
cookieManager.removeSessionCookies {
if (! siteCookies.isNullOrEmpty()) {
val cookie = siteCookies.split("; ".toRegex())
.dropLastWhile { it.isEmpty() } as ArrayList<String>
val iterator = cookie.iterator()
while (iterator.hasNext()) {
val cookie = iterator.next()
if (cookie.isNullOrEmpty()) continue
cookieManager.setCookie(“https://www.dummyurl.com”, cookie)
}
}
}
posting this if this helps someone.

WebView.loadUrl(url, headers) not working in android

I am setting the cookie in headers and call WebView.loadUrl() with this header but it(Cookie in header) will not work on any android device except 4.4. I have test it on android versions 4.2, 4.3, 4.4, 5.0 and 5.1.
webView = (WebView) findViewById(R.id.web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(false);
HashMap <String, String> extraHeaders = new HashMap<String, String>();
extraHeaders.put("Cookie", "{cookie value}");
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url){
view.loadUrl(url, extraHeaders);
return false;
}
});
webView.loadUrl(url, extraHeaders);
Have you tried this
CookieManager.getInstance().setAcceptCookie(true);
if you are using Android Lollipop, then
CookieManager.getInstance().setAcceptCookie(true);
won't work. You need to use
CookieManager.getInstance().setAcceptThirdPartyCookies(true);
To set cookie use the following method
CookieManager.getInstance().setCookie(BuildConfig.BASE_SERVER_ENDPOINT,COOKIE_VAL);
Make sure the base endpoint matches the base url of the links opened in the webview.
To remove cookie
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().removeAllCookies(null);
} else {
CookieManager.getInstance().removeAllCookie();
}
This is just a quick post about adding cookies to a web view. If you’ve ever tried to do this the way most people have said that it should be done, you’ve failed miserably and found this post. :)
The way it’s supposed to work is you set the cookie on the CookieManager and then tell the CookieSyncManager to sync.
CookieManager.getInstance().setCookie(domain, value);
CookieSyncManager.getInstance().sync();
I’ve never got this to work as described. With or without async tasks waiting for the threads to catch up.
Instead, I just add the cookie in the header of all the loadUrl calls.
Map<String, String> headers = new HashMap<String, String>();
headers.put("Cookie", "cookieName=cookieValue;domain=domain.com;path=/;Expires=Thu, 2 Aug 2021 20:47:11 UTC;");
webView.loadUrl("myurl.com", headers );
Caveat: I only need to initially load the appropriate cookie for the request, if you want to cover nested calls from inside the browser, you need to override shouldOverrideUrlLoading.
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url, headers);
return false;
}
});
If you need to inject the cookie for all requests(including images, js, etc), you’re going to need to override shouldInterceptRequest,
It's beceause of Cookie Policy, to fix it, you should add this :
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
// Allow third party cookies for Android Lollipop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
WebView webView = (WebView)super.appView;
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptThirdPartyCookies(webView,true);
}
super.loadUrl(Config.getStartUrl());
}
I got the solution for the issue by creating the custom cookie manager:
public class WebkitCookieManagerProxy extends CookieManager {
private android.webkit.CookieManager webkitCookieManager;
public WebkitCookieManagerProxy() {
this(null, null);
}
public WebkitCookieManagerProxy(CookieStore store, CookiePolicy cookiePolicy) {
super(null, cookiePolicy);
this.webkitCookieManager = android.webkit.CookieManager.getInstance();
}
#Override
public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException {
// make sure our args are valid
if ((uri == null) || (responseHeaders == null)) return;
// save our url once
String url = uri.toString();
// go over the headers
for (String headerKey : responseHeaders.keySet()) {
// ignore headers which aren't cookie related
if ((headerKey == null) || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie"))) continue;
// process each of the headers
for (String headerValue : responseHeaders.get(headerKey)) {
this.webkitCookieManager.setCookie(url, headerValue);
}
}
}
#Override
public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException {
// make sure our args are valid
if ((uri == null) || (requestHeaders == null)) throw new IllegalArgumentException("Argument is null");
// save our url once
String url = uri.toString();
// prepare our response
Map<String, List<String>> res = new java.util.HashMap<String, List<String>>();
// get the cookie
String cookie = this.webkitCookieManager.getCookie(url);
if (cookie != null) res.put("Cookie", Arrays.asList(cookie));
return res;
}
#Override
public CookieStore getCookieStore() {
// we don't want anyone to work with this cookie store directly
throw new UnsupportedOperationException();
}
}
And initialize the custom cookie manager in Application class or when application starts as:
android.webkit.CookieSyncManager.createInstance(this);
android.webkit.CookieManager.getInstance().setAcceptCookie(true);
WebkitCookieManagerProxy coreCookieManager = new WebkitCookieManagerProxy(null, java.net.CookiePolicy.ACCEPT_ALL);
java.net.CookieHandler.setDefault(coreCookieManager);
If you are using Android Lollipop i.e. SDK 21, then:
CookieManager.getInstance().setAcceptCookie(true);
won't work. You need to use:
CookieManager.getInstance().setAcceptThirdPartyCookies(true);
I ran into same issue and the above line worked as a charm.

Android CookieManager setCookie creates multiple cookies

In my android application I have a webview. It loads URLs from multiple domains. I need to delete all cookies from a specific domain. I want to keep cookies from other domains. But I need to delete all cookies from one domain. I'm open to all other solutions that handles my request. (note that domain uses both http and https)
But when I try to use CookieManager.setCookie, all available cookies for that domain didn't deleted. Multiple cookie keys appeear when I try to write to that keys.
I attach my code below. You can find results in comment lines. At the end of story I get this cookie. Note for multiple values:
"userid=12%34; token=12ased; remember_check=0; userid='-1'; token='-1'; remember_check='-1';"
My helper function that splits cookie string to get cookie keys:
public static Vector<String> getCookieAllKeysByCookieString(String pCookies) {
if (TextUtils.isEmpty(pCookies)) {
return null;
}
String[] cookieField = pCookies.split(";");
int len = cookieField.length;
for (int i = 0; i < len; i++) {
cookieField[i] = cookieField[i].trim();
}
Vector<String> allCookieField = new Vector<String>();
for (int i = 0; i < len; i++) {
if (TextUtils.isEmpty(cookieField[i])) {
continue;
}
if (!cookieField[i].contains("=")) {
continue;
}
String[] singleCookieField = cookieField[i].split("=");
allCookieField.add(singleCookieField[0]);
}
if (allCookieField.isEmpty()) {
return null;
}
return allCookieField;
}
I get present cookies:
// I take cookie string for specific URL
mCookieManager = CookieManager.getInstance();
String url2="https://mysite.com";
String cookieString = mCookieManager.getCookie(url2);
Toast.makeText(mContext, "cookie string:\n"+cookieString, Toast.LENGTH_SHORT).show();
// result is: userid=12%34; token=12ased; remember_check=0;
Then I call to replace old cookies.
Vector<String> cookie = CookieUtil.getCookieAllKeysByCookieString(cookieString);
if (cookie == null || cookie.isEmpty()) {
Toast.makeText(mContext, "cookie null", Toast.LENGTH_SHORT).show();
}
if (cookie != null) {
int len = cookie.size();
Toast.makeText(mContext, "cookie number: "+len, Toast.LENGTH_SHORT).show();
// result is, cookie number: 3
String cookieNames="";
for (int i = 0; i < len; i++) {
cookieNames += "\n"+cookie.get(i) ;
mCookieManager.setCookie(url2, cookie.get(i) + "='-1';");
}
Toast.makeText(mContext, "cookieNames:\n"+cookieNames, Toast.LENGTH_SHORT).show();
// result is: "cookienames: userid token remember_check"
mCookieSyncManager.sync();
cookieString = mCookieManager.getCookie(url2);
Toast.makeText(mContext, "cookie string:\n"+cookieString, Toast.LENGTH_SHORT).show();
mCookieSyncManager.sync();
// result is: "userid=12%34; token=12ased; remember_check=0; userid='-1'; token='-1'; remember_check='-1';"
}
Edit:
I also tried setCookie like this:
mCookieManager.setCookie(url2, cookie.get(i) + "=-1;");
mCookieManager.setCookie(url2, cookie.get(i) + "=-1");
Edit2: setCookie's signature is like this:
/**
* 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.
*
* #param url the URL for which the cookie is set
* #param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
public void setCookie(String url, String value) {
throw new MustOverrideException();
}
Although I get same keys inside cookie string ("userid=12%34; token=12ased; remember_check=0; userid='-1'; token='-1'; remember_check='-1';") will they have different host or path ?
I've had a similar experience with the CookieManager in Android. Setting the same cookie will indeed add it as a new cookie.
Please try to implement this solution. It will enable you to flush the cookies you want to remove and then you'll be able to set the again as you desire.
Good luck!
First, we can delete the cookie via CookieManager's interfaces:
setCookie(URL, 'COOKIE_KEY=;');
Then, we need to find out the correct URL, considering both Domain and Path attributes of the cookie.
For example, the following cookie
document.cookie = 'COOKIE_NAME=COOKIE_VAL; path=/; domain=.example.com;'
can be deleted by
setCookie('.example.com', 'COOKIE_NAME=;')
and cannot be deleted by
setCookie('www.example.com/info.html', 'COOKIE_NAME=;')
Finally, here is an example to remove a cookie.
String[] kvPairs = CookieManager.getInstance().getCookie(url).split(" ");
for (String kvPair : kvPairs) {
String newPair = kvPair.replaceAll("=.*", "=;");
// Delete the cookie asynchronously.
CookieManager.getInstance().setCookie(url, newPair);
}

How to get all cookies from CookieManager android ?

For Android CookieManager class there is a method -- getCookie(String url).
For this we need to know correct url.
Is there a way to get all cookies in CookieManager and get the urls .
some thing like getCookies ??
This is just to double check if i am giving anything wrong in my url for getCookie(String url) call.
I am not getting the cookie when i call the same.
I am passing complete IP address here in url. Something like this : "xx.x.x.x"
Thanks
Mia
I used the CookieManager with the java.net package in my Android Application and it works like a charm. Here is a code snippet :
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.HttpCookie;
import java.util.List;
private class MyCookieManager
{
private CookieManager mCookieManager = null;
MyCookieManager() {
mCookieManager = new CookieManager();
mCookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(mCookieManager);
}
private List<HttpCookie> getCookies() {
if(mCookieManager == null)
return null;
else
return mCookieManager.getCookieStore().getCookies();
}
public void clearCookies() {
if(mCookieManager != null)
mCookieManager.getCookieStore().removeAll();
}
public boolean isCookieManagerEmpty() {
if(mCookieManager == null)
return true;
else
return mCookieManager.getCookieStore().getCookies().isEmpty();
}
public String getCookieValue() {
String cookieValue = new String();
if(!isCookieManagerEmpty()) {
for (HttpCookie eachCookie : getCookies())
cookieValue = cookieValue + String.format("%s=%s; ", eachCookie.getName(), eachCookie.getValue());
}
return cookieValue;
}
}
You can use reflection to see the cookie map. It's called mCookieMap in 4.0.3 (and probably in earlier releases as well). The type is Map>.
This isn't a great way of doing it because you'll risk breaking on different devices or OS versions if they don't use mCookieMap, but CookieManager doesn't offer a public way of knowing which URLs it's visited.

Categories

Resources