Set cookies programatically in Crosswalk WebView on Android - android

I need to make Crosswalk on Android (in a Cordova project) use some
cookies I gathered via an Apache HttpClient.
However I'm not sure how to achieve this. I tried experimenting with
the XWalkCookieManager but I think everything I do with the
XWalkCookieManager is ignored. Where would I initialize the cookie
manager? Is this even supported yet?
//cookieStore contains the cookies I got via a request from the Apache
// HttpClient.
List<Cookie> cookies = cookieStore.getCookies();
for (int i = 0; i < cookies.size(); i++) {
Cookie cookie = cookies.get(i);
String cookieString = buildCookieStringFromCookie(cookie);
// This is a XWalkCookieManager I initialized earlier but it doesn't do anything
//as far as I can tell.
cookieManager.setCookie(cookie.getDomain(),cookieString);
}
I would really appreciate any help, this is the only thing that
currently keeps me from using Crosswalk successfully.
I have also tried using the standard Android cookie Manager via CookieManager.getInstance().setCookie(cookie.getDomain(), cookieString); but this seems to be ignored by Crosswalk as well.
Best,
Andreas
//Edit for future reference:
The issue was that Crosswalk expects the cookie url to start with https:// and the native Android webview doesn't (or the other way around, I'm not sure anymore). Now what is working fine is to set the cookie twice, once without https and once with https:
mCookieManager.setCookie(cookie.getDomain(), cookieString);
mCookieManager.setCookie("https://" + cookie.getDomain(), cookieString);

You can create an instance of XWalkCookieManager and set the differents cookies in it.
It seems to be shared accross the XwalkViews.
// Your can use this inside the onCreate() method
private XWalkCookieManager mCookieManager;
mCookieManager = new XWalkCookieManager();
mCookieManager.setAcceptCookie(true);
mCookieManager.setAcceptFileSchemeCookies(true);
// Pass it to your request executor
httpRequestExecutor.setXWalkCookieManager(mCookieManager);
//You're now able to add your cookies to this manager rather than to your cookieManager
How we extract the cookies from the HttpResponse :
responseHeaders = response.getAllHeaders();
for (int i = 0; i < responseHeaders.length; i++)
{
Header header = responseHeaders[i];
if (header.getName().equalsIgnoreCase("set-cookie"))
{
mCookieManager.setCookie(request.getUrl(), header.getValue());
}
}

The implementation of XWalkCooikeManager is a little different with Android CookieManager.
You should add schemes(http|https) before cookie.getDomain().
This is because the implementation of CookieManager in Android WebView use WebAddress(url).toString(), which will add schemes (http|https) into the url.
As the explanation in CooieManagerAdapter:
WebAddress is a private API in the android framework and a "quirk" of the Classic WebView implementation that allowed embedders to be relaxed about what URLs they passed into the CookieManager, so we do the same normalisation before entering the chromium stack.

Related

Does Android XWalkView have a process pool similar to WKProcessPool on iOS?

Our hybrid application uses our corporate Google accounts for sign in. That in-turn uses Active Directory Foundation Services to authenticate our corporate accounts. Everything works nicely until sign-out. The ADFS server holds the user credentials in a cookie or session on the server. In iOS, I can completely invalidate everything by re-creating the WKWebView and providing it with a new fresh WKProcessPool, which then requires the user to re-sign in (required for shared devices)...
let config = WKWebViewConfiguration()
let pool = WKProcessPool()
config.processPool = pool
let webView - WKWebView(frame: UIScreen.mainScreen().bounds, configuration: config)
Is there anything equivalent to that with XWalkView on Android? I am currently programmatically removing the old XWalkView and adding a new XWalkView to the main view when a logout occurs, calling clearCache, and using the cookie manager to remove all cookies, but I'm still logged into the ADFS server.
// Remove old xWalkView if it exists
if(xWalkView != null){
((ViewGroup) xWalkView.parent()).removeView(xWalkView);
xWalkView.onDestroy();
xWalkView = null;
}
// Create a new xWalkView
xWalkView = new xWalkView(this, this);
xWalkView.clearCache(true);
XWalkCookieManager cookieManager = new XWalkCookieManager();
cookieManager.removeAllCookie();
cookieManager.flushCookieStore();
// Add to the main view
RelativeLayout layout = (RelaviteLayout)findViewById(R.id.layoutMain);
layout.addView(xWalkView, 0);
Any help would be greatly appreciated.

WebView unable to save cookie on Android 2.3.x

