Reprinted from:

Author: AWeiLoveAndroid

Link: www.jianshu.com/p/2b2e5d417…

Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.

(1) Why does the Webview open a page, play a piece of music, exit the Activity when the music is still playing in the background?

Plan a

Override protected void onDestroy() {if (mWebview! = null) { mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mWebview.clearHistory(); // Must remove view to avoid: Error: WebView. Destroy () called while still attached! ((ViewGroup) mWebview.getParent()).removeView(mWebview); mWebview.destroy(); mWebview = null; } super.onDestroy(); }Copy the code

Scheme 2

@Override
protected void onPause() {
   h5_webview.onPause();
   h5_webview.pauseTimers();
   super.onPause();
}
@Override
protected void onResume() {
   h5_webview.onResume();
   h5_webview.resumeTimers();
   super.onResume();
}
Copy the code

(2) how to use the title of the page to set their own title bar?

WebChromeClient mWebChromeClient = new WebChromeClient() { @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); txtTitle.setText(title); }}; mWedView.setWebChromeClient(mWebChromeClient()); // 1. If the current page does not have a title and you get null, you can use a title or a default title when you jump to the Activity. // 2. On some models, this method is not necessarily called after webView.goback (), so the title is still the same as the previous page title. You'll need an ArrayList to hold loaded urls, and a HashMap to hold urls and their titles. Then we use webView.cangoback () to do the judgment processing.Copy the code

(3) Why does JS call fail after packaging (or when WebView and JavaScript call each other, there is no problem when calling if debug is not confused, but it cannot be called normally after setting confusion)?

  • Solution:Add obfuscation to proGuard-rules.pro
-keepattributes *Annotation* -keepattributes *JavascriptInterface* -keep public class org.mq.study.webview.DemoJavaScriptInterface{ public <methods>; } # if it is an inner class, the confusion is as follows:  -keepattributes *JavascriptInterface* -keep public class org.mq.study.webview.webview.DemoJavaScriptInterface$InnerClass{ public <methods>; } the org. Mq. Study. Webview. DemoJavaScriptInterface is need not confuse the name of the classCopy the code

(4) After 5.0 WebView loading links start with Https, but the content of the link, such as the image is Http link, at this time, the image will not load out, how to solve?

// Cause analysis: If (build.version.sdk_int >= build.version_codes.lollipop) {// Both can be loaded webSetting.setMixedContentMode(webSetting.getMixedContentMode()); //mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); }Copy the code
● MIXED_CONTENT_ALWAYS_ALLOW allows content to be loaded from any source, even if the origin is unsafe; ● MIXED_CONTENT_NEVER_ALLOW does not allow Https to load Http content, that is, does not allow to load an unsafe resource from a secure origin; ● MIXED_CONTENT_COMPLTIBILITY_MODE When it comes to hybrid content, WebView tries to be compatible with the latest Web browser styles;Copy the code

We can override WebViewClient’s onReceivedSslError method and set it to accept certificates from all websites. The code is as follows:

