preface

Android application layer development has several modules, of which WebView is one of the most important modules. There aren’t many webViews available online, and there aren’t many open source projects on Github, not to mention a ready-made packaged WebView container that can be used directly in production. This article only records some pits when using WebView to achieve business requirements, and provides some solutions to avoid the same problems encountered by friends to step on the pit again.

Present situation of the WebView

Webviews on Android have a checkered history, and developers must have worked hard to get to where they are today — webViews in apps behave the same as Those in Chrome. For Android beginners, or just start to contact WebView development, WebView is a little difficult to adapt to, and even some fear. The open source community has done very little to remodel and wrap webViews, requiring developers to find a lot of information to understand webViews.

WebView Changelog

Android4.4 (API level 19) system before, Android uses native Android Webkit kernel, this kernel is not very good support for HTML5, now use 4.4 below the machine is not much, I will not do too much introduction to this kernel, Take a look at this article if you are interested.

Since Android4.4, Chromium kernel has replaced Webkit kernel and officially taken over WebView rendering. Chromium is an open source browser kernel project, and there are many browsers modified based on the Chromium open source project, including the most famous Chrome browser, as well as many domestic browsers (360 browser, QQ browser, etc.). The implementation of Chromium on Android is Android System WebView^1.

Starting from Android5.0, WebView has been transplanted into an independent APK, which can exist and update independently without relying on the System. We can see the current version of WebView in System -> Settings ->Android System WebView.

As of Android7.0, if you have Chrome (version>51) installed, Chrome will render the WebView of your application directly. The WebView version will be updated as Chrome updates. The user can also select the service provider of the WebView (in Developer options ->WebView Implementation). The WebView can be detached from the application and rendered in a separate sandbox process (open in developer options) ^2.

Starting from Android8.0, WebView multi-process mode is enabled by default, that is, WebView runs in a separate sandbox process ^3.

Why are WebViews so difficult?

Although it’s as easy for application developers to use WebViews as it is to use a regular View — you just need to define it in XML or instantiate it directly — WebViews are pretty hard to figure out. Why is that? There are several possible factors.

  • Complex WebView configuration

The WebView provides default configuration WebSettings when it is initialized, but many default configurations cannot meet service requirements and require secondary configuration. For example, the Kaola App has made the following modifications based on the default configuration:

public static void setDefaultWebSettings(WebView webView) { WebSettings webSettings = webView.getSettings(); // Enable mixed mode loading above 5.0if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    }
    webSettings.setLoadWithOverviewMode(true);
    webSettings.setUseWideViewPort(true); / / allow the js code webSettings. SetJavaScriptEnabled (true); / / allow SessionStorage/LocalStorage storage webSettings setDomStorageEnabled (true); / / disable zooming webSettings. SetDisplayZoomControls (false);
    webSettings.setBuiltInZoomControls(false); // Disable text zoom webSettings.setTextZoom(100); //10M cache, API 18, system automatic management. webSettings.setAppCacheMaxSize(10 * 1024 * 1024); / / allow the cache, set up the cache location webSettings. SetAppCacheEnabled (true);
    webSettings.setAppCachePath(context.getDir("appcache", 0).getPath()); / / allow the WebView webSettings. Using the File agreement setAllowFileAccess (true); / / not save password webSettings. SetSavePassword (false); / / set UA webSettings. SetUserAgentString (webSettings getUserAgentString () +" kaolaApp/"+ AppUtils.getVersionName()); / / remove part of the system the JavaScript interface KaolaWebViewSecurity. RemoveJavascriptInterfaces (webView); / / automatic loading pictures webSettings. SetLoadsImagesAutomatically (true);
}
Copy the code

In addition, users also need to implement WebViewClient and WebChromeClient according to business requirements, these two classes need to overwrite more methods, It is used to implement title customization, loading progress bar control, JsBridge interaction, URL blocking, error handling (including HTTP, resources, network) and many other business-related functions.

  • Complex front-end environment

Now, the core language of the World Wide Web, hypertext Markup language has developed to HTML5, followed by HTML, CSS, JS corresponding upgrades and updates. Older versions of the syntax cannot be recognized and rendered on older kernels, and development has to face backward compatibility issues when new features need to be used for business purposes. With millions of links on the Internet, it’s not WebView’s job to decide which language features to use, and it’s almost impossible for WebView to adapt to all pages.

  • Differences between versions

