Fixing Invisible React App on Android Webview


Hey 👋,

recently I challenged myself to recover a project that was abandoned for a while: NumyNums.

It was a simple game built around 2014 (wow… 10 years already!) that I used as an experiment for another project of mine: WebWrapp.

So I rewrote the game, using React this time, and uploaded it to https://numynums.com (which I had to re-buy since it expired long ago).

It took me around three hours to bring it back to more or less the original status. I now plan on improving it, but that’s a story for another time. It’s there and it’s working 🚀.

Once the webapp was ready, I wanted to cleanup the Android project too. Oh boy, bringing up to date all the dependencies and tooling was a real challenge.

It was that big of a proble that I decided to first do a very basic proof of concept: create an Android app with a Webview that loads the game directly from the url.

The Simple App

I create a new Android project with a “blank activity” and added a WebView to the composable layout.

This is more or less the contents of the MainActivity.kt:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NumynumsTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    Greetings("Android")
                }
            }
        }
    }
}

I quickly replaced the Greetings component with a WebView and made it load https://numynums.com.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NumynumsTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    WebViewScreen()
                }
            }
        }
    }
}


@Composable
fun WebViewScreen() {

    AndroidView(
        factory = { context ->
            WebView(context).apply {
                // Important: Needed to allow JS.
                settings.javaScriptEnabled = true
                // This can be overridden for debug.
                webViewClient = WebViewClient()
                // The actual URL being loaded.
                loadUrl("https://numynums.com")
            }
        }
    )
}

If you pay attention, you will see that I’m enabling javascript execution. This is something I read while researching and also I remembered from my previous experience with WebWrapp.

The Problem

I hit that wonderful “Run” button and opened the app in the emulator. The webview appeared, displayed the characteristic pink background from my game, and then… nothing.

Nice, let’s check the logs. Probably some configuration is missing. None. No errors, no warnings, no nothing.

Investigating

I was getting quite upset, because I had no information at all about what was happening. Reading about debugging I found that I could use WebView.setWebContentsDebuggingEnabled(true); to allow debugging the webview using Chrome DevTools.

So I did it. Added the line to MainActivity’s onCreate method and ran the app again.

Went to chrome, opened chrome://inspect and… there it was! The webview was there, completely empty but there.

I right clicked, inspected and… voilà! The <html> tag had a height of 0px.

The Solution

Now I knew what was happening. Everything was fine, but apparently the html { height: 100% } was not being applied because somehow the webview had only a content height of 0px.

After some extra research found that I could make the WebView match the parent’s size.

💡 Notice that the Surface component has a Modifier.fillMaxSize() that makes it fill the whole screen. So the problem was the WebView not filling the Surface.

The code I finally used for the WebViewScreen component:

@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebViewScreen() {

    AndroidView(
        factory = { context ->
            WebView(context).apply {
                // Important: Needed to make sure the html body fills the full space.
                layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
                // Important: Needed to allow JS.
                settings.javaScriptEnabled = true
                // Important: Needed to allow dom storage access.
                settings.domStorageEnabled = true
                // This can be overridden for debug.
                webViewClient = WebViewClient()
                // The actual URL being loaded.
                loadUrl("https://numynums.com")
            }
        }
    )
}

And now, everything was working as I expected. 🎉

I hope this helps you (or my future self). If this was any helpful to you I would really appreciate a like by clicking the 👍 button below.