Detailed explanation of Android WebView (2): Intermodulation between Android native and JS

Android to call JS code

  • Via WebView's loadUrl()

    First write an html, a very simple code, alert display.

    android_load_js.html

      <!DOCTYPE html>
      <html>
         <head>
            <meta charset="utf-8">
            <title>Android调用 JS 代码demo</title>
      // JS代码
           <script>
             // Android需要调用的方法
             function callJS(){
                alert("Android调用了JS的callJS方法");
             }
          </script>
         </head>
      </html>
    

    in Activity

      mWebSettings = mWebview.getSettings();
      //与JS交互开关
      mWebSettings.setJavaScriptEnabled(true);
      //设置允许JS弹窗	    
      mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
      mWebview.loadUrl("file:///android_asset/android_load_js.html");
    
      //在这我用了一个TextView 点击事件中去调用JS中的方法
      beginLoading.setOnClickListener(new View.OnClickListener() {
          [@Override](https://my.oschina.net/u/1162528)
          public void onClick(View view) {
              //执行JS方法
        		mWebview.loadUrl("javascript:callJS()");
          }
      });
    
    
      mWebview.setWebChromeClient(new WebChromeClient() {
          //获取网站标题
          [@Override](https://my.oschina.net/u/1162528)
          public void onReceivedTitle(WebView view, String title) {
              System.out.println("标题在这里");
              mtitle.setText(title);
          }
    
          //获取加载进度
          [@Override](https://my.oschina.net/u/1162528)
          public void onProgressChanged(WebView view, int newProgress) {
              if (newProgress < 100) {
                  String progress = newProgress + "%";
                  loading.setText(progress);
              } else if (newProgress == 100) {
                  String progress = newProgress + "%";
                  loading.setText(progress);
              }
          }
    
      	//由于设置了弹窗检验调用结果,所以需要支持js对话框
          //webview只是载体,内容的渲染需要使用webviewChromClient类去实现
          //通过设置WebChromeClient对象处理JavaScript的对话框
          //设置响应js 的Alert()函数
          [@Override](https://my.oschina.net/u/1162528)
          public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
              AlertDialog.Builder b = new AlertDialog.Builder(TestActivity.this);
              b.setTitle("Alert");
              b.setMessage(message);
              b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                  [@Override](https://my.oschina.net/u/1162528)
                  public void onClick(DialogInterface dialog, int which) {
                      result.confirm();
                  }
              });
              b.setCancelable(false);
              b.create().show();
              return true;
          }
      });
    
  • Via WebView's evaluateJavascript()

    This method is more efficient than the first method, because the execution of this method does not cause the page to refresh, while the execution of the first method (loadUrl) does. This method is only available after Android 4.4, this method is executed on the main thread

      //将上面webView.loadUrl("javascript:callJS()")替换为
      mWebview.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
          @Override
          public void onReceiveValue(String value) {
              //此处为 js 返回的结果
          }
      });	
    

    Compatibility can be done:

       if (Build.VERSION.SDK_INT > 18) {
          mWebview.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
              @Override
              public void onReceiveValue(String value) {
                  //此处为 js 返回的结果
              }
          });
      } else {
          mWebview.loadUrl("javascript:callJS()");
      }
    

