In this section, I'll explain the evolution of mobile development technologies. To understand what makes flutter an exciting technology, we must understand how mobile development was before and how flutter makes it different from all those.
Native development refers to the mobile application development using development tools, SDKs, and languages supported by a particular operating system such as iOS or Android. For example, a native Android app refers to an application developed by using Java or Kotlin using the Android SDK directly; while a native iOS app refers to an application developed by directly using the iOS SDK using languages like Objective-C or Swift.
Advantages of Native Development:
- Access to all features of the platform (GPS,Camera,Microphone).
- Flawless performance.
- Complex animation and drawing can be achieved.
- Provides best user experience.
Disadvantages of Native Development:
- Platform-specific, high development costs.
- Different platforms must maintain different codebases, and development time increases accordingly.
- Delivering the same feature across all platforms at the same time sometimes becomes challenging because of different codebases.
In the early days of mobile development, app development for businesses was not complicated, and native development could cope with product demand iterations. However, in recent years, with the advent of the Internet of Things and the rapid advancement of the Internet, in many business scenarios, traditional pure native development can no longer meet the growing needs of businesses.
Mainly manifested in:
- As the demand for dynamic content surges, when the demand changes, native applications need to update the app through version updates which involve pushing updated build to the play store or app store and going through all the review and release process. Which is difficult to deal with in this fast-changing Internet era. So the necessity of dynamic application updates (application content can be updated without publishing a version) becomes crucial.
- Business requirement changes rapidly, and development cost becomes lofty. As native development requires maintaining two codebases and two development teams for Android and iOS, when the app is updated then both the labor cost and development time increases..
To sum up, pure native development mainly faces two problems of dynamization and development cost, and for these two problems, some cross-platform dynamization frameworks have been born.
For the problems faced by native development, people have been trying to find good solutions, and today, there are many cross-platform frameworks (note that the "cross-platform" in this book refers to Android and iOS), depending on this, it is mainly divided into three categories:
- H5+ native (Cordova, Ionic, WeChat applet)
- JavaScript development + native rendering (React Native, Weex)
- Self-painted UI+Native (QT for mobile, Flutter)
In the following chapters, we will look at the principles, advantages and disadvantages of these three types of frameworks one by one.
The main principle of this type of framework is to implement part of the APP that needs to be dynamically changed through H5 (HTML5), and load it through the native web page loading control WebView (Android) or WKWebView (iOS) (in the future, if there is no special instructions, we will use WebView to uniformly refer to it. Generation of web page loading controls in Android and iOS). In this way, the H5 part can be changed at any time without publishing, and dynamic requirements can be met; at the same time, because the H5 code only needs to be developed once, it can run on both Android and iOS platforms at the same time, which can also reduce development costs. In other words, the more functions of the H5 part, the lower the development cost. We call this H5+ native development model hybrid development , and apps developed in hybrid models are called hybrid apps or hybrid apps . If most of the functions of an app are implemented by H5, we call them Web APP .
Typical representatives of current hybrid development frameworks are: Cordova, Ionic and WeChat applets. It is worth mentioning that WeChat applets are currently rendered in webview, not native rendering, but native rendering may be used in the future.
As mentioned earlier, native development can access all the functions of the platform. In hybrid development, H5 code runs in WebView, and WebView is essentially a browser kernel, and its JavaScript is still running in a sandbox with restricted permissions. Therefore, there is no access permission for most system capabilities, such as inability to access the file system, and inability to use Bluetooth. Therefore, all functions that cannot be implemented by H5 need to be done natively. The hybrid framework generally implements some APIs for accessing system capabilities in the native code in advance, and then exposes them to WebView for JavaScript to call. In this way, WebView becomes the communication bridge between JavaScript and native API, mainly responsible for JavaScript and native API. Call messages are transferred between, and the transfer of messages must comply with a standard protocol, which specifies the format and meaning of the message. We use WebView to communicate between JavaScript and native and implement a certain message transfer protocol The tool is called WebView JavaScript Bridge , or JsBridge for short , and it is also the core of the hybrid development framework.
Let's take Android as an example to implement a native API for obtaining the phone model for JavaScript calls. In this example, the process of calling native API by JavaScript will be shown. Readers can intuitively experience the process of calling. We use the wendux's open source dsBridge on Github as JsBridge for communication. dsBridge is a cross-platform JsBridge that supports synchronous calling. In this example, only the synchronous calling function is used.
- First implement the API to get the phone model in the native
getPhoneModel
class JSAPI {
@JavascriptInterface
public Object getPhoneModel(Object msg) {
return Build.MODEL;
}
}
- Register native API to JsBridge through WebView
import wendu.dsbridge.DWebView
...
//DWebView inherits from WebView, provided by dsBridge
DWebView dwebView = (DWebView) findViewById(R.id.dwebview);
//Register native API to JsBridge
dwebView.addJavascriptObject(new JsAPI(), null);
- Call native API in JavaScript
var dsBridge = require("dsbridge")
//Directly call the native API `getPhoneModel
var model = dsBridge.call("getPhoneModel");
//print model
console.log(model);
The above example demonstrates the process of JavaScript calling native API. Similarly, in general, the excellent JsBridge also supports native calling JavaScript, and dsBridge also supports it. If you are interested, you can go to the github dsBridge project homepage to view.
Now, let’s look back. Hybrid applications are nothing more than pre-implementing a series of APIs for JavaScript calls in the first step, so that JavaScript has the ability to access the system. Seeing this, I believe you can also implement a hybrid development framework yourself. .
The advantage of hybrid applications is that the dynamic content is H5, the web technology stack, the community and resources are rich, but the disadvantage is that the performance is not good. For complex user interfaces or animations, WebView is unbearable.
This article mainly introduces the cross-platform framework principle of JavaScript development + native rendering .
React Native (RN for short) is a cross-platform mobile application development framework open sourced by Facebook in April 2015. It is a derivative of Facebook's earlier open source JS framework React in the native mobile application platform. It currently supports both iOS and Android platforms. RN uses Javascript language, JSX similar to HTML, and CSS to develop mobile applications. Therefore, technical personnel familiar with Web front-end development can enter the field of mobile application development with little learning.
Since RN and React have the same principles, and Flutter is also inspired by React, many ideas are also connected, so it is necessary for us to learn more about React principles. React is a reactive web framework. Let's first understand two important concepts: DOM tree and reactive programming.
The Document Object Model (DOM) is a standard programming interface recommended by the W3C organization for processing extensible markup languages. It is a platform and language-independent way to access and modify the content and structure of a document. In other words, this is a standard interface for representing and processing an HTML or XML document. Simply put, DOM is the document tree, which corresponds to the user interface control tree. In front-end development, it usually refers to the rendering tree corresponding to HTML. However, the broad DOM can also refer to the control tree corresponding to the XML layout file in Android, and the term DOM operation It means to directly manipulate the rendering tree (or control tree). Therefore, you can see that the DOM tree and the control tree are equivalent concepts, but the former is often used in Web development, and the latter is often used in native development.
An important idea is put forward in React: the UI changes automatically when the state changes, and the React framework itself performs the work of rebuilding the user interface in response to user state changes. This is a typical reactive programming paradigm. Let’s summarize React.
React principle:
- Developers only need to pay attention to state transition (data). When the state changes, the React framework will automatically rebuild the UI based on the new state.
- After the React framework receives the user state change notification, it will calculate the changed part of the tree through the Diff algorithm according to the current rendering tree, combined with the latest state change, and then only update the changed part (DOM operation), thereby avoiding the entire tree Tree reconstruction to improve performance.
It is worth noting that in the second step, the React framework will not immediately calculate and render the changed part of the DOM tree after the state changes. On the contrary, React will build an abstraction layer on the basis of the DOM , namely the virtual DOM tree. Any changes made to the data and state will be automatically and efficiently synchronized to the virtual DOM, and finally synchronized to the real DOM in batches, instead of operating the DOM every time it changes. Why can't you directly manipulate the DOM tree every time you change? This is because every DOM operation in the browser may cause the browser to redraw or reflow:
- If the DOM only changes in appearance style, such as a color change, it will cause the browser to redraw the interface.
- If the structure of the DOM tree changes, such as size, layout, node hiding, etc., the browser needs to reflow (and re-layout).
Browser redrawing and reflow are both relatively expensive operations. If each change is performed directly on the DOM, this will cause performance problems, and batch operations will only trigger one DOM update.
Questions: Shouldn’t the Diff operation and DOM batch update be the responsibility of the browser? Is it appropriate to do it in a third-party framework?
An illustration is required here
As mentioned above, React Native is a derivative of React in the native mobile application platform. What is the main difference between the two? In fact, the main difference is what is the object mapped by the virtual DOM? The virtual DOM in React will eventually be mapped to the browser DOM tree, and the virtual DOM in RN will be mapped to the native control tree through JavaScriptCore.
JavaScriptCore is a JavaScript interpreter, which has two main functions in React Native:
- Provide a runtime environment for JavaScript.
- It is a communication bridge between JavaScript and native applications. It has the same function as JsBridge. In fact, in iOS, many JsBridge implementations are based on JavaScriptCore.
The process of mapping virtual DOM to native control in RN is divided into two steps:
- Layout message transfer; transfer virtual DOM layout information to native;
- Natively render the control tree through the corresponding native control based on the layout information;
So far, React Native has achieved cross-platform. Compared with hybrid applications, because React Native is a native control rendering, the performance will be much better than H5 in hybrid applications. At the same time, React Native uses a web development technology stack and only needs to maintain a code, which is also a cross-platform framework.
Weex is a cross-platform mobile development framework released by Alibaba in 2016. Its ideas and principles are similar to React Native. The biggest difference is the syntax level. Weex supports Vue syntax and Rax syntax. Rax's DSL (Domain Specific Language) syntax is based on Created by React JSX syntax. Unlike React, JSX is mandatory in Rax. It does not support creating components in other ways, so learning JSX is a necessary foundation for using Rax. React Native only supports JSX syntax.
The main advantages of JavaScript development + native rendering are as follows:
- Using the Web development technology stack, the community is huge, quick to get started, and the development cost is relatively low.
- Native rendering, performance is much higher than H5.
- The dynamic is better and supports hot update.
Disadvantages:
- When rendering, communication between JavaScript and native is required. In some scenes, such as dragging, it may cause freezing due to frequent communication.
- JavaScript is a scripting language that requires JIT (Just In Time) to execute, and there is still a gap between execution efficiency and AOT (Ahead Of Time) code.
- Because rendering relies on native controls, controls on different platforms need to be maintained separately, and community controls may lag when the system is updated; in addition, its control system will also be restricted by the native UI system, for example, in Android, gesture conflicts The disambiguation rules are fixed. When using nested controls written by different people, gesture conflicts will become very tricky.
In this article, we look at the last cross-platform technology: self-painted UI + native. The idea of this technology is to draw the UI by implementing a unified interface rendering engine on different platforms without relying on the system's native controls, so the consistency of the UI on different platforms can be achieved. Note that the self-drawing engine solves the cross-platform problem of the UI. If it involves calling other system capabilities, it still involves native development.
The advantages of this platform technology are as follows:
-
High performance; since the self-drawing engine directly calls the system API to draw the UI, the performance is close to that of native controls.
-
Flexible, easy to maintain the component library, high fidelity and consistency of UI appearance; since UI rendering does not rely on native controls, there is no need to maintain a set of component libraries separately for controls of different platforms, so the code is easy to maintain. Since the component library is the same set of code and the same rendering engine, the display appearance of the component can achieve high fidelity and high consistency on different platforms; in addition, because it does not rely on native controls, it will not be restricted by the native layout system. This layout system will be very flexible.
Disadvantages:
- In order to ensure UI rendering performance, self-drawing UI systems generally use AOT mode to compile their release packages, so after the application is released, it cannot dynamically deliver code like Hybrid and RN frameworks that use JavaScript (JIT) as the development language .
- Low development efficiency: QT uses C++ as its development language, and programming efficiency directly affects APP development efficiency. As a static language, C++ is not as flexible as a dynamic language such as JavaScript in terms of UI development. In addition, C++ requires developers Manually manage memory allocation, there is no garbage collection (GC) mechanism in JavaScript and Java.
You may have guessed that Flutter belongs to this type of cross-platform technology. Yes, Flutter is implementing a set of self-drawing engine and has its own UI layout system. However, the idea of self-drawing engine is not a new concept, and Flutter is not the first to try to do this. Before it, there is a typical representative, namely the famous QT.
Qt is a cross-platform C++ graphical user interface application development framework developed by Qt Company in 1991. In 2008, Qt Company technology was acquired by Nokia, and Qt became a programming language tool of Nokia. In 2012, Qt was acquired by Digia. In April 2014, the cross-platform integrated development environment Qt Creator 3.1.0 was officially released, which realized full support for iOS, added WinRT, Beautifier and other plug-ins, abandoned GDB debugging support without Python interface, and integrated Clang-based C /C++ code module, and made adjustments to Android support. So far, it has realized full support for iOS, Android, WP, and it provides application developers with all the functions needed to build a graphical user interface. However, although QT has achieved great success on the PC side and is highly sought after by the community, it has not performed well on the mobile side. In recent years, although QT’s voice can be heard occasionally, it has always been weak and ultimately failed regardless of it's very interesting technology.
Main resons behing QT's Failure :
- QT mobile development community is too small, lack of learning materials, and bad ecology.
- The official promotion is not good and the support is not enough.
- QT was late as the market has been occupied by other dynamic frameworks (Hybrid and RN)
- In mobile development, C++ development has inherent disadvantages compared to Web development stacks, and the direct result is that QT development efficiency is too low.
Based on these four points, although QT is a pioneer in the development of cross-platform self-drawing engines on mobile, it has become a martyr.
"Before coming out after a thousand calls", for so long, and now finally waiting for the protagonist of the book to appear!
Flutter is a framework released by Google for creating cross-platform, high-performance mobile applications. Like QT mobile, Flutter does not use native controls. Instead, both implement a self-drawing engine and use its own layout and drawing system. So, we are worried, QT mobile is facing the same problem as Flutter, will Flutter follow the footsteps of QT mobile and become another martyr? To return to this question, let's take a look at the birth process of Flutter:
- At the Google I/O conference in 2017, Google launched for the first time a new cross-platform, high-performance mobile application framework-Flutter.
- In February 2018, Flutter released the first Beta version. In May of the same year, at the 2018 Google I/O Conference, Flutter was updated to the beta 3 version.
- In June 2018, Flutter released the first preview version, which means that Flutter has entered the final stage before the official version (1.0) is released.
- On December 4, 2018, Flutter 1.0 was released at the Flutter Live event, denoting the first "stable" version of the Framework.
Observing its development, in May 2018, Flutter entered the top 100 on the GitHub stars list, with 27k stars. Today (Feb 3, 2021), there are already 112K Stars. After a period of more than 3 years, the Flutter ecosystem has grown rapidly. It can be seen that Flutter has been warmly welcomed among developers, and its future development is worth looking forward to!
Now, let's compare with QT mobile:
- Community: Judging from Github, active users of Flutter are growing rapidly. Judging from the questions on Stackoverflow, the Flutter community is now very large. Flutter's documentation and resources are becoming more and more abundant. Many problems encountered during the development process can be answered in Stackoverflow or its github issue.
- Technical support: Google is now vigorously promoting Flutter. Many of the authors of Flutter are from the Chromium team and are very active on github. From another perspective, from the frequent version releases of Flutter in the first half of this year, it can be seen that Google's investment in Flutter is not small, so there is no need to worry about official technical support.
- Development efficiency: Flutter's hot reloading can help developers quickly test, build UI, add features, and fix errors faster. Millisecond-level hot reloading can be achieved on iOS and Android emulators or real devices without losing state. This is really great. Believe me, if you are a native developer and after experiencing the development flow of Flutter, you probably don't want to go back to native. Based on the above three points, I believe that readers, like the author, have their own conclusions about the future of Flutter. Up to now, we have a comprehensive understanding of mobile development technology, and then we are going to enter the topic of this book, are you ready!
This chapter mainly introduces three cross-platform technologies in current mobile development. Now we compare them from a framework perspective, as shown in Table 1-1:
Technology Type | UI Rendering | Performance | Efficiency | Dynamic | Frame Representative |
---|---|---|---|---|---|
H5+Native | Webview Rendering | General | High | Stand By | Cordova,Ionic |
Javascript+Native Rendering | Native Control Rendering | Good | Stand By | In | React Native, Weex |
Self Painted UI + Native rendering | Call system API Rendering | Good | Stand By | Flutter high, QT low | QT, Flutter |
Table 1-1: Cross-platform technology comparison
The development language in the above table mainly refers to the development language of the UI. The development efficiency refers to the efficiency of the entire development cycle, including coding time, debugging time, and troubleshooting and compatibility time. Dynamization mainly refers to whether to support dynamic code delivery and whether to support hot updates. It is worth noting that Flutter's Release package is compiled in Dart AOT mode by default, so it does not support dynamization, but Dart also has JIT or snapshot running modes, which all support dynamization.