Java and JavaScript interaction instances in Android

  • 2020-06-12 10:36:09
  • OfStack

Android provides a powerful WebView control for handling Web web pages, and JavaScript is a very important script in web pages. This article shows you how to implement mutual calls between Java code and Javascript code.

How to implement

Realize Java and js interaction 10 minutes convenient. The following steps are usually all that are required.

1.WebView starts JavaScript script execution
2.WebView sets up the interaction interface for JavaScript to call.
3. The client and the web side write the code to call each other.

This example code

For the sake of explanation, post the entire code

Java code


package com.example.javajsinteractiondemo; import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast; public class MainActivity extends Activity {
  private static final String LOGTAG = "MainActivity";
  @SuppressLint("JavascriptInterface")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      final WebView myWebView = (WebView) findViewById(R.id.myWebView);
      WebSettings settings = myWebView.getSettings();
      settings.setJavaScriptEnabled(true);
      myWebView.addJavascriptInterface(new JsInteration(), "control");
      myWebView.setWebChromeClient(new WebChromeClient() {});
      myWebView.setWebViewClient(new WebViewClient() {           @Override
          public void onPageFinished(WebView view, String url) {
              super.onPageFinished(view, url);
              testMethod(myWebView);
          }
         
      });
      myWebView.loadUrl("file:///android_asset/js_java_interaction.html");
  }
 
  private void testMethod(WebView webView) {
      String call = "javascript:sayHello()";
     
      call = "javascript:alertMessage(\"" + "content" + "\")";
     
      call = "javascript:toastMessage(\"" + "content" + "\")";
     
      call = "javascript:sumToJava(1,2)";
      webView.loadUrl(call);
     
  }
 
  public class JsInteration {
     
      @JavascriptInterface
      public void toastMessage(String message) {
          Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
      }
     
      @JavascriptInterface
      public void onSumResult(int result) {
          Log.i(LOGTAG, "onSumResult result=" + result);
      }
  } }

Front-end web code


<html>
<script type="text/javascript">
    function sayHello() {
        alert("Hello")
    }     function alertMessage(message) {
        alert(message)
    }     function toastMessage(message) {
        window.control.toastMessage(message)
    }     function sumToJava(number1, number2){
       window.control.onSumResult(number1 + number2)
    }
</script>
Java-Javascript Interaction In Android
</html>

Invoke the sample

js call Java

The invocation format is ES44en.jsInterfaceName.methodName (parameterValues). In this case, we use control as the injection interface name.


function toastMessage(message) {
  window.control.toastMessage(message)
} function sumToJava(number1, number2){
   window.control.onSumResult(number1 + number2)
}

Java call JS

The basic format for webView to call js is ES60en.loadUrl (" javascript:methodName(parameterValues) ")

Call js's argument - free - return function


String call = "javascript:sayHello()";
webView.loadUrl(call);

Call js with arguments and no return value

Note that you need to escape double quotes for strings as parameter values.


String call = "javascript:alertMessage(\"" + "content" + "\")";
webView.loadUrl(call);

Call js a function with arguments and return values

Before 4.4, Android did not provide a method to directly call the js function and get the value, so before that, the common idea is that java calls the js method, and after the execution of the js method, the java code is called again to return the value.

Java calls the js code


String call = "javascript:sumToJava(1,2)";
webView.loadUrl(call);

2. The js function handles it and returns the result by calling the java method


function sumToJava(number1, number2){
       window.control.onSumResult(number1 + number2)
}

3.Java gets the return value of the js function in the callback method


@JavascriptInterface
public void onSumResult(int result) {
  Log.i(LOGTAG, "onSumResult result=" + result);
}

4.4 processing

Android 4.4 is followed by evaluateJavascript. Here is a simple interaction example of an js method with a return value


function getGreetings() {
      return 1;
}

java code is called with the evaluateJavascript method


