directory

First, say in front

Second, from the development history of wechat small program

Three, micro channel small program principle analysis

  • Fast loading and native experience
  • Rendering layer
  • preload
  • Internal optimization of the base library
  • Inject applet WXML structure and WXSS style
  • Logic layer

How does JavaScriptCore execute JAVASCRIPT scripts

Five, say again pay treasure small program

  • Runtime architecture
  • Small program SDK

Six, the last

First, say in front:

Since the birth of applets. A hundred schools of thought contend with attitude to show in front of developers. Following the birth of micro channel small program on January 9, 2017, small program market has emerged alipay small program, headlines small program, Baidu intelligent small program and so on. On the basis of wechat small program, each family has gradually optimized and adjusted the architecture for its own business. However, all changes remain the same. Wechat small program is ultimately the originator of small program. Speaking of wechat small program, the optimization of experience made me think that it was Native layer rendering for a long time. The truth is not entirely true. I still can’t believe that webView rendering can create such an experience. This article mainly to a client developer’s point of view, to micro channel small program, Alipay small program. The purpose of this article is to analyze the principle, I do not have real small program architecture design experience.

Speaking of small programs, we have to point out another problem, Apple dad’s approval of HTML5 app updates. Currently, some developers have such questions: Will Hybrid and H5 be rejected by Apple? In fact, from the description of the update, it is not difficult to find that Apple’s main purpose is to target the App whose “core functions are not in the binary file”. In fact, there is no such problem in the design concept or core technology of small programs. Small programs are not APPS, and they are carried by App. The result of optimizing web pages as much as possible. There’s also the fact that vests have become so rampant that they’ve essentially morphed into the “cash Bocai, lottery and charitable donations” types described in the terms, so Apple wants to ban them as much as possible. And from the micro channel small program development documents, micro channel small program is a typical technology-driven product results. There is no such problem with RN class technology. RN is essentially JS invoking Native components through JSCore. In fact, its core is still in the Native end, of course, I still have some questions about code push. As for the dynamic update of RN, it is not difficult to find the attitude of Apple’s father from bang’s description, as long as the dynamic update is not done to bypass the audit, it is acceptable.

Second, from the development history of wechat small program

Micro channel small program is what, micro channel small program is defined as a new way to connect users and services, it can be easily obtained and spread in micro channel, while having excellent use experience. Where does convenience and excellence come from? The small program technology originally comes from the simple call between H5 and Native. Wechat constructs a WeixinJSBridge to provide some Native functions for H5, such as map, player, positioning, taking photos, preview and so on. For detailed implementation of Bridge, see “Writing a Hybrid Framework that is easy to maintain, easy to use and reliable.” However, wechat gradually encountered another problem, that is the experience problem of H5 page. In order to solve the problem of white screen of H5 page, the wechat team introduced the concept of offline package, which is very popular recently. Of course, wechat called wechat Web resources offline storage, which is actually a thing. By virtue of the resource storage capability provided by wechat, Web developers can directly load Web resources from wechat locally instead of pulling them from the server, thus reducing the loading time of Web pages. If you are not familiar with the concept of offline package, please refer to the Principles of Web Offline Technology. However, when the page is loaded with a large amount of CSS and JS, there will still be a blank screen, including the dull sensation of H5 page click events and the experience of page jump. So, based on this problem, small program technology was born.

From the development history of wechat small program, it is not difficult to see that small program is actually the developer of the H5 experience optimization in recent years, which is also in line with what has been said before, small program is actually a typical result of technology to promote products.

Three, micro channel small program principle analysis

Wechat mini program claims to be able to solve the following problems:

  • Fast loading.
  • Greater ability.
  • Native experience.
  • Easy to use and secure wechat data development.
  • Efficient and simple development.

Fast loading and Native experience, both of which are upgrades in experience, are more powerful in fact due to the fact that wechat mini program provides developers with a large number of components, some of which are based on Web technology and some are based on Native technology. In my opinion, this happens to coincide with RN technology. I’ll show you how it works with a small example that mimics an RN implementation.

The high efficiency and simplicity of development is due to the fact that wechat Applets development language is essentially based on web development specifications, which makes it easier for front-end developers to develop applets.

One more important thing is security. Why are small programs safe? Behind will gradually unfold, uncover the mystery of the small program.

Fast loading and native experience

Small program architecture design and Web technology is still a certain difference, absorb some advantages of Web technology, but also abandon the experience of web technology is not good. The most important feature of the applet is the dual threading mechanism, that is, view rendering and business logic are run in different threads. In traditional Web development, the web development rendering thread and the script thread are mutually exclusive, so a long script run on an H5 page can result in an unresponsive or blank screen and a bad experience.