The implementation of different versions of WebView methods may be different, and the front end generally only calls the API of the system to achieve functions, which will lead to different Android systems, different Versions of WebView performance is inconsistent. A typical example is the file upload function in a WebView, described below, which generates different callback methods when we click on a control () that selects a file on a Web page. In addition to the file upload function, there are many differences between versions, such as the version of the cache mechanism, JS security vulnerability shielding, cookie management and so on. Google is also trying to solve the adaptation pressure caused by these differences for developers. For example, the switch from The Webkit kernel to the Chromium kernel is transparent to developers, and the underlying API is completely unchanged, which is also the benefit of good design patterns.

  • Domestic ROM, browser to WebView kernel magic change

Domestic mobile phone manufacturers of basic comes with the browser in factory, see the system application, found no built-in com. Android. Webview or com. Google. Android. Webview package, these browsers are not simply set a webview layer of shell, But directly using the Chromium kernel, as for whether the magic changed the kernel source, unknown. Domestic produced browser, such as 360 browser, QQ browser, UC browser, almost all magic changed the core. It is worth mentioning that Tencent produced the X5 kernel, known as the page rendering fluency is higher than the native kernel, the client to reduce the WebView pit at the same time, increased the front-end adaptation of the difficulty, function implementation needs to have more consideration.

  • Some Web knowledge is required

If you just use webview.loadURL () to load a web page without knowing what’s going on at the bottom, url errors, some content in the URL can’t load, content in the URL can’t click, Alipay payment can’t float, and the front end can’t communicate, etc. To develop a fully functional WebView, it is necessary to have a certain understanding of Web knowledge (HTML, JS, CSS), know loadUrl, WebView in the background after requesting this URL, the server did what response, and what resources, what is the role of these resources.

Why don’t WebView projects on Github work?

As can be seen from the above link, the main WebView projects on Github with over 1000 stars are FinestWebView-Android and Android-AdvancedWebView. If you look at the source code, you should know that the first project is biased towards implementing a browser, and the second project provides too few interfaces and leaves some holes unfinished. I have looked at several other open source implementations and found that they are not ideal. Later, I realized that it was difficult to independently implement a WebView without relying on the business, especially when jsBridge interface was agreed with the front end, which needed to deal with a series of functions such as page closing, full screen, URL blocking, login and sharing. Even if the WebView was connected to the open source platform, it also needed to do a lot of expansion to fully meet the requirements. Instead, each e-commerce platform has its own set of rules, and it is reasonable to expand WebView based on the business needs of e-commerce.

WebView pit history

If you’re new to a WebView, it’s almost impossible not to step into a pit. When I came across WebView code left over by my predecessor, there were some trickeys in it that I could have fallen into if I hadn’t read it carefully or looked through the material. Here are some of the pits that have been encountered.

WebSettings.setJavaScriptEnabled

I’m sure 99% of all applications will call the following sentence

WebSettings.setJavaScriptEnabled(true);
Copy the code

The Android version 4.3 call WebSettings. SetJavaScriptEnabled () method is called when the reload method, at the same time will callback WebChromeClient. Many times onJsPrompt (). If you have business logic that depends on these two methods, you need to be careful to determine whether multiple callbacks make a difference.

Also, if JavaScript is enabled, it is important to take security measures to prevent remote execution vulnerabilities ^5.

@TargetApi(11)
private static final void removeJavascriptInterfaces(WebView webView) {
    try {
        if (Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT < 17) {
	        webView.removeJavascriptInterface("searchBoxJavaBridge_");
	        webView.removeJavascriptInterface("accessibility");
	        webView.removeJavascriptInterface("accessibilityTraversal"); } } catch (Throwable tr) { tr.printStackTrace(); }}Copy the code

301/302 redirection problem

301/302 redirection issues in WebView are definitely at the top of the list… A random search of solutions either did not meet the business requirements or did not completely solve the problem.

Stackoverflow.com/questions/4… Blog.csdn.net/jdsjlzx/art… www.cnblogs.com/pedro-neer/… www.jianshu.com/p/c01769aba…

301/302 service scenario and blank screen

