DEV Community

Cover image for Interaction between Vue JS Webview and native Apps
Alessandro Valenti
Alessandro Valenti

Posted on • Edited on

Interaction between Vue JS Webview and native Apps

Hi everybody! I want to show you how to implement a simple interaction between VueJs webview and native Apps and vice-versa.

Introduction

During my job I need to create some webview and make some interaction with native Android and iOS App.

I did it with some javascript function to send some message and manage it to make some operation.
During this article, we develop an interaction to open native Camera and comeback from native app to webview.
The javascript function that we develop is it:

  • openCamera
  • pictureAcquired

So let's start.

Web view Vue Js

Before we start you need to install Vue Js on your environment, I advise seeing the documentation at this site VueJs.

After that we can create our project with this command:

vue create webview
Enter fullscreen mode Exit fullscreen mode

Now we can start to create our application.

Here an example of the MyWebview component

<template>
    <div  class="hello">
        <h1>My Webview</h1>
        <p>Response app</p>
        <h3>{{msg}}</h3>
        <button type="button" class="btn btn-expand btn-primary" @click="next()">Open Camera</button>
    </div>
</template>

<script>
import * as appService from '../appService.js'
export default {
    name:  'MyWebview',
    props: {
        msg:  ""
        },
    },
    data(){
        return{
            msg:""
        }
    },
    methods:{
        pictureAcquired(msg){
            console.log("msg",msg);
            this.msg = msg;
        },
        next(){
            appService.openCamera();
        },
    mounted(){ 
    },
    watch:{
        msg:  function (msgNew, msgOld) {
            console.log('new: %s, old: %s', msgNew, msgOld)
        },
    },
    beforeMount(){
    //Create interface between Webview and Native application
        window['MyWebview'] = {
            components:  this,
            pictureAcquired: (msg) =>  this.pictureAcquired(msg),
        };
    }
};
</script> 
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style  scoped>
h3 {
    margin: 40px  0  0;
}
ul {
    list-style-type: none;
    padding: 0;
}
li {
    display: inline-block;
    margin: 0  10px;
}
a {
    color: #42b983;
}
</style>
Enter fullscreen mode Exit fullscreen mode

The first operation is add this method that native app Android or IOS can invoked to send some data:

beforeMount(){
    window['MyWebview'] = {
        components:  this,
        pictureAcquired: (msg) =>  this.pictureAcquired(msg),
    };
}
Enter fullscreen mode Exit fullscreen mode

It's important to create a page inside a javascript window with the name of the component that you want to link with a native app and add the function for the interaction. Note that it's important to add this event during beforeMount() VueJs lifecycle because it is necessary to expose it before the creation of components inside the webview.
This operation is not enough we need to create an interface inside a javascript file and import it inside the index.html file. We call it native.js.

var  nativeApp;
function  pictureAcquired(msg) {
    window.MyWebview.pictureAcquired(msg);
}
Enter fullscreen mode Exit fullscreen mode
<!DOCTYPE  html>
<html  lang="">
<head>
<meta  charset="utf-8">
<meta  http-equiv="X-UA-Compatible"  content="IE=edge">
<meta  name="viewport"  content="width=device-width,initial-scale=1.0">
<link  rel="icon"  href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<script  type="text/javascript"  src="<%= BASE_URL %>external_resource/native.js"></script>
</head>
<body>
<div  id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

After that i you want to create an interaction from webview to native app you need to define a method inside the VueJs component that invoked a method inside appService.js file like that:

export  function  openCamera(){
    console.log("openCamera")
    // Call to Android App
    if (window.nativeApp) window.nativeApp.funnelReady();
    // Call to IOS App
    else  if ((window['webkit']) && ( window['webkit'].messageHandlers) && (( window['webkit'].messageHandlers.nativeApp))) window['webkit'].messageHandlers.nativeApp.postMessage({"openCamera": {}}); 
}
Enter fullscreen mode Exit fullscreen mode

openCamera() define two types of interaction with Android and IOS native device because these two Operating Systems have a different interaction with webview. Everybody had the same connection point the name of javascript interface that defines the interaction point between webview and native app. This interface in this example is nativeApp but it should be named as you want but it must be the same inside the native Application.

Testing

Now we can test our application and enjoy it.
So we can start the application with simple npm command on the projects main root :

npm run serve
Enter fullscreen mode Exit fullscreen mode

After that inside the browser console we can see

    console.log("openCamera")
Enter fullscreen mode Exit fullscreen mode

So our application calls the native app javascript and function.
Now we can emulate the response of the native application typing inside the browser console this:

    pictureAcquired("pictureAcquired");
Enter fullscreen mode Exit fullscreen mode

After that our application print on the browser console the changes of watcher:

    new: Picture acquired, old:
Enter fullscreen mode Exit fullscreen mode

I hope you'll enjoy this article. A special thanks goes to my team-mates for their precious advice.

For additional details about the code listed in this article, here's the link to the repository with the VueJS project and a demo Android application I wrote for you all to test it.

Happy coding!

Top comments (3)

Collapse
 
bomnamu profile image
applepine

Thank you!! it helps me a lot!!

Collapse
 
gabmen profile image
gabmen

Thank you !

Collapse
 
franke92 profile image
franke92

👏👏👏🚀🚀 Good job!