Search code examples
androidandroid-webviewbackwards-compatibility

JavaScriptInterface in a WebView is not called on Lollipop and Marshmallow


I have tried it on android 7.0, it works, but on android 5,6 it does not work, i could not find any clue on what maybe going wrong. The URL redirect to payment portal and at the end it calls Android.postMessage("success") from Javascript, but it does not get called in native this problem only persist in android 5 and maybe on android 6 too.

My minimum SDK level is 21.

class PaymentActivity : BaseActivity<ActivityPaymentBinding, IPaymentMvvm.ViewModel>(), IPaymentMvvm.View {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activityComponent.inject(this)
        setAndBindContentView(savedInstanceState, R.layout.activity_payment)
        viewModel.initVM()
        binding.web.webViewClient = Web(viewModel)
        binding.web.settings.javaScriptEnabled = true
        binding.web.settings.loadWithOverviewMode = true
        binding.web.settings.useWideViewPort = true
        binding.web.addJavascriptInterface(JSBridge(this, this), "Android")


        val url = intent.extras.getString("url")
        if (url == null)
            finish()

   binding.web.loadUrl(url)




    }

    override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {

        when (menuItem.itemId) {
            android.R.id.home ->
                finish()

        }
        return super.onOptionsItemSelected(menuItem)
    }

    class Web(val viewModel: IPaymentMvvm.ViewModel) : WebViewClient() {
        init {
            viewModel.setProgress(true)
        }

        override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {

            view?.loadUrl(request?.url.toString())

            return true
        }

        override fun onPageFinished(view: WebView?, url: String?) {
            super.onPageFinished(view, url)
            viewModel.setProgress(false)
        }

        override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
            super.onReceivedError(view, request, error)
            viewModel.setProgress(false)
            Timber.e(error.toString())
        }
    }
}


class JSBridge(val context: Context, val activity: Activity) {
    @JavascriptInterface
    fun postMessage(message: String) {
        // here we return true if we handled the post.
        Timber.i(message)
        context.toast(message)

        val intent = Intent(context, OrderThanksActivity::class.java)
        intent.putExtra(Enums.contactDetail.contactNumber.name, activity.intent.getStringExtra(Enums.contactDetail.contactNumber.name))
        intent.putExtra(Enums.contactDetail.phoneNumber.name, activity.intent.getStringExtra(Enums.contactDetail.phoneNumber.name))
        intent.putExtra(Enums.contactDetail.cellNumber.name, activity.intent.getStringExtra(Enums.contactDetail.cellNumber.name))
        activity.startActivity(intent)
        activity.finish()
    }
}

Solution

  • It was the problem of JavaScript script from web, which threw an error in a script running in web view before my interface function even get called, but the weird behavior was that script only got terminated on Android 5,6 while Android 7 web view does not terminate execution and execute the whole script regarding error that's why the interface function got called in Android 7.