webView.setWebViewClient(new WebViewClient() { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { //super.onReceivedSslError(view, handler, error); Be sure to remove this line of code, otherwise the Settings will not work. // handler.cancel(); // Android's default handler. Proceed (); // handleMessage(Message MSG); // other processing}});Copy the code

(5) WebView calls the mobile phone system album to upload pictures. During the development process, it is found that many machines cannot call up the system album to select pictures. How to solve it?

  • Cause analysis: The setWebChromeClient callback method openFileChooser has been modified several times. Up to 5.0, openFileChooser has several overloaded methods. After 5.0, the callback method should be onShowFileChooser.

  • Solution: We need to reload openFileChooser() and override onShowFileChooser() for 5.0 and above:

public class MainActivity extends AppCompatActivity { private ValueCallback<Uri> uploadMessage; private ValueCallback<Uri[]> uploadMessageAboveL; private final static int FILE_CHOOSER_RESULT_CODE = 10000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); WebView webview = (WebView) findViewById(R.id.web_view); assert webview ! = null; WebSettings settings = webview.getSettings(); settings.setUseWideViewPort(true); settings.setLoadWithOverviewMode(true); settings.setJavaScriptEnabled(true); Webview. SetWebChromeClient (new WebChromeClient () {/ / android 3.0 the following: Public void openFileChooser(ValueCallback<Uri> ValueCallback) {uploadMessage = ValueCallback; openImageChooserActivity(); } // Android 3.0 or above, Android 4.0 or below: Public void openFileChooser(ValueCallback ValueCallback, String acceptType) {uploadMessage = ValueCallback; openImageChooserActivity(); } public void openFileChooser(ValueCallback<Uri> ValueCallback, String acceptType, String capture) { uploadMessage = valueCallback; openImageChooserActivity(); } //android4.4 no method... @override public Boolean onShowFileChooser(WebView WebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { uploadMessageAboveL = filePathCallback; openImageChooserActivity(); return true; }}); String targetUrl = "file:///android_asset/up.html"; webview.loadUrl(targetUrl); } private void openImageChooserActivity() { Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == FILE_CHOOSER_RESULT_CODE) { if (null == uploadMessage && null == uploadMessageAboveL) return; Uri result = data == null || resultCode ! = RESULT_OK ? null : data.getData(); if (uploadMessageAboveL ! = null) { onActivityResultAboveL(requestCode, resultCode, data); } else if (uploadMessage ! = null) { uploadMessage.onReceiveValue(result); uploadMessage = null; } } } @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) { if (requestCode ! = FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null) return; Uri[] results = null; if (resultCode == Activity.RESULT_OK) { if (intent ! = null) { String dataString = intent.getDataString(); ClipData clipData = intent.getClipData(); if (clipData ! = null) { results = new Uri[clipData.getItemCount()]; for (int i = 0; i < clipData.getItemCount(); i++) { ClipData.Item item = clipData.getItemAt(i); results[i] = item.getUri(); } } if (dataString ! = null) results = new Uri[]{Uri.parse(dataString)}; } } uploadMessageAboveL.onReceiveValue(results); uploadMessageAboveL = null; }Copy the code
  • For Android4.4, openFileChooser is removed from the system. How can I solve this problem?

For details, please see blog blog.csdn.net/xiexie758/a…

(6) WebView calls the album of the mobile phone system to upload pictures, and handles the method mentioned in the sixth point well. When we completed the release package test, we found that we still could not select pictures. How to solve it?

  • Cause analysis: OpenFileChooser () is the system API. Our release package was obfuscated, so we confused openFileChooser() when packaging. This makes it impossible to call openFileChooser().

  • The solution simply does not confuse openFileChooser().

-keepclassmembers class * extends android.webkit.WebChromeClient{ public void openFileChooser(...) ; }Copy the code

(7) How to save pictures by long pressing in WebView?

1. Add listening to WebView

mWebview.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
    }
});
Copy the code

2. Get the clicked picture address

First get the type, according to the corresponding type to process the corresponding data.

Webview.hittestresult result = ((WebView) v).gethitTestResult (); int type = result.getType(); Imgurl = result.getextra (); String imgurl = result.getextra ();Copy the code

There are several types of type:

  • WebView. HitTestResult. UNKNOWN_TYPE unknown type
  • WebView. HitTestResult. PHONE_TYPE phone type
  • WebView. HitTestResult. EMAIL_TYPE email type
  • WebView. HitTestResult. GEO_TYPE map types
  • WebView. HitTestResult. SRC_ANCHOR_TYPE hyperlink type
  • WebView. HitTestResult. SRC_IMAGE_ANCHOR_TYPE picture type with links
  • WebView. HitTestResult. IMAGE_TYPE simple image type
  • WebView. HitTestResult. EDIT_TEXT_TYPE selected text types

3. Manipulate pictures

You can pop up to save the picture, or click to jump to the page showing the picture.

mWebView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { WebView.HitTestResult result = ((WebView)v).getHitTestResult(); if (null == result) return false; int type = result.getType(); if (type == WebView.HitTestResult.UNKNOWN_TYPE) return false; / / here can intercept many types, we can deal only with the picture type is the switch (type) {case WebView. HitTestResult. PHONE_TYPE: / / processing dial-up break; Case WebView. HitTestResult. EMAIL_TYPE: / / processing Email break; Case WebView. HitTestResult. GEO_TYPE: / / map type break; Case WebView. HitTestResult. SRC_ANCHOR_TYPE: / / link break; case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE: break; Case WebView. HitTestResult. IMAGE_TYPE: / / processing according to the menu item of the picture/long/get photo path String saveImgUrl = result. GetExtra (); Intent I = new Intent(mainactivity.this, imageactivity.class); i.putExtra("imgUrl", saveImgUrl); startActivity(i); break; default: break; }}});Copy the code

(8) WebView hardware acceleration caused by the problem?

