Search code examples
javascriptandroidcordovaandroid-webviewphonegap

Android - How to use Javascript in an Android WebView?


I have a problem in my Hybrid Android App.I need to have a WebView with an HTML and in this HTML I have a button.

I have a layout with a WebView and I have a button inside the HTML, I'm trying to launch a second Activity with another screen(also a layout with a WebView) when the user click this button.

My problem is that this button is not launching the second activity.

I'm using Cordova.

This is my layout(pruebas.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<WebView
    android:id="@+id/webview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_below="@+id/textView" />

</LinearLayout>

This is my MainActivity.java:

public class MainActivity extends CordovaActivity{

    WebView wv;

    JavaScriptInterface JSInterface;

    @Override
    public void onCreate(Bundle savedInstanceState){

        super.onCreate(savedInstanceState);

        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());

        setContentView(R.layout.pruebas);
        wv = (WebView)findViewById(R.id.webview);

        wv.getSettings().setJavaScriptEnabled(true);
        wv.getSettings().setDomStorageEnabled(true);
        // register class containing methods to be exposed to JavaScript

        JSInterface = new MainActivity.JavaScriptInterface(this);
        wv.addJavascriptInterface(JSInterface, "JSInterface");

        wv.loadUrl("file:///android_asset/www/description.html");

    }

    public class JavaScriptInterface {
        Context mContext;

        /** Instantiate the interface and set the context */
        JavaScriptInterface(Context c) {
            mContext = c;
        }

        @android.webkit.JavascriptInterface
        public void changeActivity(){
            Intent i = new Intent(MainActivity.this, JavascriptInterfaceActivity.class);
            i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            finish();
        }
    }
}

And this is my second activity (JavascriptInterfaceActivity.java):

public class JavascriptInterfaceActivity extends Activity {

    WebView wv;

    JavaScriptInterface JSInterface;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());

        setContentView(R.layout.pruebas);
        wv = (WebView)findViewById(R.id.webview);

        wv.getSettings().setJavaScriptEnabled(true);
        wv.getSettings().setDomStorageEnabled(true);

        JSInterface = new JavaScriptInterface(this);
        wv.addJavascriptInterface(JSInterface, "JSInterface");

        wv.loadUrl("file:///android_asset/www/description-long.html");

    }


    public class JavaScriptInterface {
        Context mContext;

        /** Instantiate the interface and set the context */
        JavaScriptInterface(Context c) {
            mContext = c;
        }

        @android.webkit.JavascriptInterface
        public void changeActivity(){
            Intent i = new Intent(JavascriptInterfaceActivity.this, MainActivity.class);
            i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            finish();
        }
    }
}

This is the description.html, the other HTML (description-long.html) is similar:

<!DOCTYPE html>
<html>
<head>
    <script src='changeactivity.js'></script>

    <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
    <meta name="format-detection" content="telephone=no">
    <meta name="msapplication-tap-highlight" content="no">
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
    <link rel="stylesheet" type="text/css" href="css/index.css">
    <title>Main activity</title>
</head>
<body>
<button id='changeactivity'>Changue activity</button>
</body>
</html>

This is my changeactivity.js file in assets/www:

 function displaymessage(){
     JSInterface.changeActivity();
 }

 document.addEventListener('DOMContentReady', function () {
         document.getElementById('changeactivity').addEventListener('click', displaymessage);
 });

Any suggestion? I check these posts:

https://stackoverflow.com/a/10481108/3739382

https://stackoverflow.com/a/31631068/3739382


Solution

  • Based on the Binding JavaScript documentation

    Note: The object that is bound to your JavaScript runs in another thread and not in the thread in which it was constructed.

    You are starting the activity on non-UI thread. You should run it on UI thread as follows:

    @android.webkit.JavascriptInterface
        public void changeActivity(){
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                     Intent i = new Intent(MainActivity.this, JavascriptInterfaceActivity.class);
                     i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                     startActivity(i);
                     finish();
                }
            });
    
        }
    

    Alternatively you can also use Handler.