For better experience, execute the page rendering thread and script thread separately:

  • Rendering layer: all the logic related to interface rendering is executed in the webView thread. A small program has multiple pages, and one page corresponds to one webView. Wechat small program limits developers to create a maximum of five pages.
  • Logic layer: Android uses JSCore, iOS uses JavaScriptCore framework to run JS scripts. How to run script files in JavaScriptCore is explained later.

The two-threaded model differentiates applets from most front-end Web frameworks in that it provides better control and a more secure environment. Because the logical layer runs in JSCore and does not have a full browser object, the DOM API and BOM API are missing. Developers on the client side may be unfamiliar with THE DOM, but those familiar with the compilation process should know that when the compiler compiles code, it will perform a parsing process. The abstract syntax tree AST is generated, and the compiler checks whether the expression is valid and the parentheses match. The DOM is actually a tree structure that is parsed by the browser and presented to the user. Manipulating the DOM with JavaScript can change the location of elements at will, which is extremely unsafe for small programs. So another feature that the logical layer brings to applets is ease of control and security. Thread communication is based on the aforementioned WeixinJSBridge: the logical layer notifies the view layer of data changes, triggers page updates in the view layer, and the view layer notifies the triggered events to the logical layer for business processing.

When we perform event operation on the rendering layer, the data will be transmitted to the Native system layer through WeixinJSBridge. The Native system layer decides whether to use Native processing and then passes it on to the logic layer for the user’s logical code processing. After processing, the logical layer will send the data back to the View layer through WeixinJSBridge, and the View will render and update the View.

Rendering layer

According to the “wechat Small Program Developer Documentation”, in the view layer, each page of the small program runs independently on a page level. The applet starts with a single page hierarchy. Each time wx.navigateTo is called, a new page hierarchy is created. In contrast, wX. navigateBack destroys a page hierarchy. Each Web page is run in a separate webView. The advantage is that each webView simply handles the rendering logic of the current page without loading the logic code of other pages. Reducing the burden can speed up page rendering and make it as close to native as possible. This is consistent with the small program jump page experience.

In fact, there is an index. HTML file in the source code of the applet, which is the entry file after the applet starts. When first loaded, the main portal loads the corresponding webView, which includes the view layer and logic layer mentioned earlier. Although the logical layer also provides webView, it does not provide browser-related interface, but simply to obtain the current JSCore, execute the relevant JS script file, which is the root cause of the development of small programs can not directly manipulate DOM.

Calling navigateTo is like opening a new webView every time you open a new page, and keeping it open squeezes memory, which is why the applet limits the number of pages that can be opened.

preload

According to the applets development documentation, for each new page tier, the view tier needs to do some extra preparatory work. Before the mini program starts, wechat will prepare a page level in advance to display the home page of the mini program. In addition, every time a page level is used to render a page, wechat will start preparing a new page level in advance, so that each call to wx.navigateTo will display a new page as soon as possible. From the perspective of the client, it is equivalent to preloading the webView of the next page after opening a new page. This idea coincides with the current popular webView cache pool idea, because on iOS and Android systems, It takes a short time for the operating system to start webView. Preloading improves the speed of page opening and optimizes the problem of white screen.

Internal optimization of the base library

Deeper level that, through small application development tool source code, can find a pageframe. The HTML template file, location in the package. The nw/HTML/pageframe. HTML:

This is the core module of the render layer, which is used to prepare a new page for the applet. Each view layer page content of the applet is generated from the pageframe.html template, including the first page of the applet. By looking at the source code, there is a definition of an attribute var __webviewId__, I guess this is the page ID of each webView page, the logic layer to deal with multiple view layers between the business logic may be through this ID to do the mapping relationship. After the first startup, the background will cache the generated pageFrame. HTML template. When the next page is opened, the cached pageframe. HTML template will be loaded directly. Including small program base library view layer bottom layer, page template information, configuration information, style and other content, so as to avoid repeated generation, quickly open the page, improve page rendering performance.

Inject applet WXML structure and WXSS style

How pageframe.html finally generates the corresponding page is due to a framework called nw.js, the implementation of which is not covered here (mainly because I don’t know).

Logic layer

Now that we’ve seen what the render layer does, let’s take a peek at what the logic layer of the applet does. See eux.baidu.com/blog/fe/ wechat small… It is not difficult to find that the code of sevice layer is implemented by WAService. Js. In fact, the logic layer mainly provides Page, App, GetApp interface and richer WX interface modules, including data binding, event distribution, life cycle management, route management and so on. For details of the interaction between the view layer and the logic layer, see this diagram:

The page logic we wrote was eventually imported into a page called AppService.html and executed separately from app.js; When the Page constructor is called by the applet code, the applet base library records basic information about the Page, such as initial data, methods, and so on. Note that if a page is created multiple times, it does not cause the JS file in which the page is located to be executed multiple times, but only generates an additional page instance (this) based on the initial data. Variables defined directly in the page JS file are shared among all instances of the page. For the logical layer, from the client’s point of view, we should pay more attention to how the JS of the logical layer is injected into JSCore.

How does JavaScriptCore execute JAVASCRIPT scripts

Speaking of JavaScriptCore, we first discuss the construction idea of Hybrid App. Hybird App refers to a Hybrid mode mobile App, which contains both the native structure and embedded Web components. The performance and user experience of this App can not only reach the same level as the original, but also have the greater advantage of fast bug repair and version iteration without release. In essence, Hybird App does not modify the behavior of Native, but loads the delivered resources and renders the interface, similar to WebView. The following uses an example to simulate javascript script execution to enable communication between Native and JS. For details about how to use JavaScriptCore, please refer to “In-depth Analysis of JavaScriptCore” by Daming.

We intend to implement such a function: create native UILabel and UIButton controls and respond to events by issuing JS scripts. First write JS code as follows:

(function(){
 console.log("ProgectInit"); // Automatic render interface after loading JS scriptreturnrender(); }) (); / / JS class labelfunction Label(rect,text,color){
    this.rect = rect;
    this.text = text;
    this.color = color;
    this.typeName = "Label"; } //JS button classfunction Button(rect,text,callFunc){
    this.rect = rect;
    this.text = text;
    this.callFunc = callFunc;
    this.typeName = "Button"; } / / JS the Rect classfunctionRect(x,y,width,height){ this.x = x; this.y = y; this.width = width; this.height = height; } //JS color classfunctionColor(r,g,b,a){ this.r = r; this.g = g; this.b = b; this.a = a; } // The render method interface is written in thisfunction render(){var rect = new rect (20,100,280,30); Var color = new color (1,0,0,1); var label = new Label(rect,"This is a native Label",color);

    var rect4 = new Rect(20,150,280,30);
    var button = new Button(rect4,"This is a native Button.".function(){ var randColor = new Color(Math.random(),Math.random(),Math.random(),1); TestBridge.changeBackgroundColor(randColor); }); Return the control as an arrayreturn [label,button];
}
Copy the code

Create an OC class TestBridge bound to the JavaScriptCore global object:

@protocol TestBridgeProtocol <JSExport>
- (void)changeBackgroundColor:(JSValue *)value;
@end

@interface TestBridge : NSObject<TestBridgeProtocol>

@property(nonatomic, weak) UIViewController *ownerController;

@end
Copy the code
#import "TestBridge.h"

@implementation TestBridge

- (void)changeBackgroundColor:(JSValue *)value{
    self.ownerController.view.backgroundColor = [UIColor colorWithRed:value[@"r"].toDouble green:value[@"g"].toDouble blue:value[@"b"].toDouble alpha:value[@"a"].toDouble];
}

@end
Copy the code

Render (ViewController); render (ViewController);

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "TestBridge.h"@interface ViewController () @property(nonatomic, strong)JSContext *jsContext; @property(nonatomic, strong)NSMutableArray *actionArray; @property(nonatomic, strong)TestBridge *bridge; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Self.jscontext = [jsContext new]; // Bind bridge self.bridge = [TestBridge new]; self.bridge.ownerController = self; self.jsContext[@"TestBridge"] = self.bridge;
    self.actionArray = [NSMutableArray array];
    [self render];
}

-(void)render{
    NSString * path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];
    NSData * jsData = [[NSData alloc]initWithContentsOfFile:path];
    NSString * jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];
    JSValue * jsVlaue = [self.jsContext evaluateScript:jsCode];
    for (int i=0; i<jsVlaue.toArray.count; i++) {
        JSValue * subValue = [jsVlaue objectAtIndexedSubscript:i];
        if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Label"]) {
            UILabel * label = [UILabel new];
            label.frame = CGRectMake(subValue[@"rect"] [@"x"].toDouble, subValue[@"rect"] [@"y"].toDouble, subValue[@"rect"] [@"width"].toDouble, subValue[@"rect"] [@"height"].toDouble);
            label.text = subValue[@"text"].toString;
            label.textColor = [UIColor colorWithRed:subValue[@"color"] [@"r"].toDouble green:subValue[@"color"] [@"g"].toDouble blue:subValue[@"color"] [@"b"].toDouble alpha:subValue[@"color"] [@"a"].toDouble];
            label.textAlignment = NSTextAlignmentCenter;
            [self.view addSubview:label];
        }else if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Button"]){
            UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem];
            button.frame = CGRectMake(subValue[@"rect"] [@"x"].toDouble, subValue[@"rect"] [@"y"].toDouble, subValue[@"rect"] [@"width"].toDouble, subValue[@"rect"] [@"height"].toDouble);
            [button setTitle:subValue[@"text"].toString forState:UIControlStateNormal];
            button.tag = self.actionArray.count;
            [button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
            [self.actionArray addObject:subValue[@"callFunc"]];
            [self.view addSubview:button];
            
        }
    }
}

-(void)buttonAction:(UIButton *)btn{
    JSValue * action  = self.actionArray[btn.tag];
    [action callWithArguments:nil];
}

@end
Copy the code

This completes a simple JS script injection, which actually looks like this:

This is a simple logic to execute JS scripts. In fact, the principle of ReactNative is also based on this, as is the interaction logic between the small program logic layer and the wechat client.

Here, about the micro channel small program rendering layer and logic layer to do what, how to do, optimize what and why to use such a framework to design, basically all combed out. The layering of the applet is clearly intentional, with the middle layer having full control over what the applet does to the interface, as well as monitoring the data being passed and the response time. On the one hand, the behavior of the program is greatly limited, on the other hand, wechat ensures that they have absolute control over the content and experience of the mini program. We can not directly use the DOM and BOM interface provided by the browser in the JS code of the small program. On the one hand, this is because the outer layer of JS code uses local variables to shield. On the other hand, even if we can operate DOM and BOM interface, they correspond to the logical module, and will not affect the page. This structure also shows that the animation and drawing apis of applets are designed to generate a final object rather than execute it step by step. The reason for this is that jSON-formatted data transfer and parsing are expensive compared to native apis, and if called frequently, it is likely to consume too much performance and thus affect the user experience.

In a word, webView rendering, JSCore processing logic, JSBridge thread communication. After a brief analysis of alipay small program, Alipay small program is a rising star, Alipay small program on the basis of wechat small program, do some optimization, just from the technical point of view, a little latecomer on the meaning. At present, alipay technology through the official media account external disclosure of some implementation details are also gradually increasing.

Six, say again pay treasure small program

Under the front-end framework is the small program Native engine, including the small program container, rendering engine and JavaScript engine. This part is mainly to combine the client's native ability with the front-end framework and provide the developer with the interface of the system's underlying ability. In terms of rendering engine, Alipay applet not only provides JavaScript+Webview, but also JavaScript+Native. In scenes with high performance requirements, Native rendering mode can be selected to give users a better experience.

This text comes from the description of Alipay’s open technology blog. From this description, we can find that alipay applet also adopts two parts of rendering engine and JavaScript engine in architectural design, including switching between pages, which is basically consistent with the logic of wechat applet. The following is an architecture diagram of alipay applets application framework:

Runtime architecture

Small program SDK

According to the technical article of Alipay small program opening to the outside world, the architecture design is still very clever, and it is also worth our learning, first look at the picture:

Exclusive! Full analysis of Technical Architecture of Alipay small Program

The architecture design of small program SDK divides it into two parts, one is the core library foundation engine, the other is the plug-in function developed based on the basic library. Viewed from above:

  • The first applet layer is the code layer that applet developers develop using the applet DSL and various components.
  • The second layer and the third layer frame should be some components encapsulated inside the small program and the relevant API provided externally.
  • The fourth and fifth layers are the basic framework for running small programs based on React framework, which is the core layer of small programs and mainly contains the logic processing engine and rendering layer of small programs. Alipay added a Native engine based on ReactNative, which can render UI with Native. According to the introduction of Alipay mPaaS, the React version is currently used in alipay applets, while other Apps in Ant use React Native applets.
  • The base component part and the extensibility part are more like native capabilities based on Bridge calls. The ability to extend should be some of the basic components inside Alipay, as well as enabling small programs through JSBridge.

Alipay small program architecture design using hierarchical design, logic is very clear. In terms of control, it is basically the same as wechat small program. It uses its own SET of DSL to ensure its control ability, and can only use the customized template style provided by the framework to write small programs, which not only ensures security, but also solves the problem of uneven quality of H5 development.

Six, the last

I haven’t written any articles for almost half a year. In this year, I spent all my energy on the business of the company. I analyzed and summarized the current small program structure while taking advantage of the abundant time of the company’s annual meeting, and also participated in the essay contest of digging gold. Of course, the real small program should be much more complex than this. Small program is actually a result of the fusion of large front-end over the years, is a very systematic technical solution, is the concept of technology to promote products. The core of a small program is actually the construction of a rendering layer and a logic layer. So if you were to develop a small program SDK, how would you design them?