WebView has a lot of problems, for example: it can’t open PDF, it can only support video playback with hardware acceleration on, and it crashes on some models. Let’s take a look at hardware acceleration. There are four levels of hardware acceleration:

  • Application level < Application android: hardwareAccelerated = “true”… >

  • The Activity level < Activity android: hardwareAccelerated = “true”… >

  • Window level (Currently, Android does not support turning off hardware acceleration at Window level.) getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

  • View level View.setLayerType (view.layer_type_hardware, null);

1. The white screen blinks

  • Cause analysis: for systems above 4.0, WebView renders pages more quickly and drags more smoothly after hardware acceleration is enabled. As a side effect, when the WebView is completely covered and then suddenly restored (such as when SlideMenu slides the WebView out of the side), the transition will be white and the screen will flicker.

  • Solution: Temporarily turn off the hardware acceleration of WebView before the transition period, and then turn it on after the transition period. The code is as follows:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }
Copy the code

2. Overlapping characters

  • Android 4.0+ EditText character overlap:

On some machines, the contents of the EditText overlap when typing, but most machines don’t, so it doesn’t feel like a problem with the code.

Why it happened: JellyBean has a hardware acceleration bug that we can turn off. Solution: Add a line in EditText:

Android: layerType = "software"Copy the code

3. Pictures cannot be displayed

Sometimes you need to load large images, but in hardware acceleration OpenGL has a memory limit. After the event the Bitmap is too large to be matched into a texture (587×7696, Max =2048×2048).

That’s when we need to speed up the hardware. Turned off hardware acceleration for the entire application:

<application  
    android:allowBackup="true"  
    android:icon="@drawable/ic_launcher"  
    android:hardwareAccelerated="false"  
    android:label="@string/app_name"  
    android:theme="@style/AppTheme" >  
Copy the code

Controls such as ListView and WebView are particularly difficult, indicating that hardware acceleration is a significant improvement in application performance. So I switched to closing the Activity instead.

<activity  
    android:name="icyfox.webviewimagezoomertest.MainActivity"  
    android:label="@string/app_name"  
    android:hardwareAccelerated="false"  
Copy the code

(9) What is the reason why the event of non-first WebView click in ViewPager does not respond?

  • This can happen if you load multiple WebViews one by one in a ViewPager. The ViewPager first screen WebView is created in the foreground, and there is no problem when clicked; Other webViews that are not the first screen are created in the background. If you slide to it and click on the page, the following error log will appear:
20955-20968/xx.xxx. XXX E/ webCoreglue: Should not happen: no rect-based-test nodes foundCopy the code
  • Solution:

The solution to this problem is to inherit the WebView class, override the onTouchEvent method in a subclass, and fill in the following code:

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        onScrollChanged(getScrollX(), getScrollY(), getScrollX(), getScrollY());
    }
    return super.onTouchEvent(ev);
}
Copy the code

(10) After setting GLSurfaceView to Software or Hardware, I found no screen. What is the reason?

  • GLSurfaceView and WebView default LayerType is NONE. 支那

  • Solution: Simply set the LayerType of GLSurfaceView to LAYER_TYPE_NONE.

(11)Android 9.0/P WebView multi-process use problem

When Android P was released, the usage of WebView was changed: Multiple processes are not allowed to use the WebView in the same directory, and different directories need to be set for the WebView of different processes.

As you can see, when our targetSdkVersion is 28 or above, and we need to use WebView in multi-process mode, we need to adjust accordingly to support it correctly. To solve this problem, we need a mechanism compatible with Android P:

public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Fix WebView multiprocess loading bug initWebView(); } private void initWebView() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { String processName = getProcessName(); WebView.setDataDirectorySuffix(processName); }}}Copy the code

(12) WebView memory leak

  • 1. Instead of defining webViews in XML, create them in the Activity when needed, and use getApplicationgContext().
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
                                         ViewGroup.LayoutParams.MATCH_PARENT);
    mWebView = new WebView(getApplicationContext());
    mWebView.setLayoutParams(params);
    mLayout.addView(mWebView);
Copy the code
  • 2. When the Activity destroys (WebView), first let the WebView load null content, then remove the WebView, then destroy the WebView, and finally empty.
@Override protected void onDestroy() { if (mWebView ! = null) { mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null); mWebView.clearHistory(); ((ViewGroup) mWebView.getParent()).removeView(mWebView); mWebView.destroy(); mWebView = null; } super.onDestroy(); }Copy the code

Other:

The WebView – based

WebView-# Small optimizations & Security vulnerabilities and fixes

WebView-# Cache mechanism & resource preloading solution