2

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?

Bryan
  • 14,756
  • 10
  • 70
  • 125

0 Answers0