Let’s look at the business scenario. For webViews that need to intercept urls and concatenate specific parameters in urls, 301 and 302 can occur in the following scenarios:

  • If you log in to the H5 page for the first time, redirection is displayed, and the H5 page is loaded directly, for example, HTTP to HTTPS
  • When first entering, there is a redirect and then jump to native page, such as scan the short chain and then jump to Native
  • Secondary loading, redirection, jump to native page
  • For the Koala business, there is also the need to log in and jump to a page. If my group is not logged in, click my group to jump to the login page, and then load my group page after login.

The first case belongs to the normal situation, did not encounter any pit temporarily.

In the second case, there will be a WebView blank page problem. The original URL cannot be intercepted to the native page, but the URL after 301/302 is intercepted to the native page. In this case, the corresponding Activity of the WebView needs to be ended. Otherwise, when the user returns to the previous page from the intercepted page, it will be a blank WebView page.

In the third case, the problem of WebView blank page is also encountered. The reason is that the first loaded page is redirected to the second page, and the second page is intercepted by the client and redirected to the native page, so the WebView stays in the state of the first page, and the first page is obviously blank.

In the fourth case, you have the problem of loading the login page indefinitely. Koala login links are formatted like this:

Url https://m.kaola.com/login.html?target= login after the jumpCopy the code

If the URL is reloaded after a successful login, it loops back to the login page. The fourth point is relatively simple to solve. After login, you can get the jump URL after target and reload it again.

301/302 Rollback problem

No matter what kind of redirection scenario, it is inevitable to encounter the processing problem of stack rollback. If not handled properly, the user may not be able to return to the page before the redirection when pressing the back key. Many developers in overwrite the WebViewClient. ShouldOverrideUrlLoading () method, rough handling will simply use the following way:

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

The Achilles’ heel of this approach is that pressing the back key is ineffective and will remain on the page before 302 without special treatment. There are only a few solutions:

  1. Manually manage the rollback stack, and roll back ^6 twice when a redirect is encountered.
  2. throughHitTestResultDetermine if it is a redirect to determine whether to load the URL yourself^ 7 ^ 8.
  3. By setting the flag bit inonPageStartedandonPageFinishedMark variables separately to avoid redirection^ 9.

It’s fair to say that none of these solutions is perfect and all have flaws.

301/302 Superior solution

Resolve the 301/302 rollback problem

Can the above schemes be combined to make a more accurate judgment of 301/302? Here is the solution of this paper. Before providing a solution, we need to know what the return value of the shouldOverrideUrlLoading method means.

Give the host application a chance to take over the control when a new url is about to be loaded in the current WebView. If WebViewClient is not provided, by default WebView will ask Activity Manager to choose the proper handler for the url. If WebViewClient is provided, return true means the host application handles the url, while return false means the current WebView handles the url.

Simply put, return true and the URL will be handled by the client, not the WebView. If false, the current WebView implementation will handle the URL.

Does the WebView know if a URL is 301/302? The WebView can retrieve the request information and the response information from the URL according to the code in the header, which can be easily implemented. This is exactly the case. (PS: From the section above, WebView is a separate APK after 5.0, can be upgraded separately, the new version of WebView implementation must deal with redirection issues)

However, there are business requirements for URL interception, and you certainly can’t leave all cases to the system WebView. In order to solve the URL blocking problem, this article introduces another idea — determining redirection by the user’s touch events. The following is illustrated in code.

