The most comprehensive summary of how Android WebView interacts with JS

Keywords: Android Javascript Java

Preface

  • Now many Apps have built-in Web pages (Hyprid App), such as many e-commerce platforms, Taobao, Jingdong, Cost-effective, and so on, such as the following image

  • These functions are implemented by Android's WebView, which involves the implementation of Android client interaction with Web pages
  • Today I'll give you a full overview of how Android interacts with JS through WebView

Read this before reading: Android development: the most comprehensive and understandable Web view in detail

Catalog

1. Interactive Summary

Android Calling methods with JS through WebView is actually:

  • Code for Android to invoke JS
  • JS to call Android's code

The bridge between them is WebView

There are two ways for Android to call JS code:
1. loadUrl () through WebView
2. evaluateJavascript () via WebView

There are three ways for JS to call Android code:
1. Object mapping via WebView's addJavascriptInterface ()
2. Intercept URLs via the WebViewClient shouldOverrideUrlLoading () method callback
3. Intercept JS dialog alert(), confirm(), prompt() messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt() method callbacks

2. Specific analysis

2.1 Android calls JS code through WebView

There are two ways for Android to call JS code:

  1. loadUrl () through WebView
  2. evaluateJavascript () via WebView

Mode 1: Load Url () through WebView

  • Example description: Click the Android button to call JS () in WebView JS (text name is javascript)
  • Specific use:

Step 1: Place the JS code you need to invoke in the src/main/assets folder in.html format

  1. For demonstration purposes, this article uses Andorid to call local JS code instructions;
  2. As a matter of fact, Android calls more remote JS code by changing the path of the loaded JS code to a url.

JS code needs to be loaded: javascript.html

// Text name: javascript
<!DOCTYPE html>
<html>

   <head>
      <meta charset="utf-8">
      <title>Carson_Ho</title>

// JS Code
     <script>
// Method Android needs to call
   function callJS(){
      alert("Android Called JS Of callJS Method");
   }
</script>

   </head>

</html>

Step 2: Call JS code in Android through WebView settings

Android code: MainActivity.java

The comment is already clear

 public class MainActivity extends AppCompatActivity {

    WebView mWebView;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView =(WebView) findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();

        // Set permissions to interact with Js
        webSettings.setJavaScriptEnabled(true);
        // Set Allow JS Pop-up
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

        // Load JS code first
        // The format is specified as file:///android_asset/filename.html
        mWebView.loadUrl("file:///android_asset/javascript.html");

        button = (Button) findViewById(R.id.button);


        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // JS method calls must be made on a separate thread (otherwise they cannot be called)
                mWebView.post(new Runnable() {
                    @Override
                    public void run() {

                        // Note that the JS method name called should correspond to the
                        // Call the callJS() method of javascript
                        mWebView.loadUrl("javascript:callJS()");
                    }
                });

            }
        });

        // The js dialog box needs to be supported because the pop-up window check call result is set
        // webview is just a carrier, and the rendering of content needs to be done using the webviewChromClient class
        // Processing JavaScript dialogs by setting WebChromeClient objects
        //Set Alert() function in response to js
        mWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);
                b.setTitle("Alert");
                b.setMessage(message);
                b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                });
                b.setCancelable(false);
                b.create().show();
                return true;
            }

        });


    }
}

Special note: JS code calls must be made after the onPageFinished () callback, otherwise they will not be called.

onPageFinished() is a method of the WebViewClient class that is called primarily at the end of page loading

Mode 2: evaluateJavascript () through WebView

  • Advantages: This method is more efficient and concise than the first method.

    1. Because this method does not refresh the page, the first method (loadUrl) does.
    2. Android 4.4 is not available until
  • Specific use

// Simply replace the loadUrl() of the first method with the following method
    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            //Here is the result returned for js
        }
    });
}
  • 8

2.1.2 Method Comparison

2.1.3 Use Recommendations

Mixed use of the two methods, that is, Android 4.4 below method 1, Android 4.4 above method 2

// Android Version Variable
final int version = Build.VERSION.SDK_INT;
// Since this method is available in Android version 4.4, version judgment is required when using it
if (version < 18) {
    mWebView.loadUrl("javascript:callJS()");
} else {
    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            //Here is the result returned for js
        }
    });
}

2.2 JS calls Android code through WebView

There are three ways for JS to call Android code:
1. Object mapping via WebView's addJavascriptInterface ()
2. Intercept URLs via the WebViewClient shouldOverrideUrlLoading () method callback
3. Intercept JS dialog alert(), confirm(), prompt() messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt() method callbacks

2.2.1 Method Analysis

Mode 1: Object mapping via WebView's addJavascriptInterface ()

