background

Hybrid development of Android native and Html5 is still the development method chosen by development companies. This article mainly shares the knowledge points mainly as follows:

1. Intercept the Html5 JS window.open(URL) method:

(1) Basic attributes of 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); // Cache White Screen String appCachePath = getApplicationContext().getcacheDir ().getabsolutePath () + "/ webCache "; / / set Application webSetting Caches the cache directory. SetAppCachePath (appCachePath); webSetting.setDatabasePath(appCachePath); webSetting.setAppCacheMaxSize(Long.MAX_VALUE); webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND); webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);Copy the code

Set webview. loadUrl(url) and block js redirection methods. * * the if (hitTestResult. GetType () = = WebView. HitTestResult. UNKNOWN_TYPE) * * determine whether js value orientation method, if it is directly interception return false

webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, Webview.hittestresult HitTestResult = view.gethitTestResult (); if (hitTestResult == null) { clearHistory(); return false; } / / redirection will no longer jump 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); } // Note: webview.loadurl (url); Must be in webView. SetWebChromeClient (myWebChromeClient); Execute later, otherwise interception cannot be implemented.Copy the code

(3). Instantiate the myWebChromeClient method

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 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); Return true; }}); WebView.WebViewTransport transport = (WebView.WebViewTransport) message.obj; // The following operations should be the new WebView to load the corresponding URL. transport.setWebView(webView1); message.sendToTarget(); return true; }};Copy the code

(4) Block js window.open(url)

We all know that js calls window.open(url) to open a new window to load Html, but Android WebView doesn’t support opening new Windows, so we need to override onCreateWindow(). Its main function is to create a new window, just like the window.open(URL) method. Its core code:

@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); Return true; }}); WebView.WebViewTransport transport = (WebView.WebViewTransport) message.obj; // The following operations should be the new WebView to load the corresponding URL. transport.setWebView(webView1); message.sendToTarget(); return true; }Copy the code

(5) The onShowFileChooser() method needs to be rewritten when js selects the image to call the native camera, which calls different methods according to the android system version, and its core code is as follows:

** * 5.0 calls **

   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;
     }
Copy the code

4.0, 3.0 above call

private void openFilerChooser(ValueCallback<Uri> uploadMsg) { mUploadCallbackForLowApi = uploadMsg; startActivityForResult(Intent.createChooser(getFilerChooserIntent(), "File Chooser"), REQUEST_CODE_FILE_CHOOSER); } // For openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { openFilerChooser(uploadMsg); } For Android 4.1+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFilerChooser(uploadMsg); }Copy the code

(6)openFilerChooser select file method:

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

(7) getFilerChooserIntent () method:

 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;
  }
Copy the code

(8) Rewrite the onActivityResult() callback method to pass the selected file back to the web 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);
     }
Copy the code

(9)afterFileChooseGoing() will be passed to web js depending on the system version

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; }}Copy the code

Note: Thanks to other authors for their ideas, this blog is for the record only.