This article is my exploration of some of the principles of cross-platform development. Cross-platform development has long been the goal of many developers, how convenient it is to have one set of code running directly on different platforms! Of course, my level is limited, understanding is relatively shallow, there must be mistakes, in the reading on the one hand to be careful, to avoid being misled, on the other hand, if you find mistakes, please criticize and correct, thank you very much!

There are differences between computers in hardware and operating systems

In terms of hardware, the main difference is CPU. At present (2020), there are mainly AMD64 and ARM cpus, one is complex instruction set, the other is simplified instruction set. The CPU of AMD64 architecture is of high power consumption and strong performance, which is mainly used in computers. Running Windows and MacOS/Linux/BSD Operating systems Arm architecture has relatively low CPU power consumption and weak performance. It is mainly used for mobile phones and running Android/iOS operating systems. In addition, there are a growing number of ARM-based products, such as raspberry PI, which can run on Windows (although raspberry PI originally ran on Linux); Apple has also recently developed an ARM-based M1 chip that runs on MacOS. Linux distributions also have many ARM versions of the operating system. It can be said that at this point in time, the ARM architecture can run on all the major operating systems.

In terms of the operating system, now (2020) mainly divided into two categories, namely, Windows and Unix&Unix – like, which contains the MacOS/iOS/Android/Linux/BSD, etc. As some computers get smaller, while tablets get bigger, and many computers have touch screens, and a lot of work can be done on phones, the gap between PC and mobile operating systems is narrowing, and they’re learning from each other. However, nowadays, there are still obvious differences between computer and mobile operating systems. The computer side is more suitable for office, and the use of professional and high-performance software, while the mobile end is more suitable for instant messaging, information reading, simple event processing and other software. So there are two types of cross-platform, one is across Windows/MacOS/Linux/BSD, one is across Android/iOS, and of course there are some that are both, and very successful, such as browsers.

The browser

In fact, I think the most successful cross-platform technology today is the browser. One set of code can run on different platforms, and the differences between different operating systems are all masked by the huge and complex code of the browser. The principle of the browser I have previously little analysis, see, mainly is the rendering engine and JS interpreter these two core components, through the browser’s other “interface class” module (such as network module, user interface back-end module, etc.), and then through the operating system, receive or call different hardware process. We write front-end code (native HTML+CSS+JavaScript or Vue or React) that just needs to be understood by the rendering engine and JS interpreter. We don’t care how browsers smooth different operating systems, and we don’t care how different operating systems smooth different cpus and devices.

However, browsers have some disadvantages, which I think are mainly in three aspects:

  1. There is no immersive experience
  2. Not enough permissions to call hardware
  3. Performance is not good enough

The first problem is that the browser has a border, doesn’t have good offline caching controls, doesn’t have a notification push mechanism, and doesn’t have an OS style UI, which makes the user feel “temporary” rather than immersive. This is especially true of mobile devices.

Problem 2 is that the front-end code always needs to obtain hardware resources through the browser, but due to various considerations and restrictions, the browser can not give enough resources to the front-end, and the front-end does not have large permissions to call system resources.

The third problem is that JavaScript is an interpreted language and needs to be interpreted every time it is run, which is not as efficient as software developed in compiled languages. Even with the introduction of mechanisms such as JIT, this problem cannot be fundamentally solved.

There are different solutions to these three problems. Specifically for problem 1, there are PWA, small program, etc. Specifically for problem 2, there is nodejs; Specifically for question 3, there is WebAssembly.

Cross-platform technology for the front-end technology domain

For cross-platform technologies in the front end, there should be solutions for all three of these problems. Currently, the mainstream technologies are Electron, React Native, Weex, and Cordova.

  • Electron

    Electron straddles Windows/MacOS/Linux operating systems. Electron integrates the NodeJS side and browser side. Electron’s main process has more privileges than the browser, and the JavaScript interpreter can directly operate on system resources, storing, networking, pushing messages, and so on. Electron also allows developers to customize the shell to enhance user engagement. So Electron solves the problem of 1 and 2.

    Electron does not have a solution to problem 3, and there is no fundamental performance difference between an application packaged with Electron and a web page in a browser.

  • React Native

    React Native is built across the Android/iOS operating system. Electron no longer uses the browser architecture, eliminating the browser rendering engine and maintaining only a JavaScript interpreter that connects to the system’s native API via a Bridge. This approach is different from Electron, which retains the browser rendering engine and calls the graphical interface of the operating system through the browser rendering engine, whereas React Native does away with the browser rendering engine and uses the system Native rendering method for pages. This way, the page display is more native, the native rendering speed and rendering effect will be better than using the browser rendering engine; JavaScript also gets more hardware permissions. React Native basically solves problems 1 and 2.

    React Native does not substantially change question 3 because the App is still interpreted by JavaScript at runtime.

When comparing React Native and Electron, one is a reformist and the other is a reformist for the “system” of the front-end browser architecture. React Native goes directly to Native languages, naturally with the benefits of “immersion” and “access to system resources “, without going through the browser. Electron retains the browser mechanism, but in combination with NodeJS technology, it can also gain “immersion “,” access to system resources “and other features.

I don’t know much about Weex, but I understand it as using Vue’s React Native. Cordova, on the other hand, I think of it as Electron for the mobile platform, but it adds some apis to the rendering side’s JavaScript to access system resources (Electron is implemented by docking with NodeJS), and if you want to customize the system functionality, you need to use the development language of the platform.

