Tuesday, July 09, 2013

Calling Activity Method From JavaScript in Webview Android (vise-versa)

Hi everyone, Few days back I am looking for a solution to get access the html form submit data into native Android. Suppose when you have criteria to load the HTML form server or local into Webview and you want to invoke some REST request to submit this form data with additional info or to notify native regarding this form submission.

 After some Googling I found this addJavaScriptInterface method in Android. Facilitate developer to  call Activity method inside from javascript function and vise-versa.

Click here to read get the background and detail of this addJavaScriptInterface method of Webview.

Hands on Code:
I am going to use an ItelliJ IDEA IDE and I suppose that you have some experience in Android development using the ItelliJ IDE. if you it simple just download Community Edition FREE from here and move a head.

Create Simple Project.

Define Activity Name and project package.


Create the html file in assets folder name it sample.html. Copy and paste the below code into this file.

 <html>  
 <head>  
   <link rel="stylesheet" type="text/css" href="style.css"/>  
   <script type="text/javascript">  
     function bar(data){  
     var obj = eval ("(" + data + ")");  
     var html = "<p><b>Data received</b><br>"+  
       "<br>Name: <span>"+obj.cs_name+"</span><br>"+  
       "City: <span >"+obj.cs_city+"</span><br>"+  
       "Phone: <span>"+obj.cs_phone+"</span><br>"+  
       "Address: <span >"+obj.cs_address+"</span></p>";  
     var x=document.getElementById("te");  
       <!--x.innerHTML = "<p>"+ message+"</p>";-->  
     x.innerHTML = html;  
     }  
     function foo(){  
     var txt_cs_name = document.getElementById("txt_cs_name").value;  
     var txt_cs_phone = document.getElementById("txt_cs_phone").value;  
     var txt_cs_city = document.getElementById("txt_cs_city").value;  
     var txt_cs_address = document.getElementById("txt_cs_address").value;  
     var dataObj = new Object();  
     dataObj.cs_name = txt_cs_name;  
     dataObj.cs_phone = txt_cs_phone;  
     dataObj.cs_city = txt_cs_city;  
     dataObj.cs_address = txt_cs_address;  
     var jsonObj = JSON.stringify(dataObj);  
     /* NOTE: Calling Activity Method using the Activity defined 
        instance "android" in JavaScript */
     android.TestMethod(jsonObj); 
     }  
   </script>  
 </head>  
 <body>  
 <div id="te" ></div>  
 <div>  
   <form id="form1">  
     <table width="100%" class="mytable">  
       <tr>  
         <td>Name</td>  
       </tr>  
       <tr>  
         <td><input type="text" id="txt_cs_name" ></td>  
       </tr>  
       <tr>  
         <td>Phone</td>  
       </tr>  
       <tr>  
         <td><input type="text" id="txt_cs_phone" ></td>  
       </tr>  
       <tr>  
         <td>City</td>  
       </tr>  
       <tr>  
         <td><input type="text" id="txt_cs_city" ></td>  
       </tr>  
       <tr>  
         <td>Address</td>  
       </tr>  
       <tr>  
         <td><textarea id="txt_cs_address"> </textarea></td>  
       </tr>  
     </table>  
   </form>  
 </div>  
 <button onClick="foo()"> Submit</button>  
 </body>  
 </html>  

This html file has a two javascript function
  1. foo() This function calls the activity method.
  2. bar(data) This function calls from the activity method with parameters.
Below is the foo() function line invokes the activity method.
 
android.TestMethod(jsonObj);

Now create the Activity part as we already create through wizard, it time to setup TestMethod in activity for javascript invoking.

 package com.example.WebviewExample;  
 import android.app.Activity;  
 import android.os.Bundle;  
 import android.webkit.JavascriptInterface;  
 import android.webkit.WebView;  
 import android.widget.Toast;  
 import org.json.JSONException;  
 import org.json.JSONObject;  
 public class MyActivity extends Activity {  
   private WebView wv;  
   // the method to call from the html button click  
   @JavascriptInterface  
   public void TestMethod(String formData) {  
     System.out.println("TestMethod FormData " + formData);  
     try {  
       JSONObject jsonData = new JSONObject(formData);  
     } catch (JSONException e) {  
       e.printStackTrace();  
     }  
     wv.loadUrl("javascript:bar('" + formData + "');");  
     Toast.makeText(getApplicationContext(), formData, 5000).show();  
   }  
   @Override  
   public void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.main);  
     wv = (WebView) this.findViewById(R.id.web_view1);  
     // requires javascript  
     wv.getSettings().setJavaScriptEnabled(true);  
     // make this activity accessible to javascript  
     wv.addJavascriptInterface(this, "android");
     // set the html view to load sample.html
     wv.loadUrl("file:///android_asset/sample.html");  
     
   }  
 }  

The onCreate method simply initialize Webview with layout which has only Webview declared with id web_view1 inside After initialization we call Webview settings to enable the JavaScript.
 
wv.getSettings().setJavaScriptEnabled(true); 
and in the next line calling another addJavascriptInterface Webview method.
 
wv.addJavascriptInterface(this, "android"); 
it accept two parameters one is class instance to bind to JavaScript and the second one is used to define instance name to expose and use in JavaScript and finally we call/load our sample.html file in Webview.

The TestMethod method annotated with JavascriptInterface this means that this method can be accessed from JavaScript this method simply calling javascript function "bar" using Webview loadUrl method
 
 wv.loadUrl("javascript:bar('" + formData + "');");   
and also show the result in Toast as well.

Testing Time:

1 comment:

Samra Faraz said...

Hi Saifuddin, your blog was really helpful, but i m stuck midway here. I am building a hybrid app and What I want to do is Launch Activity on my menu.html page load.
So, I have added webview in the native app, and added all code from your onCreate() function. Now when i go to menu.js, it does not recognize my "android" webview attribute set. can you guide what am i missing here?