WebView in fragment and navigation back

So, I have Fragment with WebView in it and the user is expected to navigate in it, browse some whole site, maybe add something to cart and hopefully proceed to checkout. What happens when the user taps on the back button on Android’s navigation bar? Yes, the fragment is destroyed and the user is navigated back. But that’s no good. Let’s fix that.

I’m honestly sad, but yes, this is interface that will be implemented by activity

interface IOBackPressedCallbackRegistry {
    fun addOnBackPressedCallback(id: String, callback: () -> Boolean)
    fun removeOnBackPressedCallback(id: String)
}

We will use this back pressed callback in fragment. This is where magic happens

class WebViewFragment : Fragment() {
    override fun onResume() {
        super.onResume()
        (activity as? IOBackPressedCallbackRegistry)?.let { registry ->
            registry.addOnBackPressedCallback(this.javaClass.simpleName) {
                // Activity detected tap on back button. 
                // Do something and return true, or return false
                if (webView.canGoBack()) {
                    webView.goBack()
                    return@addOnBackPressedCallback true
                }
                return@addOnBackPressedCallback false
            }
        }
    }

    override fun onPause() {
        (activity as? IOBackPressedCallbackRegistry)
            ?.removeOnBackPressedCallback(fragmentName)
        super.onPause()
    }
}

Actual implementation in Activity

class HostActivity : AppCompatActivity(), IOBackPressedCallbackRegistry {
    private val onBackPressedCallbacks = HashMap<String, () -> Boolean>()

    override fun addOnBackPressedCallback(id: String, callback: () -> Boolean) {
        onBackPressedCallbacks[id] = callback
    }

    override fun removeOnBackPressedCallback(id: String) {
        onBackPressedCallbacks.remove(id)
    }

    override fun onBackPressed() {
        onBackPressedCallbacks.values.forEach { callback ->
            if (callback.invoke()) {
                return
            }
        }
        super.onBackPressed()
    }
}

This can be also useful when a fragment has selection mode (e.g. selecting items from recycler view) and the user can tap on the back button to return to normal viewing mode