/** * WebView base class, * * @author xingli * @time 2017-12-06 */ Public Class BaseWebView extends WebView {private Boolean mTouchByUser; public BaseWebView(Context context) { super(context); } public BaseWebView(Context context, AttributeSet attrs) { super(context, attrs); } public BaseWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public final void loadUrl(String url, Map<String, String> additionalHttpHeaders) { super.loadUrl(url, additionalHttpHeaders); resetAllStateInternal(url); } @Override public void loadUrl(String url) { super.loadUrl(url); resetAllStateInternal(url); } @Override public final void postUrl(String url, byte[] postData) { super.postUrl(url, postData); resetAllStateInternal(url); } @Override public final void loadData(String data, String mimeType, String encoding) { super.loadData(data, mimeType, encoding); resetAllStateInternal(getUrl()); } @Override public final void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, StringhistoryUrl) {
        super.loadDataWithBaseURL(baseUrl, data, mimeType, encoding, historyUrl);
        resetAllStateInternal(getUrl());
    }

    @Override
    public void reload() {
        super.reload();
        resetAllStateInternal(getUrl());
    }

    public boolean isTouchByUser() {
        return mTouchByUser;
    }

    private void resetAllStateInternal(String url) {
        if(! TextUtils.isEmpty(url) && url.startsWith("javascript:")) {
            return; } resetAllState(); } // Reset the touch state protected void when loading the URLresetAllState() {
        mTouchByUser = false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            caseMotionevent. ACTION_DOWN: // set to before the user presses to load the next linktrue
                mTouchByUser = true;
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public void setWebViewClient(final WebViewClient client) {
        super.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { boolean handleByChild = null ! = client && client.shouldOverrideUrlLoading(view, url);if(handleByChild) {// Open the client interface to upper-layer business calls, if returnedtrue"Indicates that the service has been processed.return true;
            	   } else if(! IsTouchByUser ()) {// If the service is not processed and the user does not touch the screen again during the loading process, the event is considered to be 301/302 and submitted to the system for processing.return super.shouldOverrideUrlLoading(view, url);
                } else{// otherwise, it is a case of secondary loading of a link. In order to solve the problem of missing concatenation parameters, call loadUrl method again to add inherent parameters. loadUrl(url);return true; } } @RequiresApi(api = Build.VERSION_CODES.N) @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { boolean handleByChild = null ! = client && client.shouldOverrideUrlLoading(view, request);if (handleByChild) {
                    return true;
                } else if(! isTouchByUser()) {return super.shouldOverrideUrlLoading(view, request);
                } else {
                    loadUrl(request.getUrl().toString());
                    return true; }}}); }}Copy the code

The code above solves the normal stack rollback problem.

Solve the service blank screen problem

In order to solve the problem of white screen, koola’s current solution is similar to the above problem of back stack, by listening to the touch event distribution and onPageFinished event to determine whether the white screen is generated, the code is as follows:

public class KaolaWebview extends BaseWebView implements DownloadListener, Lifeful, OnActivityResultListener { private boolean mIsBlankPageRedirect; // Whether the page is blank due to redirection. public KaolaWebview(Context context) { super(context); init(); } public KaolaWebview(Context context, AttributeSet attrs) { super(context, attrs); init(); } public KaolaWebview(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } protected voidback() {
        if (mBackStep < 1) {
            mJsApi.trigger2("kaolaGoback");
        } else {
            realBack();
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_UP) {
            mIsBlankPageRedirect = true;
        }
        return super.dispatchTouchEvent(ev);
    }

    private WebViewClient mWebViewClient = new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { url = WebViewUtils.removeBlank(url); // Enable the third-party application client to be startedif (WebViewUtils.canHandleUrl(url)) {
                boolean handleByCaller = false; // If the operation is not triggered by the user, there is no need to hand it over to the upper layer.if(null ! = mIWebViewClient && isTouchByUser()) { handleByCaller = mIWebViewClient.shouldOverrideUrlLoading(view, url); }if(! handleByCaller) { handleByCaller = handleOverrideUrl(url); }return handleByCaller || super.shouldOverrideUrlLoading(view, url);
            } else {
                try {
                    notifyBeforeLoadUrl(url);
                    Intent intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
                    intent.addCategory(Intent.CATEGORY_BROWSABLE);
                    mContext.startActivity(intent);
                    if(! MIsBlankPageRedirect) {// If you encounter a blank screen, manually back(); } } catch (Exception e) { ExceptionUtils.printExceptionTrace(e); }return true;
            }
        }

        @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            return shouldOverrideUrlLoading(view, request.getUrl().toString());
        }
        
        private boolean handleOverrideUrl(final String url) {
           RouterResult result =  WebActivityRouter.startFromWeb(
                    new IntentBuilder(mContext, url).setRouterActivityResult(new RouterActivityResult() {
                        @Override
                        public void onActivityFound() {
                            if(! MIsBlankPageRedirect) {// The route has intercepted the redirect to the native page, but it may have occurred at this time // 301/302 redirect, so perform the backward action to prevent white screen. back(); } } @Override public voidonActivityNotFound() {
                            if(mIWebViewClient ! = null) { mIWebViewClient.onActivityNotFound(); }}}));returnresult.isSuccess(); }}; @Override public void onPageFinished(WebView view, String url) { mIsBlankPageRedirect =true;
        if (null != mIWebViewClient) {
            mIWebViewClient.onPageReallyFinish(view, url);
        }
        super.onPageFinished(view, url);
    }
}
Copy the code

