WebView Overall Use Strategy

Keywords: Android network html5 Javascript

Links to the original text: http://blog.csdn.net/qq_17766199/article/details/71698593
The most complete use of WebView in history, with a copy of Html5 Activity Deer only share

Share a comprehensive article on WebView usage. Links to the original text are here

I will have some supplements in the article.

WebView should still be used very frequently in current projects.  
Personally, I always feel that HTML5 It is a trend. Find something to sum up here.  
At the end of this article, there is a very good Html5Activity loading class. If you don't want to see it, you can download it directly.

WebSettings

WebSettings webSettings = mWebView .getSettings();

//Support for gesture focus, user name, password or other input
webview.requestFocusFromTouch();

setJavaScriptEnabled(true);  //Support js
setPluginsEnabled(true);  //Support plug-ins

webSettings.setRenderPriority(RenderPriority.HIGH);  //Improving the Priority of Rendering

//Set up an adaptive screen for both
setUseWideViewPort(true);  //Adjust the image to the appropriate size for webview
setLoadWithOverviewMode(true); // Scale to screen size

setSupportZoom(true);  //Support zooming, default to true. That's the premise below.
setBuiltInZoomControls(true); //Set the built-in zoom control.
//If the above is false, the WebView is not scalable, and nothing can be scaled regardless of the settings.
setTextZoom(2);//Set the text zoom multiple, default to 100

setDisplayZoomControls(false); //Hide native zoom controls

setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); //Support content repositioning
supportMultipleWindows();  //Multi-window
setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);  //Close caching in webview
setAllowFileAccess(true);  //Setting Accessible Files
setNeedInitialFocus(true); //Set up nodes for webview when requestFocus is invoked by webview
setJavaScriptCanOpenWindowsAutomatically(true); //Support for opening new windows through JS
setLoadsImagesAutomatically(true);  //Support automatic loading of pictures
setDefaultTextEncodingName("utf-8");//Setting the encoding format

setStandardFontFamily("");//Set the font of WebView and the default font is "sans-serif"
setDefaultFontSize(20);//Set the size of the WebView font to 16 by default
setMinimumFontSize(12);//Set the minimum font size supported by WebView, default to 8

About Caching

Caching mode

LOAD_CACHE_ONLY: Read only local cached data without using the network
LOAD_DEFAULT:(default) Decides whether to retrieve data from the network based on cache-control.  
LOAD_NO_CACHE: No caching, only data from the network.
LOAD_CACHE_ELSE_NETWORK uses the data in the cache whenever it is locally available, whether it expires or no-cache.

Combined use (offline loading):

if (NetStatusUtil.isConnected(getApplicationContext())) {
    webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//Decide whether to retrieve data from the network based on cache-control.
} else {
    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//If there is no network, it is obtained locally, i.e. offline loading.
}

webSettings.setDomStorageEnabled(true); // Turn on the DOM storage API function
webSettings.setDatabaseEnabled(true);   //Turn on the database storage API function
webSettings.setAppCacheEnabled(true);//Open Application Caches

String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //Setting up the Application Caches cache directory

Note: Each Application only calls WebSettings.setAppCachePath(), WebSettings.setAppCacheMaxSize()

Loading mode

Load a web page:

webView.loadUrl("http://www.google.com/");

Loading an html page in the apk package

webView.loadUrl("file:///android_asset/test.html");

How to load an html page locally on the phone:

webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");

Add HTTP request header

loadUrl(String url, Map<String, String> additionalHttpHeaders)

WebViewClient

WebViewClient is to help WebView handle various notification and request events.  
When opening a web page, the system browser is not called, but displayed in this WebView:

mWebView.setWebViewClient(new WebViewClient(){
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
          view.loadUrl(url);
      return true;
      }
  });

WebViewClient Method

WebViewClient mWebViewClient = new WebViewClient()
{
    shouldOverrideUrlLoading(WebView view, String url)  Most commonly used, such as the one above.
    //All loads on a web page go through this method, and we can do a lot of things with this function.
    //For example, get url, look at url.contains("add"), and add

    shouldOverrideKeyEvent(WebView view, KeyEvent event)
    //This method can be overridden to handle key events in browsers.

    onPageStarted(WebView view, String url, Bitmap favicon)
    //This event is to start loading page calls. We can set up a loading page to tell the user that the program is waiting for the network response.

    onPageFinished(WebView view, String url)
    //Called at the end of page loading. Similarly, we can turn off the loading bar and switch program actions.

    onLoadResource(WebView view, String url)
    // Page resources are called when they are loaded, and each resource (such as a picture) is called once.

    shouldInterceptRequest(WebView view, String url)
    // Intercepting and replacing network request data, API 11 was introduced and API 21 was discarded
    shouldInterceptRequest (WebView view, WebResourceRequest request)
    // Intercept and replace network request data, introduced from API 21

    onReceivedError(WebView view, int errorCode, String description, String failingUrl)
    // (Reporting error messages)

    doUpdateVisitedHistory(WebView view, String url, boolean isReload)
    //(Updating of historical records)

    onFormResubmission(WebView view, Message dontResend, Message resend)
    //(The application re-requests web page data)

    onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,String realm)
    //(Authorization request for return information)

    onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
    //Rewriting this method allows webview to process https requests.

    onScaleChanged(WebView view, float oldScale, float newScale)
    // (Called when WebView changes)

    onUnhandledKeyEvent(WebView view, KeyEvent event)
    //(Called when the Key event is not loaded)
}

Set the WebViewClient defined above to WebView:

webView.setWebViewClient(mWebViewClient);

WebChromeClient

WebChromeClient is an assistant to WebView processing JavaScript Dialog boxes, website icons, website title, loading progress, etc. : 
All the code in the method is generated by ____________ Android Handle it by yourself.

WebChromeClient mWebChromeClient = new WebChromeClient() {

    //Get the loading progress of the page and display it in the TextView control in the upper right corner
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        if (newProgress < 100) {
            String progress = newProgress + "%";
        } else {
        }
    }

    //Get the title in the Web page to set the title in your interface
    //When a load error occurs, such as no network, the title retrieved in onReceive Title is that the page cannot be found.
    //Therefore, it is recommended not to use the captured title when triggering onReceive Error.
    @Override
    public void onReceivedTitle(WebView view, String title) {
        MainActivity.this.setTitle(title);
    }

    @Override
    public void onReceivedIcon(WebView view, Bitmap icon) {
        //
    }

    @Override
    public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
        //
        return true;
    }

    @Override
    public void onCloseWindow(WebView window) {
    }

    //A way to deal with alert pop-up box, html pop-up box
    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        //
        return true;
    }

    //Processing confirm pop-up box
    @Override
    public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult
            result) {
        //
        return true;
    }

    //Handling prompt pop-up box
    @Override
    public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
        //
        return true;
    }
};

Similarly, set the WebChrome Client defined above to WebView:

webView.setWebChromeClient(mWebChromeClient);

Some Methods of WebView

Forward and backward

goBack()//Back off
goForward()//Forward
goBackOrForward(intsteps) //Take the current index as the starting point to move forward or backward to the steps specified in the history. If the steps are negative, they are backward, and if they are positive, they are forward.
canGoForward()//Is it possible to move forward?
canGoBack() //Is it possible to retreat?

Clear cached data:

clearCache(true);//Clear the cache left by web access, because the kernel cache is global, this method is not only for web view, but also for the entire application.
clearHistory()//Clearing up the history of the current webview access will only allow the webview to access all records in the history except the current access record.
clearFormData()//This api simply clears the form data that is automatically filled, and it does not clear the data that WebView stores locally.

The status of WebView:

onResume() //Activate WebView to be active and can normally execute web page responses
onPause()//When the page loses focus and is switched to the background invisible state, onPause action needs to be executed. The onPause action notifies the kernel to suspend all actions, such as DOM parsing, plugin execution, JavaScript execution.

pauseTimers()//When the application is switched to the background, we use webview, which is not only for the current webview, but also for the whole application. It will suspend the layout, parsing and JavaScript timer of all webviews. Reduce CPU power consumption.
resumeTimers()//Restore pauseTimers action.

destroy()//When the Activity is destroyed and shut down, music or video is still playing. It must be destroyed.

But note:
When WebView calls destory, WebView is still bound to Activity. This is because the context object of the Activity is passed in when a custom WebView is built, so you need to remove WebView from the parent container first, and then destroy webview:

rootLayout.removeView(webView);
webView.destroy();

Determine whether WebView has scrolled to the bottom or top of the page:

The getScrollY()// method returns the distance from the top of the current visible area to the top of the entire page, that is, the distance from which the current content scrolls.
getHeight() or getBottom()// methods return the height of the current WebView container.
getContentHeight() returns the height of the entire html, but it is not the same as the current height of the entire page. Because WebView has zooming function, the current height of the entire page should actually be the height of the original HTML multiplied by the zooming ratio. Therefore, the correct result should be:

    if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
        //Already at the bottom
    }

    if(webView.getScrollY() == 0){
        //At the top
    }

Return key

Return to the page you visited last time

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
        mWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

Call JS code

  WebSettings webSettings = mWebView .getSettings();
  webSettings.setJavaScriptEnabled(true);

  mWebView.addJavascriptInterface(new InsertObj(), "jsObj");

Above is the premise!!!  
Then we implement the above class, which provides four methods with very clear annotations.

class InsertObj extends Object {
    //The method provided to html can be obtained in js by var str = window.jsObj.HtmlcallJava(); and
    @JavascriptInterface
    public String HtmlcallJava() {
        return "Html call Java";
    }

    //The parametric functions provided to html are window. jsObj. Htmlcall Java2 ("IT-homer blog").
    @JavascriptInterface
    public String HtmlcallJava2(final String param) {
        return "Html call Java : " + param;
    }

    //Html provides us with functions
    @JavascriptInterface
    public void JavacallHtml() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                //Here is the call method
                mWebView.loadUrl("javascript: showFromHtml()");
                Toast.makeText(Html5Activity.this, "clickBtn", Toast.LENGTH_SHORT).show();
            }
        });
    }

    //The parametric function provided by Html
    @JavascriptInterface
    public void JavacallHtml2(final String param) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mWebView.loadUrl("javascript: showFromHtml2('IT-homer blog')");
                Toast.makeText(Html5Activity.this, "clickBtn2", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

There is a vulnerability in Android calling js:

http://blog.csdn.net/leehong2005/article/details/11808557

Here I suggest that you can use it. Tencent's X5 Core

Mixed problem of Http and Https in Android 5.0 WebView

On Android 5.0, Webview does not allow loading Http and Https mixed content by default:

Solution:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
     webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

Description of parameter type:
MIXED_CONTENT_ALWAYS_ALLOW: Allows content to be loaded from any source, even if the origin is unsafe;
MIXED_CONTENT_NEVER_ALLOW: Https are not allowed to load the content of Http, that is, an unsafe resource is not allowed to load from the origin of security;
MIXED_CONTENT_COMPATIBILITY_MODE: When it comes to mixed content, WebView tries to be compatible with the latest Web browser styles.

Under 5.0, Android is allowed by default.
But up to 5.0, it is not allowed. In fact, it is very difficult for us to determine that all the pages are https, so we need this step of operation.

Here we share one: Web View loading https page can not display resources properly 
The article includes: Setting up WebView to Accept Certificates for All Websites

Cookie correlation

Previously, the CookieSyncManager class was needed to synchronize cookies, but now this class has been discarded. Now that WebView can automatically synchronize cookies when needed, it is no longer necessary to create objects of the CookieSyncManager class for mandatory synchronization cookies. Now you just need to get the CookieManager object and set the cookie in.

Prerequisite: The way to get cookies from the server's return header is different according to the different clients of Http requests. Please get cookies by yourself.

1. Client sets cookie through the following code. If the two settings are the same, the previous one will be overwritten.

/**
 * Setting cookie s to WebView
 * @param url url to load
 * @param cookie Cookies to be synchronized
 */
public static void syncCookie(String url,String cookie) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        CookieSyncManager.createInstance(context);
    }
    CookieManager cookieManager = CookieManager.getInstance();
    cookieManager.setCookie(url, cookie);//If there are no special requirements, you just need to use session id as cookie in the form of "key=value"
}