Step 1: Define an Android class that maps to JS objects: AndroidtoJs

AndroidtoJs.java (comment is already clear)

// Inherit from Object class
public class AndroidtoJs extends Object {

    // Define the method JS needs to call
    // Methods invoked by JS must be annotated with @JavascriptInterface
    @JavascriptInterface
    public void hello(String msg) {
        System.out.println("JS Called Android Of hello Method");
    }
}

Step 2: Place the JS code you need to call in the src/main/assets folder in.html format

JS code needs to be loaded: javascript.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <title>Carson</title>  
      <script>


         function callAndroid(){
        // Because of the object mapping, calling the test object is equal to calling the Android mapping object
            test.hello("js Called android In hello Method");
         }
      </script>
   </head>
   <body>
      //Click the button to call the callAndroid function
      <button type="button" id="button1" onclick="callAndroid()"></button>
   </body>
</html>

Step 3: Set up the mapping of Android classes to JS code in Android through WebView

See notes for more details

public class MainActivity extends AppCompatActivity {

    WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView) findViewById(R.id.webview);
        WebSettings webSettings = mWebView.getSettings();

        // Set permissions to interact with Js
        webSettings.setJavaScriptEnabled(true);

        // Mapping Java objects to JS objects via addJavascriptInterface()
        //Parameter 1: Javascript object name
        //Parameter 2: Java object name
        mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS class object maps to js test object

        // Load JS code
        // The format is specified as file:///android_asset/filename.html
        mWebView.loadUrl("file:///android_asset/javascript.html");

Characteristic

Mode 2: Intercept url through WebViewClient's method shouldOverrideUrlLoading () callback

  • Specific principles:

    1. Android intercepts URLs via WebViewClient's callback method shouldOverrideUrlLoading ()
    2. Protocol for resolving the url
    3. If a pre-agreed protocol is detected, the corresponding method is called

    That is, JS needs to call Android's method

  • Specific use:
    Step 1: Url protocol required in the JS Convention
    JS code: javascript.html

    Place in the src/main/assets folder in.html format

<!DOCTYPE html>
<html>

   <head>
      <meta charset="utf-8">
      <title>Carson_Ho</title>

     <script>
         function callAndroid(){
            /*The agreed url protocol is: js://webview?Arg1=111&arg2=222*/
            document.location = "js://webview?arg1=111&arg2=222";
         }
      </script>
</head>

<!-- Click the button to invoke callAndroid()Method  -->
   <body>
     <button type="button" id="button1" onclick="callAndroid()">Click Call Android Code</button>
   </body>
</html>

When the JS is loaded through Android's mWebView.loadUrl("file:///android_asset/javascript.html"), it calls back shouldOverrideUrlLoading(), and then proceeds to step 2:

Step 2: Replicate shouldOverrideUrlLoading () from WebViewClient on Android

MainActivity.java

public class MainActivity extends AppCompatActivity {

    WebView mWebView;
//    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView) findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();

        // Set permissions to interact with Js
        webSettings.setJavaScriptEnabled(true);
        // Set Allow JS Pop-up
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

        // Step 1: Load JS code
        // The format is specified as file:///android_asset/filename.html
        mWebView.loadUrl("file:///android_asset/javascript.html");


// Override the shouldOverrideUrlLoading method of the WebViewClient class
mWebView.setWebViewClient(new WebViewClient() {
                                      @Override
                                      public boolean shouldOverrideUrlLoading(WebView view, String url) {

                                          // Step 2: Determine if the required url is based on the parameters of the protocol
                                          // Generally based on scheme & authority (protocol name) (first two parameters)
                                          //Assume that the incoming url = "js://webview?Arg1=111&arg2=222" (which is also agreed to require interception)

                                          Uri uri = Uri.parse(url);                                 
                                          // If the url's protocol = the pre-agreed js protocol
                                          // Parse parameters down
                                          if ( uri.getScheme().equals("js")) {

                                              // If authority = webview in a pre-agreed agreement, that is, agreement that represents compliance with the agreement
                                              // So intercept url, the JS below starts calling the methods Android needs
                                              if (uri.getAuthority().equals("webview")) {

                                                 //  Step 3:
                                                  // Logic to invoke to execute JS
                                                  System.out.println("js Called Android Method");
                                                  // Can take parameters on the protocol and pass them to Android
                                                  HashMap<String, String> params = new HashMap<>();
                                                  Set<String> collection = uri.getQueryParameterNames();

                                              }

                                              return true;
                                          }
                                          return super.shouldOverrideUrlLoading(view, url);
                                      }
                                  }
        );
   }
        }

