Interaction between Vue JS Webview and native Apps
Tags: vue, android, ios, webview
Published: 2021-04-25 14:07:33

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](https://cli.vuejs.org/).

After that we can create our project with this command:
```
vue create webview
```
 Now we can start to create our application.

 Here an example of the `MyWebview` component

```javascript
<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>
```

The first operation is add this method that native app Android or IOS can invoked to send some data:
```javascript
beforeMount(){
	window['MyWebview'] = {
		components:  this,
		pictureAcquired: (msg) =>  this.pictureAcquired(msg),
	};
}
```

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**.

```javascript
var  nativeApp;
function  pictureAcquired(msg) {
	window.MyWebview.pictureAcquired(msg);
}
```
```html
<!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>
```
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:
```javascript
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": {}}); 
}
```
**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
```
After that  inside the browser console we can see 
```javascript
	console.log("openCamera")
```
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:
```javascript
	pictureAcquired("pictureAcquired");
```
After that our application print on the browser console the changes of watcher:
```javascript
	new: Picture acquired, old:
```

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](https://github.com/alexiey91/Mywebview) with the **VueJS** project and a demo Android application I wrote for you all to test it.

Happy coding!