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.
Related
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);
I have a method that sets and saves a Session Cookie for Android WebView. This code lets me to send a cookie with request that goes by loading url into webview. Unfortunately its not sent on device with android 4.1.2.
private void handleSessionCookieFromWebView() {
CookieManager cookieManager = CookieManager.getInstance();
if (sessionCookie != null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP){
cookieManager.removeSessionCookie();
}
else {
cookieManager.removeSessionCookies(null);
}
String cookieString = JSESSION_ID + sessionCookie.getValue();
cookieManager.setCookie(sessionCookie.getDomain(), cookieString);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(FunctionActivity.this);
CookieSyncManager.getInstance().sync();
}
else {
cookieManager.flush();
}
}
}
I call it before loading URL into WebView. Any ideas what's the problem? Maybe some kind of workaround?
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.
I'm trying to extract the value of a cookie from a webpage after logging in. I am using a cookie helper class and the android.webkit.CookieManager to retreive cookies once the webpage has finished loading i.e. onPageFinished()
This all works fine and I can see the cookie names and values on my test devices, Galaxy S2 (4.0.4), Galaxy S3 (4.1.1) and a HTC Explorer (2.3). However, the same code is not functioning on a Sony Xperia (2.3)?
I have logged out the url to make sure I'm working from the correct page and for some reason I only get 3 cookies from the site on the Xperia, where I should be getting 7 (roughly).
Below is a simplified version of the code I'm running. Appreciate any responses. Thanks in advance!
WebViewActivity
#Override
public void onPageFinished(WebView view, String url) {
if(!cookieCreated){
CookieHelper cookieHelper = new CookieHelper(getApplicationContext());
if(cookieHelper.processCookie(url)){
cookieCreated = true;
}
}
}
CookieHelper
public CookieHelper(Context cont){
this.cookieManager = CookieManager.getInstance();
}
public void processCookie(String url){
if(manager.getCookie(url).contains("cookie_name_required")){
Log.d(TAG, "Got cookie");
}
else{
Log.d(TAG, "No cookie");
}
}
public static void setCookies(Context context) {
//gets all cookies from the HttpClient's cookie jar
List<Cookie> cookies = httpClient.getCookieStore().getCookies();
if (! cookies.isEmpty()) {
CookieSyncManager.createInstance(context);
CookieManager cookieManager = CookieManager.getInstance();
//sync all the cookies in the httpclient with the webview by generating cookie string
for (Cookie cookie : cookies) {
Cookie sessionInfo = cookie;
String cookieString = sessionInfo.getName() + "=" + sessionInfo.getValue() + "; domain=" + sessionInfo.getDomain();
cookieManager.setCookie("zoboon.com", cookieString);
CookieSyncManager.getInstance().sync();
}
} else {
Log.i("httpclient","has no cookies");
}
}
I have a "native" login screen which sets a static cookie and then this activity gets the cookie from LoginWebView.
I'm doing this in an async task.
The problem now is that the async task contains 3 very ugly hacks which makes the code very unreliable (the hacks are marked out in the code below).
The question is, do you have any idea on how to get rid of one or more of these ugly hacks?
Hack nr 1 -
This is taken from an example that someone posted here on stack overflow, the cookie needs to wait a bit before it actually works and loads in the webview, I have no idea why but without it it just does not work. This is not the biggest problem though.
Hack nr 2 -
I don't know why but if I want to be able to load another page I have to first load the page that I got the cookie from. When this is loaded I simply wait a small bit and then load another url. Do anyone have any idea why?
If I don't do this the webview recognizes that the cookie is there but won't finish loading any pages at all, it just stucks on loading and never finishes.
Hack nr 3 -
It's just to remedy hack nr 2.
private class WebViewTask extends AsyncTask<Void, Void, Boolean> {
String cookieString1;
CookieManager cookieManager;
#Override
protected void onPreExecute() {
Cookie sessionCookie = LoginWebView.cookie1;
CookieSyncManager.createInstance(WebViewActivity.this);
cookieManager = CookieManager.getInstance();
cookieString1 = sessionCookie.getName() + "=" + sessionCookie.getValue() + "; " +
"domain=" + sessionCookie.getDomain();
CookieSyncManager.getInstance();
//cookieManager.removeSessionCookie();
super.onPreExecute();
}
protected Boolean doInBackground(Void... param) {
// HACK NR.1
SystemClock.sleep(600);
return false;
}
#Override
protected void onPostExecute(Boolean result) {
Log.v(TAG, "COOKIE SYNC 1: " + cookieString1);
Log.v(TAG, "COOKIE SYNC 1: " + domain);
cookieManager.setCookie(domain, cookieString1);
CookieSyncManager.getInstance().sync();
WebSettings webSettings = webView.getSettings();
webSettings.setSavePassword(true);
webSettings.setSaveFormData(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setSupportZoom(false);
webView.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i(TAG, "Loading...");
view.loadUrl(url);
return true;
}
});
//HACK NR 2
webView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.FAR);
webView.loadUrl(domain);
Log.v(TAG, "PROGRESS " + webView.getProgress());
button1.setChecked(true);
if(webView.getProgress() == 100) {
//HACK NR. 3
SystemClock.sleep(80);
webView.getSettings().setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);
clickButtonOne();
}
}
}
Could you perhaps try a connecting thread solution I have proposed in
android session management
A login activity could utilise that.
And as for the WebView, you can pass the cookie with (sCookie is the static cookie string already set by the login activity):
CookieSyncManager.createInstance(this);
CookieManager cookieManager = CookieManager.getInstance();
String cookieString = sCookie+"; domain="+sDOMAIN;
cookieManager.setCookie(sDOMAIN, cookieString);
CookieSyncManager.getInstance().sync();