The above two problems could have been solved by using the same variable control, but due to the legacy of the historical code, there is no time to optimize the test, which is one of the reasons the code is not released (the code is too ugly:).

Url parameter stitching problem

In general, WebView will concatenate some local parameters as identification codes to the front end, such as APP version number, network status, etc., for example, the URL to be loaded is

http://m.kaola.com?platform=android
Copy the code

Suppose we concatenate appVersion and network, then the concatenated URL becomes:

http://m.kaola.com?platform=android&appVersion=3.10.0&network=4g
Copy the code

Load the concatenated URL with webView.loadUrl (). Click a link on the page to jump to another page. Local concatenated parameters are not carried over automatically. If you need the front end to handle parameters, you can pass them through cookies if they are co-domain. If not, the client concatenation parameter is still required.

Some models do not have WebView, and the application crashes directly

The following Crash was found on some models of Crash platform, all of which are 7.0 or above.

android.util.AndroidRuntimeException: android.webkit.WebViewFactory$MissingWebViewPackageException: Failed to load WebView provider: No WebView installed
at android.webkit.WebViewFactory.getProviderClass(WebViewFactory.java:371)
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:194)
at android.webkit.WebView.getFactory(WebView.java:2325)
at android.webkit.WebView.ensureProviderCreated(WebView.java:2320)
at android.webkit.WebView.setOverScrollMode(WebView.java:2379)
at android.view.View.(View.java:4015)
at android.view.View.(View.java:4132)
at android.view.ViewGroup.(ViewGroup.java:578)
at android.widget.AbsoluteLayout.(AbsoluteLayout.java:55)
at android.webkit.WebView.(WebView.java:627)
at android.webkit.WebView.(WebView.java:572)
at android.webkit.WebView.(WebView.java:555)
at android.webkit.WebView.(WebView.java:542)
at com.kaola.modules.webview.BaseWebView.void (android.content.Context)(Unknown Source)
Copy the code

After testing, it is found that there is no way for ordinary users to uninstall the WebView (even if they can uninstall, it is only the update uninstall, the original version of the WebView still exists), so theoretically there is no exception… But since it happened and uploaded, it needs to be analyzed carefully. Following code WebViewFactory. GetProvider (),

static WebViewFactoryProvider getProvider() {
    synchronized (sProviderLock) {
        // For now the main purpose of this function (and the factory abstraction) is to keep
        // us honest and minimize usage of WebView internals when binding the proxy.
        if(sProviderInstance ! = null)return sProviderInstance;

        final int uid = android.os.Process.myUid();
        if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID
                || uid == android.os.Process.PHONE_UID || uid == android.os.Process.NFC_UID
                || uid == android.os.Process.BLUETOOTH_UID) {
            throw new UnsupportedOperationException(
                    "For security reasons, WebView is not allowed in privileged processes");
        }

        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
        Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
        try {
            Class<WebViewFactoryProvider> providerClass = getProviderClass();
            Method staticFactory = null;
            try {
                staticFactory = providerClass.getMethod(
                    CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
            } catch (Exception e) {
                if (DEBUG) {
                    Log.w(LOGTAG, "error instantiating provider with static factory method", e);
                }
            }

            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
            try {
                sProviderInstance = (WebViewFactoryProvider)
                        staticFactory.invoke(null, new WebViewDelegate());
                if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
                return sProviderInstance;
            } catch (Exception e) {
                Log.e(LOGTAG, "error instantiating provider", e); throw new AndroidRuntimeException(e); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); StrictMode.setThreadPolicy(oldPolicy); }}}Copy the code

