I created a library that handles authentication, which I added as a dependency to my application. The library uses OkHttp to handle authentication, so I use a CookieJar
to sync the cookies from the OkHttpClient instance with the Android CookieManager
.
object SyncCookieJar : CookieJar {
val manager by lazy { CookieManager.getInstance() }
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
for (cookie in cookies) {
manager.setCookie(url.toString(), cookie.toString())
}
}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
val header = manager.getCookie(url.toString())
return if (!header.isNullOrBlank()) {
header.split(';').mapNotNull { Cookie.parse(url, it) }
} else {
emptyList()
}
}
fun empty(callback: (() -> Unit)? = null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
manager.removeAllCookies { callback?.invoke() }
} else {
manager.removeAllCookie()
callback?.invoke()
}
}
}
This should allow me to use the cookies set by OkHttp in the standard WebView
. So I built a WebViewClient
that refreshes authentication if the WebView
loads our login page (so the user doesn't have to resubmit their credentials unless the refresh fails).
private inner class AuthWebViewClient : WebViewClient() {
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
showDeterminateProgressBar()
refreshMenuItem?.isVisible = false
cancelMenuItem?.isVisible = true
}
override fun onPageFinished(view: WebView, url: String) {
hideProgressBar()
forwardMenuItem?.isEnabled = webViewFragment.webView.canGoForward()
refreshMenuItem?.isVisible = true
cancelMenuItem?.isVisible = false
}
@SuppressWarnings("Deprecation")
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
return shouldOverrideUrlLoading(view, Uri.parse(url))
}
@TargetApi(Build.VERSION_CODES.N)
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
return shouldOverrideUrlLoading(view, request.url, request.requestHeaders)
}
private fun shouldOverrideUrlLoading(
view: WebView, uri: Uri, headers: Map<String, String>? = null
): Boolean {
if (uri.host.endsWith(URL_LOGIN)) {
showIndeterminateProgressBar()
viewModel.refreshAuthentication(this@SimpleWebActivity, { authToken ->
if (authToken != null) {
Timber.d("cookies=${CookieManager.getInstance().getCookie(uri.toString())}")
view.loadUrl(uri.toString(), headers)
} else {
finish()
}
})
} else if (TrustedHost.contains(uri)) {
view.loadUrl(uri.toString(), headers)
} else {
openInBrowser(uri.toString())
}
return true
}
}
This works perfectly in the sample application I built along with the library.
But when I added the library as a dependency to another project, the OkHttpClient
logs that the cookies are acquired and that a token is successfully acquired, yet the WebView
never gets those cookies.
I cannot figure out why this would be. Any clues?