Is it feasible to invoke a Vue.js function from an Android WebView?

After searching for answers on various sites without success, I am reaching out for help with a specific issue. I am using vuejs with typescript and a webview in an android app. My goal is to have a button in the android app call a vuejs function, and vice versa, have a function in javascript call an android function. However, neither of these functionalities are working for me. I have tried multiple solutions but none have worked so far. If anyone has any insight on how to solve this issue, please let me know. I have included the relevant code snippets below. The URL path is correct and the page is loading in the webview, with "Home" being routed to "http://url/"

Home js

<template>
  <div class="home">
        <h1>This is an Home page</h1>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
    name: 'Home',
    methods:{
      getAlert(){
        alert(11111);        
      },
      getWebViewAlert(toast:String){
        android.showToast(toast);
      }

    }
})
interface WebAppInterface{  // eslint-disable-line no-unused-vars
  showToast(toast: String) : void;
}

declare var android: WebAppInterface;// eslint-disable-line no-unused-vars

</script>

MainActivity.kt

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        val webviewSetting = binding.webview.settings
        webviewSetting.javaScriptEnabled = true
        webviewSetting.setSupportMultipleWindows(false)
        webviewSetting.javaScriptCanOpenWindowsAutomatically = false
        webviewSetting.loadWithOverviewMode = true
        webviewSetting.useWideViewPort = true
        webviewSetting.setSupportZoom(false)
        webviewSetting.builtInZoomControls = false
        webviewSetting.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
        webviewSetting.cacheMode = WebSettings.LOAD_NO_CACHE
        webviewSetting.domStorageEnabled =true
        binding.webview.webViewClient = object : WebViewClient() {
            override fun onPageFinished(view: WebView, url: String) {
                binding.webview.loadUrl("javascript:getAlert()")
            }
        }
        binding.webview.webChromeClient = WebChromeClient()
        //binding.webview.addJavascriptInterface(WebAppInterface(this),"android")
        binding.webview.loadUrl(url)

        binding.button.setOnClickListener {
            binding.webview.loadUrl("javascript:getAlert()")
        }
    }

class WebAppInterface internal constructor(c: Context) {
    var mContext: Context
    @JavascriptInterface
    fun showToast(toast: String) {
        Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show()
    }
    init {
        mContext = c
    }
}

Error in android studio

I/chromium: [INFO:CONSOLE(1)] "Uncaught ReferenceError: getAlert is not defined", source: url (1)

updated code

import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify'

Vue.config.productionTip = false
let HomeVue; // eslint-disable-line no-unused-vars
new Vue({
  router,
  store,
  vuetify,
  mounted(){
    HomeVue = this
  },
  methods:{
    getAlert(){
      return this;
    }

  },
  render: h => h(App)
}).$mount('#app')

Answer №1

It may be a bit late for you to join the discussion now. However, you can still mount the app and attempt to access it through your Android webview code.

    const resumeApp = Vue.createApp({
  data() {
    return {
      resume: {
        ...resumeEN,
        address: [resumeEN.country, resumeEN.city, resumeEN.postalCode]
          .filter(Boolean)
          .join(", "),
        lang: lang,
      },
    };
  },
  methods: {
    changeLang: function (lang) {
      this.resume = resumeEN;
    },

    renderResumeDocument: function (jsonData) {
      this.resume = jsonData;
    },
  },
});

var mobileAppProxyObj = resumeApp.mount("#app");

When working from your Android web view:

  resumeViewerBinding.webViewResumeViewer.webViewClient = object : WebViewClient() {
            override fun onPageFinished(view: WebView?, weburl: String?) {
                resumeViewerBinding.webViewResumeViewer.loadUrl("javascript:mobileAppProxyObj.renderResumeDocument('Javascript function in webview')")
            }
        }

Answer №2

It seems like TypeScript might be causing the issue. Perhaps try using ES5 instead and test it out again.

Make sure you have included the Vue JS runtime in the HEAD section of your HTML as well.

Edit: To include Vue JS in your index.html, follow this example: (note the script tag inside the head section>

https://github.com/vuejs/vuejs.org/blob/master/src/v2/examples/vue-20-hello-world/index.html

<!DOCTYPE html>
<html>
<head>
  <title>My first Vue app</title>
  <script src="https://unpkg.com/vue"></script>
</head>
<body>
  <div id="app">
    {{ message }}
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue!'
      }
    })
  </script>
</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The opacity setting in THREE.ShaderMaterial is not functioning as intended

I've made the switch from MeshBasicMaterial to ShaderMaterial to implement filters on my mesh textures. While ShaderMaterial inherits from Material and includes an opacity parameter, changing this parameter doesn't seem to affect the object' ...

Inject the error into the Router in Express.js, utilizing Node.js

Is it possible to pass an error into an express.js Router? The express.js documentation does not provide a clear answer regarding passing errors in relation to middleware, routers, and error handling (I am unable to include links as I lack reputation). I ...

Having trouble with the JsonLoader copied from Threejs.org?

I've been trying to make use of a JSONLoader from threejs.org, but I'm facing some issues. Three.js seems to be functioning properly because I can easily create a cube. However, when I attempt to load a js file through the JSONLoader, nothing hap ...

Full-width sub menu within the menu

I'm trying to make a sub menu appear below my main menu that is the same width as the main menu, which has a fixed width. I want the sub menu to adjust its width based on the number of links it contains. Is this even possible? Here's the code I h ...

What is the best way to generate a fresh set of data from a search parameter?

I have received data from an API call that needs to be filtered. I am utilizing Redux instead of local state for this task. Below are the actions I have defined: import ActionTypes from '../constants/ActionTypes'; export const passengersDataAc ...

Manage image placement using CSS object-position

I have the following code snippet: img{ width: 100%; height: 1000px; object-fit: cover; object-position: left; } <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

The driver instance that has forked will never cease

Issues arise when attempting to run multiple browser windows in Protractor. The code snippet being tested is as follows: I create a new browser instance to perform certain tests. When input is entered into the original browser, it should not affect the ne ...

The cookie is not displaying in the web browser

Why are my cookies not showing in the browser? I have tried multiple times, but even though the backend is sending the cookie, it is not being stored in the browser. I have also attempted to use different browsers like Chrome and Microsoft Bing. In Postma ...

Accessing QML Functions from JavaScript

Currently, I am faced with a challenge in my app development using Qt. I need to trigger a QML function from JavaScript when a specific event is triggered from my HTML page. I attempted the following method: app.html <html> <head><title& ...

Transferring JavaScript files via Node server using NowJS

As someone new to Node, I need some help with a server-client web application I'm creating for a board game using Raphael for graphics. The issue I'm facing is that while the server successfully sends the HTML file in response to requests, the b ...

Is it possible to manipulate the attribute of an object using Object.defineProperty when a value is passed as a function parameter?

As I delve into understanding reactivity in Vue, the concept of how reactivity is achieved when passing a value as a function parameter perplexes me. //here is the actual code snippet var obj = {a: 'aa'} function reactive(obj, key, value) { ...

Is it possible to insert JavaScript code with the <link> element?

Is it possible to include JavaScript code using the <link> tag on my website? For instance, if I have a JavaScript file named test.js that includes the simple code alert('hello'); Can I trigger a popup window to appear by using the follow ...

Using jQuery to store the selection made in a select element option

Hello everyone, I need some help with saving the selected option on my form by the user. I am not sure how to accomplish this. Let me give you a brief overview of my setup... On my home page, I have a form that looks like this: <form class="form-home ...

Retrieve particular JSON information on a single webpage by selecting an element on a separate page

My goal is to fetch specific information from a JSON file and display it on different HTML pages by clicking a button. I will achieve this using jQuery and plain JS. For the first HTML page, I want to show all products from the JSON in an element with id= ...

jQuery Algorithm for calculating totals

Here is an algorithm for formatting amounts using jQuery: Visit jsfiddle for the code However, there are some issues. For instance, if I enter 900.800,00 and then delete the "9", it still displays 00.800,00. How can this be resolved? I have fixed severa ...

Tips for informing flowtype of expanding a partial options object to ensure it is fully developed by a specific stage

Most of you are probably familiar with a very simple use case from your projects. Imagine you have a utility class or function that looks like this: type Options = { foo?: string }; class Something { static get defaultOptions(): Options { ...

Displaying or concealing dropdown menus based on a selected option

My goal is to have a drop-down menu in which selecting an option triggers the display of another drop-down menu. For example, if I have options like "Vancouver," "Singapore," and "New York," selecting Vancouver will reveal a second set of options, while ch ...

Choose the ListView row instead of the individual item

I've encountered an issue with my listview where I need to tap on the item itself rather than just the row to select it. Is there a way to change this so that clicking on the row will select the item? Below is the code for my listview: ListView ...

Warning: React Element creation caution with flow-router integration

Whenever I incorporate the following code into my Meteor app: Home = FlowRouter.route("/", { name: "App", action(params) { ReactLayout.render(App); } }); An error message pops up in the Chrome console: Warning: React.createElement: type shoul ...

Updating Content in HTML Code Generated by JavaScript

My goal is to change the innerHTML of a div when it's clicked. I have an array of dynamically generated divs, and I want to target the specific table that the user clicks on. I attempted to set the IDs of the tables dynamically in my JavaScript code: ...