JS to call Android code

  • Object mapping through WebView's addJavaScriptInterface()

    html

      <!DOCTYPE html>
      <html>
         <head>
            <meta charset="utf-8">
            <title>DEMO</title>
            <script>
               function callAndroid(){
              // 由于对象映射,所以调用test对象等于调用Android映射的对象
                  test.showLog("js调用了android中的hello方法");
               }
            </script>
         </head>
         <body>
            //点击按钮则调用callAndroid函数
            <button type="button" id="button1" onclick="callAndroid()" text="Android"></button>
         </body>
      </html>
    

    mapped code

      package org.professor.procartoon.temp;
    
      import android.webkit.JavascriptInterface;
    
      import org.professor.procartoon.utils.LogUtils;
    
      /**
       * Created by Caipeng on 2018.02.06.
       */
      public class JSObject {
    
      	/**
      	 * 定义JS需要调用的方法被JS调用的方法必须加入@JavascriptInterface注解
      	*/
          @JavascriptInterface
          public void showLog(String text) {
              LogUtils.i(text);
          }
      }
    

    Test code in Activity

      mWebSettings.setJavaScriptEnabled(true);
      mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
      //通过addJavascriptInterface()将Java对象映射到JS对象
      //参数1:Javascript对象名
      //参数2:Java对象名
      mWebview.addJavascriptInterface(new JSObject(),"test");
      mWebview.loadUrl("file:///android_asset/android_load_js.html");
    
  • Callback interception through the ShouldOverrideUrlLoading() method of WebViewClient

    Android intercepts the url through the callback method shouldOverrideUrlLoading () of WebViewClient, parses the protocol of the url, and calls the corresponding method of Android if it detects a pre-agreed protocol.

    html Document

      <!DOCTYPE html>
      <html>
         <head>
            <meta charset="utf-8">
            <title>DEMO</title>
            <script>
               function callAndroid(){
      			//协议org://professor?arg1=com&arg2=test
                  document.location = "org://professor?arg1=111&arg2=222";
               }
            </script>
         </head>
         <body>
            //点击按钮则调用callAndroid函数
             <button type="button" id="button1" onclick="callAndroid()">CallAndroid</button>
         </body>
      </html>
    

    JAVA code

      @Override
      public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
          //一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
          Uri uri = Uri.parse(request.getUrl().toString());
          if (uri.getScheme().equals("org")) {
              if (uri.getAuthority().equals("professor")) {
                  LogUtils.i(uri.getQueryParameter("arg1"));
              }
              return true;
          }
    
          return super.shouldOverrideUrlLoading(view, request);
      }
    

    Remark

    JS is complicated to get the return value of Android method. If JS wants to get the return value of the Android method, it can only execute the JS method through WebView's loadUrl() to pass the return value back. The relevant code is as follows:

      //Android原生调用js
      mWebView.loadUrl("javascript:returnResult(" + result + ")");
    
      //需要在html中接收
      function returnResult(result){
          alert("result is" + result);
      }
    
  • Intercept JS dialog alert(), confirm(), prompt() messages through WebChromeClient's onJsAlert(), onJsConfirm(), onJsPrompt() method callbacks

    First introduce the three methods of alert(), confirm(), and prompt() in JS

    • alert(), pop up a warning window, no return value, add \n to the text to wrap
    • confirm(), pops up a confirmation box, two return values, returns a boolean value, through which you can determine whether the click is confirmed or canceled (true means clicked to confirm, false means clicked to cancel)
    • prompt(), pop up the input box, set the return value arbitrarily, click OK to return to the value in the input box, click cancel to return null

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

    The commonly used interception is: intercepting the input box of JS ( ie the prompt() method ). Because only prompt() can return any type of value , the operation is the most comprehensive, convenient and more flexible; the alert() dialog has no return value ; the confirm() dialog can only return two values ​​in two states (OK/Cancel) .

    html code

      <!DOCTYPE html>
      <html>
         <head>
            <meta charset="utf-8">
            <title>DEMO</title>
            <script>
               function callAndroid(){
                  //document.location = "org://professor?arg1=111&arg2=222";
                  var result=prompt("org://professor?arg1=111&arg2=222");
                  alert("demo " + result);
               }
            </script>
         </head>
         <body>
            //点击按钮则调用callAndroid函数
             <button type="button" id="button1" onclick="callAndroid()">CallAndroid</button>
         </body>
      </html>
    

    JAVA code

      @Override
      public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    
          //一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
          Uri uri = Uri.parse(url);
          if (uri.getScheme().equals("org")) {
              if (uri.getAuthority().equals("professor")) {
                  LogUtils.i(uri.getQueryParameter("arg1"));
                  //参数result:代表消息框的返回值(输入值)
                  result.confirm("js调用了Android的方法成功啦");
              }
              return true;
          }
    
          return super.onJsPrompt(view, url, message, defaultValue, result);
      }
    
  • Epilogue

    It can be compared from the above, according to the third method, namely: intercepting by the method of WebChromeClient is more flexible

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325092085&siteId=291194637