So I've been trying to get a WebView to work properly to authenticate a user session that is used in app. It works on all 4.0+ devices but when I try to use the same process on a 2.3.6 and 2.3.7 devices it throws this exception in the log:
com.myapp.WebActivity E/webkit﹕ parse cookie failed for: request_uri=xxxxxxxx; path=/; expires=Mon, 16-Jun-2014 00:00:00; domain=;
It doesn't crash the app but will not save this one cookie needed to properly authenticate the users session. I've looked into the Android Source code and it appears that when trying to save this specific cookie there is a RunTimeException that is happening. Here is the Android Source where the exception is thrown and caught. I'm not 100% sure where to look next since the cookies are saved properly on 4.0+ and it seems like a AOSP bug. Also, after the WebView loads the CookieManager doesn't have the cookie that it threw the exception on but has others.
So my real question is: Is there anyway to manually get a cookie returned from a WebView page load or can I get the cookie to be saved by the Android 2.3 WebView automatically somehow?
Thanks in advance.
Here is what I use to check and save a cookie that is picked up by a subsequent WebView. It works on Android 2.2 for sure, as well as Android 4.X.
Checking:
// see if the cookie is already set up
boolean cookieAlreadySetUp = false;
String cookie = cookieManager.getCookie(urlHost);
if ( cookie != null && cookie.length() > 0 ) {
String[] cookies = cookie.split(";");
for ( int i = 0; i < cookies.length; i++ ) {
String oneCookie = cookies[i];
if ( oneCookie.trim().equals(SharedData.COOKIE_STRING) ) {
cookieAlreadySetUp = true;
break;
}
}
}
Saving:
cookieManager.setAcceptCookie(true);
cookieManager.setCookie(urlHost, myCookieString);
CookieSyncManager.getInstance().sync();
// give time for the cookie to become known since the save process is asynchronous to this thread
SystemClock.sleep(100);
Be aware of the asynchronous nature of the cookie manager, both for adding or removing a cookie, as well as testing its existence.

Cookie on Android 2.2 is not available in WebView

I made a Android App with minimum required API 8.
The users are authenticated on my backend with a cookie. This works on every device that has an api level 9 or higher.
The Cookie is saved with CookieManager:
CookieManager cManager = CookieManager.getInstance();
CookieSyncManager.createInstance(LauncherApplication.getAppContext());
cManager.setAcceptCookie(true);
cManager.setCookie(".xxxxxxxx.xx", "MobileGuid=" + guid);
CookieSyncManager.getInstance().sync();
I check if this Cookie is available also with CookieManager:
public static boolean hasCookie(){
CookieManager cManager = CookieManager.getInstance();
String cookieString = cManager.getCookie(".xxxxxxx.xx");
if(cookieString != null && cookieString.contains("MobileGuid")){
return true;
}
return false;
}
This returns always true, but the Cookie is just available in the WebView if the Android Version is higher then 2.2. (I checked this with phpinfo)
My WebView configuration looks like this:
String databasePath = LauncherApplication.getAppContext().getApplicationContext().getDir("database",
Context.MODE_PRIVATE).getPath();
WebSettings mainWebSettings = mainWebView.getSettings();
mainWebSettings.setJavaScriptEnabled(true);
mainWebSettings.setAppCacheEnabled(true);
mainWebSettings.setDatabaseEnabled(true);
mainWebSettings.setDomStorageEnabled(true);
mainWebSettings.setDatabasePath(databasePath);
When you call cManager.setCookie(), try passing
cManager.setCookie("a.xxxxxxxx.xx", "MobileGuid=" + guid + "; domain=xxxxxxx.xx");
So I've added an "a" to the first parameter (literally the character 'a'), and added "domain=xxxxxxx.xx" to the cookie itself.
Your code as written seems to be all correct, and I had a similar struggle with API 9 devices not sending cookies while API 14 devices did. I'm afraid I don't know exactly why it works, but it was the only thing that helped me.
Like the answer of Hylianpuffball the idea is to add a character below your domain name. I think that the CookieManager is looking for something like .domain.com and kind of substring is done to get the domain name.
Just add a dot or any character and it will be working

Cookie corruption with multiple createHTTPClient Titanium calls

While creating an Android app in Appcelerator's Titanium that involves both webView and background calls, I ran into a problem / bug where the cookies were getting corrupted on multiple createHTTPClient calls.
Cookies were originally obtained from the webView:
var webview = Ti.UI.createWebView();
webview.url = 'http://www.example.com';
window.add(webview);
webview.addEventListener('load', function(e) {
cookies = e.source.evalJS("document.cookie");
Titanium.App.Properties.setString('cookies',cookies);
}
window.open({modal:true});
and then later used with a background call:
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();
The first time the above createHTTPClient chunk of code was called, everything worked, but subsequent runs of the above code would send corrupted cookies. In Google App Engine (gae), printing out the request headers would look like this (broken):
logging.info('Request:\n%s' % self.request)
broken response (only the cookie portion of the request header is shown)
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7", auth=eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357225569|7a469fab7a38a437649c25620729e07c4607f617
Cookie2: $Version=1
working response
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7"
...
I suspect the issue has something to do with unicode characters or something inside createHTTPClient. Two auth= statements are shown in the corrupted cookie.
In summary, when the app first launches, the background Titanium.Network.createHTTPClient call works, and any calls after that appear to send corrupted cookies.
The HTTPClient documentation says "object is intended to be used for a single request," so I assumed everything would reset after multiple calls. But something was different after the first call.
Adding loader.clearCookies(base_url); to the code before setting the cookies seems to fix the issue.
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.clearCookies(base_url); // THE FIX.
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();

WebView with Headers Connection Error

I am trying to open a Web view of a site (in Android) that needs token/Cookie in the headers for authentication.
I try to open the page using code below
HashMap<String,String> headers = new HashMap<String,String>();
headers.put("Cookie","MyToken");
MyWebView.loadUrl("https://myURL.com",headers);
I am hitting the onReceivedError with following values
errorCode: -6
*description: The connection to the server was unsuccessful.*
(PS: Since this site can be access from Intranet, using emulator I don't see this error the page loads correctly. Also HttpPost works fine with same token)
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,
That is not a valid cookie header. Try:
headers.put("Cookie", "foo=bar");

Categories

Resources