Glubker
Glubker

Reputation: 11

Android WebView with Jetpack Compose not rendering Mantine UI (React) components properly

Description

I've developed a React website using the Mantine UI framework, and it works seamlessly across various browsers and devices. Now, I'm trying to create an Android app using Jetpack Compose that displays a WebView of the website. However, I've encountered an issue where some Mantine UI components, such as modals and the sidebar, fail to render correctly in the Android Webview, but does work in a regular android browser like Chrome.

Problem Description:

The modal background blurs as expected, but the modal itself and all it's contents does not appear. This issue is specific to Android; the website functions properly in a regular browser and on iOS. Webview permissions have been granted, including allowing JavaScript, but the problem persists.

Here's the code I'm using to display the WebView:

AndroidView(
    modifier = Modifier.fillMaxSize(),
    factory = { context ->
        WebView(context).apply {
             setupWebView(this)
             loadUrl("https://v6.mantine.dev/core/modal/")
        }
    }
)

Attempts and Observations:

I tried various different ways of implementing the built in Webview into my app to see if I could resolve the issue, but none worked. I've also ensured the Webview isn't missing any permissions that's preventing it from working.

I've explored alternative WebView options and tested Mozilla's Geckoview, which renders the Mantine UI components correctly. However, I'm struggling to integrate Geckoview into my project due to Gradle build configuration differences.

I used this guide to try implement it, but failed:

https://firefox-source-docs.mozilla.org/mobile/android/geckoview/consumer/geckoview-quick-start.html

My Gradle Build Configuration:

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.myapp"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.myapp"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.1"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {

    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    implementation("androidx.activity:activity-compose:1.8.1")
    implementation(platform("androidx.compose:compose-bom:2023.08.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.ui:ui-graphics")
    implementation("androidx.compose.ui:ui-tooling-preview")
    implementation("androidx.compose.material3:material3")

    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")

    implementation("androidx.compose.material:material-icons-extended:1.5.4")

    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-tooling")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}

Question:

  1. Has anyone faced challenges with Mantine UI components failing to render correctly within an Android WebView using Jetpack Compose?
  2. Could someone offer guidance on seamlessly integrating Mozilla's Geckoview or other WebView libraries into a Jetpack Compose project? Alternatively, suggestions on resolving issues with the default WebView to ensure proper functionality would be greatly appreciated. Please take my current Kotlin Gradle build configuration into account.

I appreciate any insights, workarounds, or examples that could help resolve this problem. Thank you!

Upvotes: 1

Views: 2951

Answers (2)

Risal Fajar Amiyardi
Risal Fajar Amiyardi

Reputation: 1011

You need to set layoutParams

AndroidView(
    factory = { context ->
        WebView(context).apply {
            settings.domStorageEnabled = true
            settings.javaScriptEnabled = true
            webChromeClient = WebChromeClient()
            webViewClient = WebViewClient()
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        }
    },
    update = {
        it.loadUrl(url)
    },
    modifier = Modifier
        .fillMaxWidth()
        .weight(1f)
)

Upvotes: 0

Chirag Thummar
Chirag Thummar

Reputation: 3202

As I checked your problem. You are missing the one line settings.javaScriptEnabled = true which causes the error. Because default it is false so JavaScript will not work and React is also a part of JavaScript.

I have checked below example in my emulator and it works and open the model dialog with content.

import android.graphics.Bitmap
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.viewinterop.AndroidView

@Composable
fun WebViewDemoScree() {
    var backEnabled by remember { mutableStateOf(false) }
    var webView: WebView? = null
    AndroidView(
        modifier = Modifier.fillMaxSize(),
        factory = { context ->
            WebView(context).apply {
                webViewClient = object : WebViewClient() {
                    override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
                        backEnabled = view.canGoBack()
                    }
                }
                settings.javaScriptEnabled = true

                loadUrl("https://v6.mantine.dev/core/modal/")
                webView = this
            }
        }, update = {
            webView = it
        })

    BackHandler(enabled = backEnabled) {
        webView?.goBack()
    }
}

Upvotes: 1

Related Questions