The author | Lu Yunhai

Write in front:

Webview is an important carrier for our front-end development from the PC end to the mobile end. Now, Webview plays an important role in the App we use every day. Let’s look at the world from a Webview.

I. Application scenarios

When it comes to application scenarios, we can most intuitively think of some pages embedded in the App, which provide us with a variety of interactions, as shown in the picture below:

In fact, the application scenarios of WebView are far more than these, in fact, in some PC software, and we interact with our HTML pages, but wearing webView clothes, clothes are too beautiful and we did not find their true meaning.

In addition, there are some interactions in the network set-top box that the WebView does with us. For example, some of the epGs in the early IPTV were run in the WebView, they were based on the WebKit kernel, although we used the remote control for the interaction.

Of course, today we will introduce you to a real WebView from a native perspective.

Ii. Interaction with App Native

Having said all that, in fact, the webview embedded in the client is still the most frequently used one at present, ranging from a public article we read with our mobile phone in the subway to some important interaction processes we use in the App. In fact, it is the WebView that opens PAGE M to take over. So, how does page M interact with Native?

At present, there are two common ways for javascript to interact with clients (collectively referred to as Native), one is through JSBridge, the other is through Schema.

1. JSBridge

First, let’s talk about JSBridge. In fact, when we open page M in Native, Native will inject a Bridge for us under the global window. This Bridge will include various methods for us to interact with native, such as determining whether third-party APPS are installed and obtaining network information.

Here’s an example:


     

    / * *

    * JSBridge under scope,

    * and instantiated getNetInfomation,

    * All are subject to actual agreements.

    * This is just for illustration

    * /

    const bridge = window.JSBridge;

    console.log(bridge.getNetInfomation());

Copy the code

The IOS side

In IOS, WebViewJavascriptBridge is used for registration. For details, see Github WebViewJavascriptBridge


     

    jsBridge = [WebViewJavascriptBridge bridgeForWebView:webView];

    .

    [jsBridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {

    // to do

    }];

Copy the code

Android

In Android, you need to register with addJavascriptInterface


     

    class JSBridge{

    @javascriptInterface // Note the annotations here. For security reasons, this is mandatory after 4.2, otherwise you cannot initiate calls from Javascript

    public void getNetInfomation(){

    // to do

    };

    }

    webView.addJavascriptInterface(new JSBridge(); , "JSBridge");

Copy the code
2. Schema url

If Bridge can only interact within native, then schame URL can interact within native as well as across APP. Schema is also the main way we use it now. It is similar to a pseudo-protocol link (also known as unified hop protocol), such as:

schema://path? param=abc

In webView, when the M page initiates a schema request, the native side will capture it. Here we can introduce you to the knowledge of IOS and Android, as follows:

The IOS side

UIWebView, for example, in IOS, initiated in the UIWebView network request, can be the delegate in native to intercept, then capture schema to trigger the corresponding function or business logic (using shouldStartLoadWithRequest). The code is as follows:


     

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

    // Process the scheme URL

    NSURL *url = [request URL];

    NSString *requestString = [[request URL] absoluteString];

    return YES;

    }

Copy the code

The Android end

In Android, you can use shouldoverrideurlloading to capture schema urls. The code is as follows:


     

    public boolean shouldOverrideUrlLoading(WebView view, String url){

    // Read the url and analyze it

    If false is returned, the WebView processes the url. If true, the WebView executes the URL according to the program

    return true;

    }

Copy the code

The above are the simple IOS and Android schema capture codes respectively. You can execute the corresponding business logic in the function according to your own needs to achieve the desired function.


Of course, just now we mentioned that you can use schema for cross-end interaction. How do you do that?

In fact, in JavaScript, the webView is basically the same, also initiates a schema request, but in the Native side will be slightly changed.

In Natvie (IOS and Android), the schema is used to find matching apps. IOS cannot be repeated, just like appId; Android can repeat, and when it does, it pops up and asks the user to choose one of them.

When we make a request in another app, such as this schema, the underlying system (IOS & Android) will use the schema to find the matching app, and then pull the app up. After pulling up the APP, the corresponding processing is as follows:

The IOS side

On the IOS side, the Schema is passed as a parameter to a pre-defined callback function, which is then executed. This callback function can be parsed through the resulting schema and directed to a fixed page within the app.


     

    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation{

    // The parameter URL is the obtained schema

    // to do

    }

Copy the code

The Android end

On the Android side, it will be a little more troublesome. On the external M page, a pseudo-protocol link of schema will be initiated, and the system will search according to this schema. The App to be pulled needs to have a configuration file, which is roughly as follows:


     

    <activity

    android:name=".activity.StartActivity"

    android:exported="true">

    <intent-filter>

    <action android:name="android.intent.action.VIEW"/>

    <category android:name="android.intent.category.DEFAULT"/>

    <category android:name="android.intent.category.BROWSABLE"/>

    <data android:scheme="zhuanzhuan"/>

    </intent-filter>

    </activity>

Copy the code

For example, in the above configuration, scheme is zhuanzhuan. Any schema link that starts with “zhuanzhuan://” will initiate the Activity(similar to StartActivity) for that schema. The Activity does something to the schema URL, for example:


     

    public class StartActivity extends TempBaseActivity {

    Intent intent;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    intent = getIntent();

    Uri uri = intent.getData();

    }

    }

Copy the code

For example, you can retrieve information about the incoming schema in the Activity using the getData method in the Intent.

