Html5 js 与android WebView交互

1,157 阅读3分钟

背景

android原生与Html5混合开发现在依然是开发公司选择的开发方式,本篇文章主要给大家分享的知识点主要有以下几点:

1.拦截Html5 js window.open(url)方法:

(1)WebView基本属性:

       webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
       webSetting.setJavaScriptEnabled(true);
       webSetting.setAllowFileAccess(true);
       webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
       webSetting.setSupportZoom(true);
       webSetting.setBuiltInZoomControls(true);
       webSetting.setUseWideViewPort(true);
       webSetting.setSupportMultipleWindows(true);
       webSetting.setAppCacheEnabled(true);
       webSetting.setDomStorageEnabled(true);
       webSetting.setGeolocationEnabled(true);
       webSetting.setDatabaseEnabled(true);
       // 缓存白屏
       String appCachePath = getApplicationContext().getCacheDir()
               .getAbsolutePath() + "/webcache";
       // 设置 Application Caches 缓存目录
       webSetting.setAppCachePath(appCachePath);
       webSetting.setDatabasePath(appCachePath);

       webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
       webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
       webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
       

(2)设置webView.loadUrl(url),并拦截js重定向方法 讲解: ** if (hitTestResult.getType() == WebView.HitTestResult.UNKNOWN_TYPE)** 判断js是否为重定向方法,如果是就直接拦截 return false

       webView.setWebViewClient(new WebViewClient() {
           @Override
           public boolean shouldOverrideUrlLoading(WebView view, String url) {
               //这里可以对特殊scheme进行拦截处理
               //判断重定向的方式一
               WebView.HitTestResult hitTestResult = view.getHitTestResult();
               if (hitTestResult == null) {
                   clearHistory();
                   return false;
               }
               //重定向不再跳转
               if (hitTestResult.getType() == WebView.HitTestResult.UNKNOWN_TYPE) {
                   clearHistory();
                   return false;
               }

               return false;
           }

           @Override
           public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
               return super.shouldOverrideUrlLoading(view, request);
           }

       });
       webView.setWebChromeClient(myWebChromeClient);
       webView.loadUrl(url);

   }
   //  注:webview.loadUrl(url);必须在 webView.setWebChromeClient(myWebChromeClient);
   后面执行,否则无法实现拦截。

(3).实例化WebChromeClient myWebChromeClient方法

private WebChromeClient myWebChromeClient = new WebChromeClient() {
     @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @Override
     public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
         mUploadCallbackForHighApi = filePathCallback;
         Intent intent = fileChooserParams.createIntent();
         Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
         photoPickerIntent.setType("image/*");
//            startActivityForResult(photoPickerIntent, PICTURE_REQUEST_CODE);
//            intent.addCategory(Intent.CATEGORY_OPENABLE);
//            if (intent.getType().contains("image")) {
//                intent.setType("image/*");
//            }
         try {
             startActivityForResult(photoPickerIntent, REQUEST_CODE_FILE_CHOOSER);
         } catch (ActivityNotFoundException e) {
             mUploadCallbackForHighApi = null;
             return false;
         }
         return true;
     }

     private void openFilerChooser(ValueCallback<Uri> uploadMsg) {
         mUploadCallbackForLowApi = uploadMsg;
         startActivityForResult(Intent.createChooser(getFilerChooserIntent(), "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
     }

     // For 3.0+
     protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
         openFilerChooser(uploadMsg);
     }

     //For Android 4.1+
     public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
         openFilerChooser(uploadMsg);
     }

     @Override
     public void onProgressChanged(WebView webView, int i) {
         if (i == 100) {
             progressBar.setVisibility(8);
             progressBar.setProgress(0);
         } else {
             progressBar.setVisibility(0);
             progressBar.setProgress(i);
         }
     }

     @Override
     public boolean onCreateWindow(WebView webView, boolean b, boolean b1, Message message) {
         WebView webView1 = new WebView(MainActivity.this);
         webView1.setWebViewClient(new WebViewClient() {
             @Override
             public boolean shouldOverrideUrlLoading(WebView view, String url) {

                 Intent intent = new Intent();
                 intent.setAction("android.intent.action.VIEW");
                 Uri contentUrl = Uri.parse(url);
                 intent.setData(contentUrl);
                 startActivity(intent);
//                        web.loadUrl(url);//将拦截到url交由第一个WebView打开
                 return true;
             }
         });
         WebView.WebViewTransport transport = (WebView.WebViewTransport) message.obj;
         //以下的操作应该就是让新的webview去加载对应的url等操作。
         transport.setWebView(webView1);
         message.sendToTarget();
         return true;
     }
 };