Be careful:

1. Synchronized cookies need to be loaded before the WebView url, otherwise the WebView can not get the corresponding cookies, so it can not pass the validation.

2. Cookies should be updated in a timely manner, otherwise WebView is likely to take the old session id and communicate with the server.

2. CookieManager will store the Cookie in the application data/data/package_name/app_WebView/Cookies.db.

3. Open the web page, WebView reads the cookie value from the database, puts it in the head of the http request, and passes it to the server.

/**
 * Gets the cookie for the specified url
 */
public static String syncCookie(String url) {
    CookieManager cookieManager = CookieManager.getInstance();
    return cookieManager.getCookie(url);
}

4. Clean up Cookie:

// These two are at API level 21 Abandoned
CookieManager.getInstance().removeSessionCookie();
CookieManager.getInstance().removeAllCookie();

// It is recommended to use these two level s. 21 Additional
CookieManager.getInstance().removeSessionCookies();// Remove all expired cookie s
CookieManager.getInstance().removeAllCookies(); // Remove all cookie s
private void removeCookie(Context context) {
    CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
        @Override
        public void onReceiveValue(Boolean value) {
            // Removal results
        }
    });
}

Let me add here that we can see that removing cookies removes everything, so if you update the cookies of your own url, you don't need to clean the cookies, as long as you set the cookies again, they will be automatically replaced. After all, there are so many cookies that clearing them directly can affect other places. Specifically, we can look at the setCookie source code.

Some Ways to Avoid WebView Memory Leakage

1. You can start a new process for Activity of Webview and exit the current process directly at the end of the process.
Start a new process, the main code: AndroidManifest.xml configuration file code is as follows

    <activity
        android:name=".ui.activity.Html5Activity"
        android:process=":lyl.boon.process.web">
        <intent-filter>
            <action android:name="com.lyl.boon.ui.activity.htmlactivity"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>

Initiate Activity in the new process, which sends a Url:

    Intent intent = new Intent("com.lyl.boon.ui.activity.htmlactivity");
    Bundle bundle = new Bundle();
    bundle.putString("url", gankDataEntity.getUrl());
    intent.putExtra("bundle",bundle);
    startActivity(intent);

Then add System.exit(0) to onDestory() of Html5Activity to kill the current process.

2. Webview cannot be defined in xml, but created when needed, and Context uses getApplicationgContext(), as follows:

    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    mWebView = new WebView(getApplicationContext());
    mWebView.setLayoutParams(params);
    mLayout.addView(mWebView);

3. When Activity is destroyed, you can first let WebView load null content, then remove WebView, then destroy WebView, and finally empty it.  
The code is as follows:

    @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();
    }

Html5Activity Loading Class

public class Html5Activity extends AppCompatActivity {

    private String mUrl;

    private LinearLayout mLayout;
    private WebView mWebView;

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

        Bundle bundle = getIntent().getBundleExtra("bundle");
        mUrl = bundle.getString("url");

        Log.d("Url:", mUrl);