Characteristic

  • Advantages: There is no vulnerability in Mode 1;
  • Disadvantage: The return value of the JS Get Android method is complex.
    If the JS wants to get the return value of the Android method, it can only pass the return value back through the loadUrl() of WebView, as follows:
// Android: MainActivity.java
mWebView.loadUrl("javascript:returnResult(" + result + ")");

// JS: javascript.html
function returnResult(result){
    alert("result is" + result);
}

Mode 3: Intercept JS dialog alert(), confirm(), prompt () messages via WebChromeClient onJsAlert(), onJsConfirm(), onJsPrompt () method callbacks

There are three common dialog box methods in JS:

Principle of Mode 3: Android intercepts JS dialog boxes through WebChromeClient onJsAlert(), onJsConfirm(), and onJsPrompt () method callbacks, respectively
(that is, the three methods above), get their message content, and then parse it.

The following example illustrates using an input box (prompt() method) that intercepts JS:

  1. The common interception is to intercept the JS input box (prompt() method)
  2. Because only prompt () can return any type of value, it is the most comprehensive and flexible operation; the alert () dialog does not return a value; the confirm () dialog can only return two states (OK/Cancel) with two values.

Step 1: Load the JS code as follows:
javascript.html

Place in the src/main/assets folder in.html format

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <title>Carson_Ho</title>

     <script>

    function clickprompt(){
    // Call prompt()
    var result=prompt("js://demo?arg1=111&arg2=222");
    alert("demo " + result);
}

      </script>
</head>

<!-- Click the button to invoke clickprompt()  -->
   <body>
     <button type="button" id="button1" onclick="clickprompt()">Click Call Android Code</button>
   </body>
</html>

When the above JS code is loaded using mWebView.loadUrl("file:///android_asset/javascript.html"), the callback onJsPrompt() is triggered as follows:

  1. If the warning box is intercepted (alert()), the callback onJsAlert() is triggered;
  2. If the confirmation box is intercepted (confirm()), the callback onJsConfirm () is triggered;

Step 2: Replicate onJsPrompt() via WebChromeClient on Android

public class MainActivity extends AppCompatActivity {

    WebView mWebView;
//    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView) findViewById(R.id.webview);

        WebSettings webSettings = mWebView.getSettings();

        // Set permissions to interact with Js
        webSettings.setJavaScriptEnabled(true);
        // Set Allow JS Pop-up
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

// Load JS code first
        // The format is specified as file:///android_asset/filename.html
        mWebView.loadUrl("file:///android_asset/javascript.html");


        mWebView.setWebChromeClient(new WebChromeClient() {
                                        // Intercept Input Box (same way 2)
                                        // Parameter message: Content representing promt() (not url)
                                        // Parameter result: Represents the return value of the input box
                                        @Override
                                        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                                            // Determine if the required URL is based on the parameters of the protocol (same principle as mode 2)
                                            // Generally based on scheme & authority (protocol name) (first two parameters)
                                            //Assume that the incoming url = "js://webview?Arg1=111&arg2=222" (which is also agreed to require interception)

                                            Uri uri = Uri.parse(message);
                                            // If the url's protocol = the pre-agreed js protocol
                                            // Parse parameters down
                                            if ( uri.getScheme().equals("js")) {

                                                // If authority = webview in a pre-agreed agreement, that is, agreement that represents compliance with the agreement
                                                // So intercept url, the JS below starts calling the methods Android needs
                                                if (uri.getAuthority().equals("webview")) {

                                                    //
                                                    // Logic to invoke to execute JS
                                                    System.out.println("js Called Android Method");
                                                    // Can take parameters on the protocol and pass them to Android
                                                    HashMap<String, String> params = new HashMap<>();
                                                    Set<String> collection = uri.getQueryParameterNames();

                                                    //Parameter result: Represents the return value of the message box (input value)
                                                    result.confirm("js Called Android The method succeeded");
                                                }
                                                return true;
                                            }
                                            return super.onJsPrompt(view, url, message, defaultValue, result);
                                        }

// Interception by alert() and confirm() works the same way, but we won't go into much detail here

                                        // Warning box to intercept JS
                                        @Override
                                        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                                            return super.onJsAlert(view, url, message, result);
                                        }

                                        // Confirmation box to intercept JS
                                        @Override
                                        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
                                            return super.onJsConfirm(view, url, message, result);
                                        }
                                    }
        );


            }

        }

2.2.2 Comparison of three modes - using scenes

3. Summary

  • This article gives an overview of how Android interacts with JS through WebView.
  • Next, I'll continue with other Android developments, and I'm interested in continuing to focus on them Carson_Ho's Android Development Notes!!!!

Posted by predator12341 on Sun, 14 Jul 2019 09:03:28 -0700