1

I'm using kotlin to develop the native application which have a webview and some functions for the webview javascript.

User can click the button on the page then call the native toast or alert dialog

I finished the functions and it work perfectly, now I want to add the callback function into the dialog, when user click OK button (positive button), it will run the javascript on the webpage,

Javascript on webpage

Android.showAlert("Title","Message",function(){alert(123)});

JavascriptInterface

@JavascriptInterface
    fun showAlert(title:String,msg: String, callBack: Any?) {
        val alertDialog = AlertDialog.Builder(mContext)
        alertDialog.setTitle(title).setMessage(msg)
        alertDialog.setPositiveButton("OK") { _, _->callBack())}
        alertDialog.show()

        Log.d('check',callBack) // Logged callback is null

  }

The code seems cannot receive the callback function, how can I solve it and run the callback?

Thanks

Pete
  • 170
  • 1
  • 13
  • Possible duplicate of [Asynchronous JavaScript calls from Android WebView](https://stackoverflow.com/questions/30816325/asynchronous-javascript-calls-from-android-webview) – tynn May 26 '19 at 10:02
  • This [`JSPromise`](https://gist.github.com/timfreiheit/12a67124f1bb2a9572da) might also help to work around your issue. – tynn May 26 '19 at 10:07

1 Answers1

0
  1. You can't just log a function, because in JavaScript function don't have ID or address or anything like that, present on other languages. To log it, you have to explicitly set a property or string with function ID or textual name, and then use it. The best way to do it might be to pass callback by textual name - you could then both log it, and actually call it back, see the following.

  2. People on this site suggest this way to make calls from Android to JavaScript in WebView:

    mWebView.loadUrl("javascript:someFuncInJS();");
    

    However, there's BETTER & CLEANER way to do this, which looks more right: use evaluateJavascript() method. Here's the reference idiom to use it:

    mWebView.evaluateJavascript("""
        (your javascript code goes here)
    """.trimIndent()) { retv ->
        (and here in Kotlin you can handle return value after the code above will be executed)
    }
    

    In your case, you can write so:

    var myCB = "myCallbackFunc1"  // you can get it from previous call from JS
    
    Log.d("check, ${myCB}")
    
    mWebView.evaluateJavascript("""
        ${myCB}();
    """.trimIndent()) { retv ->
    }
    

Please also look at this: Kotlin use Java callback interface

Edit: That all is so if you make a call from the UI thread (main thread) of your Android program. However, if you try to do it from inside the JavascriptInterface call, which runs on a different thread, it will fail. The solution is to always place evaluateJavascript() on the UI thread, and if you need to do it from another thread, use View.post {} for that. Here's an example:

class WebAppInterface(private val mContext: Context, val mAct: MainActivity) {
    /** Show a toast from the web page  */
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()

        mAct.mWebView?.post {
            mAct.mWebView?.evaluateJavascript("f1();") { retv ->
                Toast.makeText(mContext, retv, Toast.LENGTH_LONG).show()
            }
        }
    }
}

For full example on how to do it, please look at https://github.com/latitov/Android_WebViewApp_FullScreen

Hope it helps.

latitov
  • 432
  • 3
  • 8