As for whether code developed using these technologies can be deployed to the Web, the first step is to ensure that the software does not have access to system resources (such as reading and writing files) and does not call apis, which means that the software is a static display page. In this case, the front-end parts of Electron, Cordova and Weex can be reused on the Web side, but React Native is written differently from React, so it is not easy to reuse on the Web side.

On the other hand, current frontend to cross-platform technologies do not address the performance issues of interpreted languages. If you want to “improve performance,” the idea is the same: find a Level close to the bottom but independent of the operating system platform. In the future, if WebAssembly or similar technologies become mature, this problem will be solved to some extent.

technology Across the platform JavaScript interpreter Rendering engine How to interact with the system Page development techniques
Electron Windows/ MacOS/ Linux V8 Blink Interacting with nodeJS at the system level via Web Api Any front-end technology
Cordova iOS/ Android JavaScriptCore(iOS)/ V8(Android) Webkit(iOS)/ Blink(Android)/ Custom Interact with system-level Native Code(Java, Swift) via specific apis Any front-end technology
React Native iOS/ Android JavaScriptCore Mobile platform native engine Interact with system-level Native Code(Java, Swift) via specific apis React
Weex iOS/ Android JavaScriptCore(iOS)/ V8(Android) Mobile platform native engine Interact with system-level Native Code(Java, Swift) via specific apis Vue

A compromise between cross-platform and performance conflicts

As we know, high-level programming languages have two basic types: compiled and interpreted. The former is represented by C/C++, while the latter is represented by Python and JavaScript. Compiled languages convert code into platform-specific machine code for execution, so they are fast, but if they want to be cross-platform, they need to be compiled separately (such as Qt) or written separately; Interpreted languages run as they are interpreted, which has the advantage of being cross-platform, but the process of repeatedly interpreting high-level languages into machine code results in low performance.

Interpreted languages are inefficient because they are interpreted every time. Because the platform is different, it cannot be explained in advance. Another strategy is runtime optimization, where the snippet of code that is always repeatedly interpreted is recorded and the next time it is used, the machine code is executed directly, eliminating the need for interpretation. This is the JIT technique. In the browser, the JIT technique runs into a problem where JavaScript variables are untyped, so the machine code from the last time may not be reused, but interpreted again. So one idea is to turn JavaScript into a strongly typed language, which is TypeScript.

Another way to think about it is, instead of JIT, why don’t we just put the precompiled byte code in the browser and execute it? The fundamental problem here is that you need to run high-performance programs across different hardware platforms that exist. Interpreted languages have strong cross-platform capability, but high-level languages are costly to interpret. Compiled language development programs perform better, but require multiple compiles into machine code to accommodate multiple platforms. We need to find a balance between high level languages and machine code. This point should be as close to the underlying machine code as possible to reduce interpretation time and solve performance problems as much as possible; At the same time, it has to balance the differences between different platforms, and the language that is carried upwards must be basically platform independent. Use high-level language (developer’s favorite language, development ecology language, suitable for the project development language) development, development in the interpretation of the runtime environment (real-time debugging) development, deployment into this intermediate code, improve the performance of the program.

WebAssembly was designed with this in mind. I left out weakly typed JavaScript and developed it in a strongly typed language like C++. The compiler compiled it into wasm bytecode, which was interpreted into machine code when the program was run, and introduced a JIT mechanism to further improve performance.

The success of the Web is linked to its cross-platform nature, and if we can solve the problem of its lower performance than native applications, Web technology will once again shine and become better at writing complex software. Aside from the Web domain, the DESIGN of the JVM is based on the idea that high-level languages such as Java are compiled into class virtual machine code, which is interpreted by the JIT virtual machine. It can be seen that a combination of the advantages of compilation and interpretation is an effective way to maintain convenient development and efficient program operation under different platforms.

Other cross-platform technologies

These are just some of the cross-platform technologies for producing graphical interface software from the front end (HTML+CSS+JavaScript), and the mainstream cross-platform technologies for developing software in other languages (graphics & command lines).

The first is C/C++(collectively, C++). If you use only the C standard library, which is available on Windows/MacOS/Linux, you can compile the C++ code to form a command line executable file on each platform. If you need to call the system Api, you need a tool to unify the way you use the system Api. For example, Qt. Qt is a development suite that flatters the different apis of the operating system, and is typically used to develop Windows/MacOS/Linux cross-platform graphics applications. Qt development applications still need to be compiled separately.

The Dart language’s Flutter technology, WHICH I feel is similar in mechanics to Qt, but across iOS/Android/Web platforms. Dart is a compiled language, but when applied to the Web platform, Dart is translated into JavaScript to run in an interpreted language.

If you look at Java, Java is an interpreted language, or it’s more accurate to say that Java is a (mixed compiled) interpreted language, and class bytecode is the intermediate code of the Java language that runs on the JVM. Unlike Qt, the JVM exposes essentially the same interfaces across operating systems, and the class bytecode that Java translates into needs to be interpreted at runtime depending on the platform.

Python is also a (mixed compiled) interpreted language, and in the same way as Java, there are two main types of bytecode that Python converts to, one that runs on the PVM and one that can run on the JVM.

JavaScript running on NodeJS has no concept of bytecode and is (purely) an interpreted language, but it also requires the introduction of an intermediate code mechanism such as WebAssembly to improve performance.