(4)拦截js window.open(url)

我们都知道js执行window.open(url)是打开一个新窗口来加载Html,但是在Android WebView 并不支持打开新窗口,所以需要我们重写onCreateWindow()方法,它的主要作用就是跟window.open(url)方法一样,都是新建一个窗口。其核心代码:


	@Override
        public boolean onCreateWindow(WebView webView, boolean b, boolean b1, Message message) {
            WebView webView1 = new WebView(MainActivity.this);
            webView1.setWebViewClient(new WebViewClient() {
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {

                    Intent intent = new Intent();
                    intent.setAction("android.intent.action.VIEW");
                    Uri contentUrl = Uri.parse(url);
                    intent.setData(contentUrl);
                    startActivity(intent);
//                        web.loadUrl(url);//将拦截到url交由第一个WebView打开
                    return true;
                }
            });
            WebView.WebViewTransport transport = (WebView.WebViewTransport) message.obj;
            //以下的操作应该就是让新的webview去加载对应的url等操作。
            transport.setWebView(webView1);
            message.sendToTarget();
            return true;
        }

(5)js 选择图片调用原生相机需重写 onShowFileChooser()方法,其中根据android 系统版本的不同调用不同的方法,其核心代码如下:

** * 5.0以上调用**

   private ValueCallback<Uri> mUploadCallbackForLowApi;
	 private ValueCallback<Uri[]> mUploadCallbackForHighApi;
  private static final int REQUEST_CODE_FILE_CHOOSER = 1;
	 public static final int P_REQUEST_CODE = 100;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
     @Override
  public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
     mUploadCallbackForHighApi = filePathCallback;
         Intent intent = fileChooserParams.createIntent();
         Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
         photoPickerIntent.setType("image/*");
//            startActivityForResult(photoPickerIntent, PICTURE_REQUEST_CODE);
//            intent.addCategory(Intent.CATEGORY_OPENABLE);
//            if (intent.getType().contains("image")) {
//                intent.setType("image/*");
//            }
         try {
             startActivityForResult(photoPickerIntent, REQUEST_CODE_FILE_CHOOSER);
         } catch (ActivityNotFoundException e) {
             mUploadCallbackForHighApi = null;
             return false;
         }
         return true;
     }

4.0、3.0以上调用

private void openFilerChooser(ValueCallback<Uri> uploadMsg) {
            mUploadCallbackForLowApi = uploadMsg;
            startActivityForResult(Intent.createChooser(getFilerChooserIntent(), "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
        }

        // For 3.0+
        protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            openFilerChooser(uploadMsg);
        }

        //For Android 4.1+
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            openFilerChooser(uploadMsg);
        }

(6)openFilerChooser 选择文件方法:

    private void openFilerChooser(ValueCallback<Uri> uploadMsg) {
            mUploadCallbackForLowApi = uploadMsg;
            startActivityForResult(Intent.createChooser(getFilerChooserIntent(), "File Chooser"), REQUEST_CODE_FILE_CHOOSER);
        }

(7)getFilerChooserIntent() 方法:

 private Intent getFilerChooserIntent() {
      Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
      intent.addCategory(Intent.CATEGORY_OPENABLE);
      if (intent.getType().contains("image")) {
          intent.setType("image/*");
      }
      return intent;
  }

(8)重写 onActivityResult() 回调方法,将选中后的文件回传给网页js

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     super.onActivityResult(requestCode, resultCode, data);
     if (requestCode == REQUEST_CODE_FILE_CHOOSER && (resultCode == RESULT_OK || resultCode == RESULT_CANCELED)) {
         afterFileChooseGoing(resultCode, data);
     }

(9)afterFileChooseGoing()方法将根据系统版本不同会传给网页js处理

    private void afterFileChooseGoing(int resultCode, Intent data) {
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
           if (mUploadCallbackForHighApi == null) {
               return;
           }
           mUploadCallbackForHighApi.onReceiveValue(WebChromeClient.
           FileChooserParams.parseResult(resultCode, data));
           mUploadCallbackForHighApi = null;
       } else {
           if (mUploadCallbackForLowApi == null) {
               return;
           }
           Uri result = data == null ? null : data.getData();
           mUploadCallbackForLowApi.onReceiveValue(result);
           mUploadCallbackForLowApi = null;
       }
   }

说明:感谢其他作者提供思路,本篇博客仅作为记录知识使用.