        mLayout = (LinearLayout) findViewById(R.id.web_layout);


        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        mWebView = new WebView(getApplicationContext());
        mWebView.setLayoutParams(params);
        mLayout.addView(mWebView);

        WebSettings mWebSettings = mWebView.getSettings();
        mWebSettings.setSupportZoom(true);
        mWebSettings.setLoadWithOverviewMode(true);
        mWebSettings.setUseWideViewPort(true);
        mWebSettings.setDefaultTextEncodingName("utf-8");
        mWebSettings.setLoadsImagesAutomatically(true);

        //Call the JS method. Android version is larger than 17, with the annotation @JavascriptInterface
        mWebSettings.setJavaScriptEnabled(true);

        saveData(mWebSettings);

        newWin(mWebSettings);

        mWebView.setWebChromeClient(webChromeClient);
        mWebView.setWebViewClient(webViewClient);
        mWebView.loadUrl(mUrl);
    }

    @Override
    public void onPause() {
        super.onPause();
        webView.onPause();
        webView.pauseTimers(); //Watch out for this!!! Pause all layout, parsing, JS for the entire WebView.
    }

    @Override
    public void onResume() {
        super.onResume();
        webView.onResume();
        webView.resumeTimers();
    }

    /**
     * Multi-window problem
     */
    private void newWin(WebSettings mWebSettings) {
        //The _bank tag in html means that a new window is opened, sometimes it can't be opened, so we need to do the following
        //Then override the onCreateWindow method of WebChromeClient
        mWebSettings.setSupportMultipleWindows(false);
        mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    }

    /**
     * HTML5 data storage
     */
    private void saveData(WebSettings mWebSettings) {
        //Sometimes Web pages need to save some key data by themselves, and Android WebView needs to be set up by itself.
        mWebSettings.setDomStorageEnabled(true);
        mWebSettings.setDatabaseEnabled(true);
        mWebSettings.setAppCacheEnabled(true);
        String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
        mWebSettings.setAppCachePath(appCachePath);
    }

    WebViewClient webViewClient = new WebViewClient(){

        /**
         * When multiple pages are opened in the same WebView, they do not create new activity or call the system browser to open it.
         */
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }

    };

    WebChromeClient webChromeClient = new WebChromeClient() {

        //========= HTML5 Location==========================================================
        //Privileges need to be added first
        //<uses-permission android:name="android.permission.INTERNET"/>
        //<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        //<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        @Override
        public void onReceivedIcon(WebView view, Bitmap icon) {
            super.onReceivedIcon(view, icon);
        }

        @Override
        public void onGeolocationPermissionsHidePrompt() {
            super.onGeolocationPermissionsHidePrompt();
        }

        @Override
        public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
            callback.invoke(origin, true, false);//Note the function, the second parameter is whether to agree to the location permission, and the third is whether to want the kernel to remember.
            super.onGeolocationPermissionsShowPrompt(origin, callback);
        }
        //========= HTML5 Location==========================================================

        //========= Multi-window problem==========================================================
        @Override
        public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
            transport.setWebView(view);
            resultMsg.sendToTarget();
            return true;
        }
        //========= Multi-window problem==========================================================
    };

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
            mWebView.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (mWebView != null) {
            mWebView.clearHistory();
            ((ViewGroup) mWebView.getParent()).removeView(mWebView);
            mWebView.loadUrl("about:blank");
            mWebView.stopLoading();
            mWebView.setWebChromeClient(null);
            mWebView.setWebViewClient(null);
            mWebView.destroy();
            mWebView = null;
        }
    }

}

Finally, put the project address: Click Enter

Reference resources

  1. Android Detailed usage of webview
  2. Android Details of WebView Development (1)
  3. Easy to do WebView cookie synchronization problem

I think it's a good idea to have a few favorites. It would be a great honor to have a direct appreciation.

Posted by rubberjohn on Sun, 30 Jun 2019 14:36:07 -0700