Hi guys I am an android developer and quite new to...
# kobweb
s
Hi guys I am an android developer and quite new to KMP and kobweb. I was recently experimenting with kobweb. I wonder if it is possible to use js function from kotlin. where to place the js file in the sourceset and call that in kotlin. This is what I tried. But when I tried to show the webpage in android(flutter) webview, I get the error that
"Uncaught ReferenceError: globalThis is not defined"
. Also I have noticed that there is no
onclick
event added to the
button
in the index.html which causes problem when I display the page in the webview. I see that some calls are there in generated js file which is minified and hard to understand. I want to invoke a method from the webview listen to it JavaScript Platform Channel of flutter web view and handle it in flutter.
Copy code
fun invokeClick() {
    js(" MessageInvoker.postMessage('clicked')")
}
@Page
@Composable
fun HomePage() {
Button(
onClick =  {
                        if (cta == "Click me!") invokeClick()
                    },
                    attrs = Modifier.fillMaxWidth().height(ButtonHeight)
                        .border(NilBorder).borderRadius(BorderRadius)
                        .color(Colors.Navy.copy(alpha = 250))
                        .boxShadow(blurRadius = BlurRadius, spreadRadius = SmallSpreadRadius, color = Colors.Black.copy(alpha = 30))
                        .backgroundColor(Colors.SkyBlue.copy(alpha = 190))
                        .fontWeight(FontWeight.Bolder)
                        .fontFamily("Arial")
                ) {
                    Text("Check it out".uppercase())
                }
}
So to make the JavaScriptChannel work, I had to just create the external functions and then add it manually to the html page like following:
Index.kt
Copy code
external fun invokeClick() // Removed the implementation and made it an external function

@Page
@Composable
fun HomePage() {
Button(
onClick =  {
                        if (cta == "Click me!") invokeClick()
                    },
                    attrs = Modifier.fillMaxWidth().height(ButtonHeight)
                        .border(NilBorder).borderRadius(BorderRadius)
                        .color(Colors.Navy.copy(alpha = 250))
                        .boxShadow(blurRadius = BlurRadius, spreadRadius = SmallSpreadRadius, color = Colors.Black.copy(alpha = 30))
                        .backgroundColor(Colors.SkyBlue.copy(alpha = 190))
                        .fontWeight(FontWeight.Bolder)
                        .fontFamily("Arial")
                ) {
                    Text("Check it out".uppercase())
                }
}
I tried adding the script element like this. But not sure where to place the script.js in the project.
Copy code
LaunchedEffect(Unit){
        val script = document.createElement("script")
        script.asDynamic().src = "script.js"
        document.body!!.appendChild(script)
    }
Code that I added to the generated index.html manually :
trimmed index.html
Copy code
<!doctype html>
<html lang="en">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Flutter web app</title>
  <meta content="Powered by Kobweb" name="description">
  <link href="/favicon.ico" rel="icon">
  <meta content="width=device-width, initial-scale=1" name="viewport">
  <link href="/fonts/faces.css" rel="stylesheet">
  <link href="<https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css>" rel="stylesheet">
 </head>
 <body>
  <div id="root" style="width: 100%; height: 100%;" class="silk-colors_light">


 </div><button onclick = "invokeClick()" <=================== I had to add this manually

style="width: 100%; height: 48px; border: 0px; border-radius: 5px; color: rgba(0, 0, 128, 0.98); box-shadow: rgba(0, 0, 0, 0.118) 0px 0px 3px 1px; background-color: rgba(135, 206, 235, 0.745); font-weight: bolder; font-family: Arial;">CHECK IT OUT</button>
        </div>
       </div>
      </div>
     </div>
    </div>
   </div>
  </div>

  <script>
   function invokeCashbook() {  <============================= I had to add this manually to make it work.
       MessageInvoker.postMessage('clicked')
   }
  </script>
  <script src="/generated.js"></script>
 </body>
</html>
The actual code has been simplified to prepare the question. This is the actual webpage generated by kobweb export:
d
Hey @sunragav as you also asked this question in the Discord (link to Discord thread for our Discord users) and got an answer there that you are investigating -- once you get something that works, can you put the answer here? Thank you!
s
I understood that it is due to the limitation of webview provided by the flutter plugin I used. I could achieve the desired result without hardcoding using the following code:
Copy code
```kotlin
@Page
@Composable
fun HomePage() {
    LaunchedEffect(Unit){
        val script = document.createElement("script")
        script.textContent = """
            function invokeClick() {
                console.log(" MessageInvoker.postMessage('clicked')")
                MessageInvoker.postMessage('clicked')
            }
        """.trimIndent()
        document.body!!.appendChild(script)
    }
    Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Button({}, Modifier.attrsModifier { attr("onClick", "invokeClick()") }) {
            Text("Click me!")
        }
    }
}
This produces the following code (the same one which I had created manually hardcoded earlier) and WORKS WELL. I am happy that I could generate the same programmatically using kobweb.
Copy code
html
 <body>
...
    <button class="silk-button silk-button-size_md" onclick="invokeClick()" type="button">
      <div class="kobweb-row kobweb-arrange-center kobweb-align-center-vert">
       Click me!
      </div></button>
...
  <script src="/flutterwebview.js"></script>
  <script>
     fun invokeClick(){
        MessageInvoker.postMessage("clicked")
     }
    </script>
 </body>
```
I will try a more advanced flutter plugin like this Thanks for all your help.
The correct solution of this experiment can be found here.