private void testEvaluateJavascript(WebView webView) {
  webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {   @Override
  public void onReceiveValue(String value) {
      Log.i(LOGTAG, "onReceiveValue value=" + value);
  }});
}

The output


I/MainActivity( 1432): onReceiveValue value=1

Pay attention to

1. The above qualified result return result is String, for simple types will try to convert to string return, for complex data types, it is recommended to return json as a string.
2. The evaluateJavascript method must be called on the UI thread (the main thread), so onReceiveValue also executes on the main thread.

Question answer

Alert cannot pop out

You should not have set WebChromeClient, as follows


myWebView.setWebChromeClient(new WebChromeClient() {});
Uncaught ReferenceError: functionName is not defined

The reason for the problem is that the js method is called before the page's js code is loaded. The solution is to call the js method after the page has loaded


myWebView.setWebViewClient(new WebViewClient() {   @Override
  public void onPageFinished(WebView view, String url) {
      super.onPageFinished(view, url);
      // Execute what you want to call here js function
  }
 
});

Uncaught TypeError: Object [object Object] has no method

Safety restriction problem

If only a machine older than 4.2 has a problem, then the system is in a security limit. The Android document says so


Caution: If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.

Chinese main idea is

Warning: If your application targets platform is 17 Or even higher, you have to add to the method that is exposed to the web page (the method must be public) @JavascriptInterface The comments. If you don't, yes 4.2 On future platforms, web pages cannot access your method.

The solution

1. Set targetSdkVersion to 17 or higher and introduce the @JavascriptInterface annotation
2. Create your own annotation interface named @JavascriptInterface and bring it in. Note that this interface should not be confused. This approach is not recommended and is probably problematic after 4.4.

Note, create @JavascriptInterface code


public @interface JavascriptInterface { }

Code confusion problem

If it works well in the non-obturated version and the code in the obturated version runs incorrectly and says Uncaught TypeError: Object [object Object] has no method, then you are not making a obturation exception. Add code like this in the obfuscation file


-keep class com.example.javajsinteractiondemo$JsInteration {
    *;
}

All WebView methods must be called on the same thread

Filtering logs have found this problem.


E/StrictMode( 1546): java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {528712d4} called on Looper (JavaBridge, tid 121) {52b6678c}, FYI main Looper is Looper (main, tid 1) {528712d4})
E/StrictMode( 1546):   at android.webkit.WebView.checkThread(WebView.java:2063)
E/StrictMode( 1546):   at android.webkit.WebView.loadUrl(WebView.java:794)
E/StrictMode( 1546):   at com.xxx.xxxx.xxxx.xxxx.xxxxxxx$JavaScriptInterface.onCanGoBackResult(xxxx.java:96)
E/StrictMode( 1546):   at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
E/StrictMode( 1546):   at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
E/StrictMode( 1546):   at android.os.Handler.dispatchMessage(Handler.java:102)
E/StrictMode( 1546):   at android.os.Looper.loop(Looper.java:136)
E/StrictMode( 1546):   at android.os.HandlerThread.run(HandlerThread.java:61)

The Java callback thread after the js call is not the main thread. Such as print log can be verified


<html>
<script type="text/javascript">
    function sayHello() {
        alert("Hello")
    }     function alertMessage(message) {
        alert(message)
    }     function toastMessage(message) {
        window.control.toastMessage(message)
    }     function sumToJava(number1, number2){
       window.control.onSumResult(number1 + number2)
    }
</script>
Java-Javascript Interaction In Android
</html>
8

To resolve the above exception, place the webview operation in the main thread.


<html>
<script type="text/javascript">
    function sayHello() {
        alert("Hello")
    }     function alertMessage(message) {
        alert(message)
    }     function toastMessage(message) {
        window.control.toastMessage(message)
    }     function sumToJava(number1, number2){
       window.control.onSumResult(number1 + number2)
    }
</script>
Java-Javascript Interaction In Android
</html>
9


Related articles: