2

I have a need to integrate an app which has a native login screen with the rest of the application running inside of a webview (hybrid app). It sounds like a somewhat common approach but I'm having problems transferring session data (cookies) from native code to the webview and I think it's related to the asynchronous behaviour of CookieManager.

Sometimes, on some devices, the cookies are either being removed or not applied. From what I've read it could be because removeSessionCookie, setCookie and sync run asynchronously in their own thread. I don't really understand this in Java coming from other programming languages as there doesn't seem to be any hooks to know when then task is complete EG callbacks, events, asyc/await etc.

So the question is how do you know when a async task is done in Android/Java? I've come across the synchronized block syntax but it doesn't look like it would wait for something like removeSessionCookie to complete.

My code looks a little like this:

CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeSessionCookie(); // problem
CookieSyncManager.getInstance().sync(); // maybe problem

List<Cookie> cookies = httpClient.getCookieStore().getCookies();
for (int i = 0; i < cookies.size(); i++) {
    Cookie cookie = cookies.get(i);
    String cookieString = cookie.getName() + "=" + cookie.getValue();
    cookieManager.setCookie(url, cookieString);
}
CookieSyncManager.getInstance().sync();
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
sub
  • 232
  • 2
  • 9

2 Answers2

4

Unfortunately, the CookieManager API design makes this difficult/impossible. CookieSyncManager is not relevant at all here; it only handles synchronisation between the in-memory cookie database and the one stored on disk. Calling sync() on it won't make any difference; the WebView and CookieManager both share the in-memory database already, and see each other's changes immediately when they are actually made.

Normally an asynchronous method would provide some kind of callback or way to wait for it complete, but removeSessionCookie() just doesn't. There is actually such a method implemented inside the code in some versions the classic WebView (from Honeycomb up until JB) but it's not a public API method, you would have to access it via reflection, and it won't work on the new WebView on KK and above. If you really want to call it, it's void waitForCookieOperationsToComplete(), but I wouldn't advise it.

Why are you calling removeSessionCookie() in the first place? The easiest fix would be to not use it; the rest of the CookieManager API behaves as you would expect. You also don't need to call CookieSyncManager.sync() explicitly. Were you having a problem that caused you to add these calls, or did you copy them from somewhere?

This is even more complicated if you support older OS versions; from Cupcake to Gingerbread the network stack used by CookieManager was different and the APIs behave differently, so there's actually three versions to target here: up until Gingerbread, Honeycomb through Jellybean, and then KitKat and later..

Torne
  • 672
  • 3
  • 11
  • Thanks - that's been the clearest information I've come across so far. I find it so strange why such methods have no callback. – sub Dec 05 '13 at 09:24
  • 1
    It's not that strange; the WebView API is very old and the only app that made nontrivial use of it for a long time was the browser, which had the ability to call nonpublic/hidden methods as it was part of the platform. So, some of the API is rough around the edges, and Android's compatibility requirements make it hard to change. – Torne Dec 10 '13 at 10:37
1

Create your own implementation of java.net.CookieManager which forwards all requests to the WebViews' webkit android.webkit.CookieManager. This means no sync is required and HttpURLConnection uses the same cookie storage as the WebViews.

Two way sync for cookies between HttpURLConnection (java.net.CookieManager) and WebView (android.webkit.CookieManager)

Community
  • 1
  • 1
Dan McNerthney
  • 394
  • 5
  • 7