This is also how we can call up our own app from inside the third-party app. Of course, in order to avoid traffic loss, some apps in the market will restrict the schema, only the schema in the PList whitelist can be pulled, otherwise it will be directly filtered out. For example, after the whitelist is enabled, more jsApiList can be used. Pulling up the schema is one of them. I won’t go into details here… 🙂

3. Evolution of WebView

For webview, to say evolution, or transformation, let me first think of the IOS WKWebView, every thing exists has its inevitability, let’s take a look at this super version of webView.

1. Appearance of WKWebView

At present, mixed development has become the mainstream, in order to improve the experience, WKWebView in IOS8 release, also born together. Up until now, IOS has been using UIWebView.

In terms of performance, WKWebView will be much better than UIWebView, which is a leap forward. It uses a cross-process scheme with Nitro JS parser and a refresh rate of up to 60fps. It also provides good H5 page support and a load progress property similar to UIWebView. At present, some first-tier Internet apps have switched to WKWebView on IOS, so we feel we can’t refuse.

Initialization of the entire WKWebView is also simple:


     

    WKWebView *webView = [[WKWebView alloc] init];

    NSURL *url = [NSURL URLWithString:@"https://m.zhuanzhuan.com"];

    [webView loadRequest:[NSURLRequest requestWithURL:url]];

Copy the code

It’s basically like UIWebView.

2. Comparison between WKWebView and UIWebView

As mentioned above, the performance is improved. Why is the memory footprint of APP connected to WKWebView so much smaller than UIWebView? This is mainly because the memory and performance consuming process of loading and rendering web pages is implemented by WKWebView (WKWebView is independent of app process). The diagram below:

In this way, mutual process independence is equivalent to the entire App process to reduce the memory consumption, App process will be more stable. In addition, even if the page process crashes, it is shown as a blank screen or load failure, will not affect the entire App process crash.

In addition to the performance mentioned above, WKWebView has one more query procedure than UIWebView. After the server completes its response, it asks if the retrieved content has been loaded into the container, which is a little more fine-grained in control than UIWebView, and can also interact with m pages better in some communications. The general process is as follows:

WKWebView’s delegate protocol is WKNavigationDelegate, in contrast to UIWebDelegate, which first jumps to the query, which is a call before loading the URL, asking the developer whether to download and load the current URL. UIWebView only has one query, WKWebView will also send a query after the URL is downloaded, allowing the developer to make another determination based on the Web content returned by the server.

There is a long way to go

In front of WKWebView so good, in fact, there are some pain points in the development. Unlike UIWebView, WKWebView has many interactions that are asynchronous, so it increases development costs when communicating with M pages to a large extent.

1. cookie

The first is the cookie problem, which I think is also WKWebView’s pit in the industry. There was a problem before, that is, after the completion of IOS login, the cookie in login state could not be obtained immediately after entering page M. This problem doesn’t exist in UIWebView.

After investigation, it is found that the main problem is that UIWebView uniformly handles cookies through NSHTTPCookieStorage. When the server responds, it writes cookies in the request header in the next request, so as to achieve the shared cookie value of M page and native.

But in WKWebView, it’s not. It also writes cookies to NSHTTPCookieStorage, but it doesn’t store them in real time. And from the actual test, it is found that the delay time is different for different IOS versions, which is a challenge to the developers of M page. Similarly, the request is not read in real time, so it cannot be synchronized with native, resulting in errors in page logic.

The current solution to this problem is to require the client to manually intervene in the storage of cookies. Persisting the cookie of service response to the local, reading the local cookie value when the next WebView starts, and manually writing it to the WebView through Native. The general process is as follows:

Of course, this is not a perfect solution, because occasionally there is the problem of losing cookies during the page routing switch of SPA. The problem of cookie still needs to be explored and solved by us and the students on the client side. Here, if you have any good advice and treatment method welcome to leave a message, we learn progress together.

2. The cache

In addition to cookies, WKWebView cache issues have also been on our radar recently. Because WKWebView internal default to use a set of caching mechanism, developers can operate permissions will be limited, especially IOS8 version, perhaps was just born WKWebView’s sake, is still very imperfect, simply can’t operate (certainly believe that IOS8 will soon exit the historical stage). For some m page static resources, occasionally the cache does not update, which is a real headache.

However, after IOS 9, the system provides a cache management interface WKWebsiteDataStore.


     

    // RemoveCache

    NSSet *websiteTypes = [NSSet setWithArray:@[

    WKWebsiteDataTypeDiskCache,

    WKWebsiteDataTypeMemoryCache]];

    NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];

    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:websiteTypes

    modifiedSince:date

    completionHandler:^{

    }];

Copy the code

For IOS8, you can only delete the file to solve the problem, the general WKWebView cache data will be stored in this directory:

~/Library/Caches/BundleID/WebKit/

You can clear the cache by deleting this directory.


In addition, in addition to the pain points we said above, there is a common webview, that is, every time we open M page for the first time, there must be a webview initialization process, so how to reduce the initialization of webview time, is also an important link we can improve the speed of page opening.

Of course, in order to improve the opening speed of the page, we can also combine the M page with Native to make some offline schemes. At present, there are some offline page projects in the shop, which will not be launched today.

Speaking of which, we have come to the end. Maybe in the near future, various emerging technologies will obscure the halo of some WebView, such as React-Native, small programs, android light application development, etc. But it is undeniable that WebView will not quit the stage of history easily. We will make interaction better, and we also have feelings. There is no such thing as quiet time, but someone is carrying a heavy burden……