So you can see, to get an instance of a WebView, you get the WebViewFactoryProvider factory class, Create a WebViewFactoryProvider using the static CHROMIUM_WEBVIEW_FACTORY_METHOD method in the WebViewFactoryProvider factory class, and then, Call WebViewFactoryProvider. CreateWebView () to create a WebViewProvider (the equivalent of a WebView proxy class), behind the WebView approach is achieved through the proxy class.

In the first step of getting the WebVIewFactoryProvider class,

private static Class<WebViewFactoryProvider> getProviderClass() { Context webViewContext = null; Application initialApplication = AppGlobals.getInitialApplication(); Try {/ / get the WebView context and set the provider webViewContext = getWebViewContextAndSetProvider (); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } code omitted... } } private static ContextgetWebViewContextAndSetProvider() {
    Application initialApplication = AppGlobals.getInitialApplication();
    WebViewProviderResponse response = null;
    Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
            "WebViewUpdateService.waitForAndGetProvider()");
    try {
        response = getUpdateService().waitForAndGetProvider();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
    }
    if(response.status ! = LIBLOAD_SUCCESS && response.status ! = LIBLOAD_FAILED_WAITING_FOR_RELRO) {// The crash occurred here. throw new MissingWebViewPackageException("Failed to load WebView provider: "+ getWebViewPreparationErrorReason(response.status)); }}Copy the code

It can be found that in the process of communicating with the WebView package, the so library did not load successfully, and finally the code went to the native layer and did not continue.

For this kind of problem, there are two solutions, one is a package name, if a system is detected in the package name does not contain com. Google. Android. Webview or com. Android. Webview, argue that users of mobile phone webview unavailable; Another is through the try/catch whether the WebView instantiation is successful, if throw WebViewFactory $MissingWebViewPackageException abnormalities, argues that the user’s WebView is not available.

It should be noted that the first solution is not reliable, because domestic manufacturers have many kinds of WebView implementations based on Chromium, and it is likely that the package name will be changed, such as MiWebView, the package name is com.mi.webkit.core.

POST requests in WebView

In WebView, if the front using POST way backend initiated a request, the request is not go to WebViewClient. The shouldOverrideUrlLoading () method in 10 ^. There are some solutions, such as android – post – webview, through js judgment whether a post request, and if so, in the WebViewClient. ShouldInterceptRequest () method in their connection is established, and get the corresponding page information, Return to WebResourceResponse. In short, try to avoid using POST requests on Web pages, which can cause a lot of unnecessary trouble.

WebView file upload function

The file upload function in WebView produces a different callback method when we click on the control () to select the file on the Web page :^4

Void openFileChooser(ValueCallback uploadMsg) works on Android 2.2 (API level 8) up to Android 2.3 (API level 10)

openFileChooser(ValueCallback uploadMsg, String acceptType) works on Android 3.0 (API level 11) up to Android 4.0 (API level 15)

openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) works on Android 4.1 (API level 16) up to Android 4.3 (API level 18)

onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient. FileChooserParams FileChooserParams) works on the Android 5.0 (API level 21) and above

The most frustrating point is that there is no callback on Android4.4, which will lead to incomplete functions and require the front end to do compatibility. The solution is to contract a separate JsBridge with the front-end to solve such problems.

conclusion

Here’s how to Design an Elegant and Robust Android WebView (Part 1). This article introduces the current status of WebView in Android, as well as due to the status quo can not change the left behind some pits. Fortunately, there is no code problem in the world that can’t be solved by one programmer, and if there is, two programmers can solve it. Now that we’ve filled in some of the holes left by our predecessors, it’s time to build a WebView that can be used in a production environment! “How to design an elegant and robust Android WebView? (2)” will introduce how to build the actual operation of WebView, as well as for a better user experience, put forward some WebView optimization strategies, please look forward to.

Refer to the link

  1. Developer.chrome.com/multidevice…
  2. Developer.android.com/about/versi…
  3. Developer.android.com/about/versi…
  4. Stackoverflow.com/questions/3…
  5. Blog.csdn.net/self_study/…
  6. Qbeenslee.com/article/and…
  7. Juejin. Cn/post / 684490…
  8. www.cnblogs.com/zimengfang/…
  9. Blog.csdn.net/dg_summer/a…
  10. Issuetracker.google.com/issues/3691…

The original link

Kaolamobile. Making. IO / 2017/12/10 /…