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");
}
}
Related
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 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.
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 have native application in Andriod and Iphone with ASP.NET as a back-end. I am sending request to my ASP.NET server API by appending Session_Id cookie using HttpClient classes which works great. But I also need to send the same session in WebView. The problem is that some times WebView send the Session_Id cookie and sometimes doesn't. It strange for me. I am not able to find why sometimes webview send the cookie and sometimes doesn't. Here is my code,
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myapp = ((....) getApplicationContext());
setTimeout(true);
try {
getActionBarHelper().setupHomeActivity();
} catch (Exception e) {
e.printStackTrace();
}
cm = (ConnectivityManager) this.getSystemService(Activity.CONNECTIVITY_SERVICE);
webView = new CustomWebView(this, this);
webView.getWebView().addJavascriptInterface(new MyJavaScriptInterface(), "android");
getTimeDiff();
if(MyApplication.INSTANCE.isLoggedin()){
Cookie sessionCookie = MyApplication.INSTANCE.getCookie();
List<Cookie> cookies = MyApplication.INSTANCE.getClient().getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
sessionCookie = cookies.get(i);
}
try{
if(sessionCookie!=null){
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.setAcceptCookie(true);
if (sessionCookie != null) {
cookieManager.removeSessionCookie();
String cookieString = sessionCookie.getName() + "="
+ sessionCookie.getValue() + "; domain="
+ sessionCookie.getDomain();
if (MyApplication.isDebug())
cookieManager.setCookie(sessionCookie.getDomain(),(sessionCookie.getName() + "=" + sessionCookie.getValue()));
CookieSyncManager.getInstance().sync();
}else{
if (MyApplication.isDebug())
Log.d("WebView", " Cookie is null: " );
}
}else{
if (MyApplication.isDebug())
Log.d("WebView", " Cookie is null: " );
}
}catch (Exception e) {
e.printStackTrace();
}
Log.e("WenView", "============================ ");
}
}
Your for loop appears to only include the single line that retrieves the cookie... so your logic that's setting the cookie below only gets called once, with whatever the last cookie happened to be. Since the cookies aren't ordered in the list, this probably explains why sometimes it works and sometimes it doesn't; it's working when your cookie is last, and failing otherwise.
The answer is to just expand your for loop to include ALL the logic underneath as well. Your copying code looks fine, and I expect it is if you can get it to work sometimes.
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();