Xiong Wenyuan

Jingdong Android client architect

Jingdong Multi-terminal integration platform group core engineer

Participated in the transformation of Android terminal architecture, and had many years of experience in the underlying design of Android system. Led the design and development of system core App and Framework, as well as performance memory optimization.



Flutter: Google’s open source mobile UI framework released the first Beta of Flutter on February 27, 2018. Dart is Google’s mobile application development framework that uses Dart code to build high-performance, high-fidelity iOS and Android applications. Flutter’s tools and libraries help developers easily bring their ideas to iOS and Android devices. If you don’t have any mobile development experience, build beautiful mobile applications with Flutter.

Existing mobile platforms: Apple’s iOS SDKs was released in 2008, and Google’s Android software Development kit was released in 2009. These two SDK packages are based on different programming languages, objective-C and Java respectively. The general structure is as follows:

So the problem is that most apps have to offer different versions for different systems, because the components and languages provided by the systems are different. The problem then was how to develop just one set of code that would work on both ends, and the following three generations of cross-platform platforms emerged.

WebView

This is the first cross-platform framework based on JavaScript and WebViews such as Cordova, PhoneGap, APPCan, Ionic, etc. Applications can be written in Html and displayed in mobile WebViews. And native interaction via JavaScript interfaces.

Disadvantages:

● Slow loading performance, not up to the experience of the native UI;

● Large memory consumption;

● There is a big gap between gesture/animation and native;

● Limited support for related native features.

Reactive view

The second generation of cross-platform frameworks for native experience, such as ReactNative/Weex, generate virtual DOM and further generate native components to make pages composed of native components to achieve native experience. JS code and native code themselves are fast, and bottlenecks often occur when we switch views from one side to the other, so we have to minimize the number of Bridges we use when building high-quality applications.

Disadvantages:

● Bridge is required for communication between virtual DOM and native components;

● Some complex interactive components and animation performance is not up to native performance;

● Compatibility issues between platforms.

Flutter

A third generation cross-platform framework, Flutter also provides a responsive view. Flutter takes a different approach to avoiding performance issues caused by JavaScript Bridges by compiling in a programming language called Dart, which precompiles native code for multiple platforms. This allows Flutter to communicate directly with the platform and use the Skia graphics engine to draw graphics, text, images, animations, etc. It has its own graphics system and no longer relies on native.

Disadvantages:

● High learning cost;

● Large dependent library;

● The current version is in beta.



The framework architecture

The purpose of this layered design is to help developers write less code to implement features. For example, the Material layer is built by combining widgets from the Widget layer, while the Widget layer itself relies on the Rendering layer. The above layering gives us many options for developing apps. First, we can combine existing widgets provided by Flutter or create custom widgets.

Widget

The developer defines a Widget by implementing a build function that returns a Widget tree that more specifically describes the Widget hierarchy in the UI. For example, a ToolBar Widget’s build function might return a horizontal layout, some text, and different buttons, and the framework recursively calls each Widget’s build function until all the widgets have been traversed, then combines the widgets into a Widget tree.

Interaction changes

If the features of a Widget change based on user interaction or other factors, the Widget is stateful. A Flutter provides two types of widgets, a StatelessWidget and a StatefulWidget. The latter can be changed to update the UI by changing state with setState(), and developers can use the StatefulWidget as they see fit:

StatelessWidget:

layout

On Android, UI layout is usually done using XML, and views can be added or removed using addChild and removeChild.

However, a Widget is immutable in a Flutter and can be passed a function that returns a child Widget to the parent Widget. This function controls the creation of child widgets through a bool value.

Event listeners

There are two ways to handle touch in Flutter:

One is to pass an event handling method directly to the Widget.

Or use GestureDetector to implement event listening and processing.

Tap(onTapDown/ onTapUp/ onTap/ onTapCancel)

Double tap(onDoubleTap)

Long press(onLongPress)

Vertical drag(onVerticalDragStart/ onVerticalDragUpdate/ onVerticalDragEnd)

Horizontal drag(onHorizontalDragStart/ onHorizontalDragUpdate/ onHorizontalDragEnd)


Start the animation

In Android we can start an Animation with view.animate (). In Flutter we wrap the Widget in an Animation. In a Flutter, there are AnimationController and Interpolator to control the start of animation.


Canvas

In Android we can use Canvas to draw and customize some UI. In Flutter, there are CustomPaint and CustomPainter to provide algorithms for painting.

The custom Widget

In Android, we implement custom components by inheritance, such as View/ViewGroup components. Flutter does not provide inheritance, but through small component combinations.

Page switching

Android uses Intents to start a page or service, while a Flutter does not have an Intent. Instead, route and Navigator are required to manage the page. Route can be a page or an activity. The Navigator is a Widget that manages routes and can push or pop pages.


The life cycle

In Android, the page life cycle is controlled in both activities and fragments, but Flutter has only one FlutterView. We need to hook WidgetsBinding observer and monitored didChangeAppLifecycleState event messages.

Parameter passing

Switch between the Router and Navigator on the Flutter page. You can also result back the data returned by the Router you push.


Data interaction

Flutter supports a mix of native and Flutter pages, but does not support native components for use in Flutter. The native side has methodChannels to support some of the API calls that Flutter makes to native.


Network request

In Flutter, we have many convenient network uses like Okhttp. In Flutter, we use HTTP package to simply call a network request.

UI components

There are many Material Design and Cupertino (iOS style) widgets, rich gesture apis, and natural smooth sliding animations built into Flutter

ListView/GridView/ViewPager/Card…

Row/Column/Stack and so on

import ‘package:flutter/material.dart’

The UI pages

From the perspective of Android page level, the main page MainActivity inherits FlutterActivity and controls some initialization through FlutterActivityDelegate, including FlutterView. The entire page displayed by Flutter is drawn in the FlutterView.

The foundation of Flutter cross-platform is UI cross-platform. UI drawing does not depend on system components. FlutterView encapsulates the Dart interface into a component that can be used by the Android platform. IOS has the same set of mechanisms that allow different platforms to use the same set of code to draw interfaces.

FlutterView inherits SurfaceView. It can be seen from the API that SurfaceView belongs to the subclass of View and provides double cache function. It is specially produced for making games and has very powerful functions. 2D and 3D effects. Since the Flutter interface is directly inherited from the SurfaceView, its drawing process is no longer platform dependent and decoupled from the invocation of system controls.

The messaging system

MethodChanel is used to implement 7 message module management: multi-language, route navigation, key message, life cycle, system information, user Settings and platform plug-ins, which almost covers all the most differentiated functions of different platforms, and is very dependent on the native system.

MethodChanel:

Keyevent = keyevent = keyevent = keyevent

FlutterView class has two interfaces for handling key events, one is onKeyUp() and the other is onKeyDown(), corresponding to key release and press events respectively. The two methods flow the same, Flutter will intercept key events of the platform in the form of messages.

system_channels.dart

raw_keyboard.dart

raw_keyboard_listener.dart

Other features

SharePreferences, using the plug-in Shared_Preferences

https://pub.dartlang.org/packages/shared_preferences

GPS, using plug-in https://pub.dartlang.org/packages/location

Camera, the use of plug-in https://pub.dartlang.org/packages/image_picker

Sqlite, use Sqlfile https://pub.dartlang.org/packages/sqflite

Notification, using Firebase_Messaging,

https://github.com/flutter/plugins/tree/master/packages/firebase_messaging

UI Hierarchy comparison

It can be seen that there is only one FlutterView inside the Flutter architecture to render the layout of all widgets, so the whole rendering process is independent of the native UI, while ReactNative is similar to the native one by one, mapping UI components in JS to native components.

Flutter UI level

Native /ReactNative UI levels

Memory /CPU/GPU comparison

We did a simple demo to test sliding a list of 100 data. The memory of Flutter was not much different from that of the native, and was relatively stable, while the memory of ReactNative fluctuated greatly. The CPU aspect of the Flutter is nearly twice as high as the native and significantly higher than the ReactNative. With respect to GPU, Flutter was initialized with a high GPU, which should be initialized with FlutterView. GPU rendering could not be seen in the subsequent drag process, because Android Studio could not extract the independent rendering system. So overall native performance is the best.

Flutter performance

ReactNative performance

The original performance

APK size comparison

Under the Flutter Debug package, the lib library contains 86_64/x86/ armeabi-v7A, which is close to 50M. Considering that current mobile phones do not support x86, only Armeabi-v7A was included in the release package. The size of the lib library was reduced to 3.3m. The entire APK will be about 7.5m after compression. Most of the other resources are Flutter code, mainly concentrated under assets, and there is room for optimization.

Compared with ReactNative, its SDK library is about 3.5m, and the JS package size corresponding to a simple page is about 300K, which can greatly reduce the space occupied by Flutter. However, Flutter is a set of engine implemented by itself, which is completely independent of the system platform and takes up a large amount of space. In fact, it is understandable.

Flutter APK structure

ReactNative APK structure

Native APK structure

The performance comparison

ReactNative is a framework developed based on front-end ideas. There is no way to directly implement the native complex ListView/Gridview and other containers, and some complex UI relies on nested superposition of views. In this design, compared with the native design, there will be a lot more views. There are many more View objects than native implementations, resulting in performance degradation. In other words, under complex UI requirements, RN’s UI expression efficiency is much lower than native’s, resulting in low performance. Flutter is based on Skia’s own implementation of a library of UI components, so there is much more flexibility and room for performance optimization at the layout and animation levels.

In terms of development language, JS or DART are declarative writing methods, but JS needs to be explained. Dart is a direct language level that supports node tree writing, and the object creation cost is low. It can be directly compiled into native code (AOT), and VM is more efficient. Dart is much more efficient to run, and dart is a language that also supports JIT/AOT compilation, which is the key to the Hot Reload experience.

Compatibility comparison

All the widgets/animations and event mechanisms that Flutter provides are based on SKIA and are platform independent, so there is a high level of cross-platform compatibility. However, the separate UI system resulted in the failure of many Android/iOS corresponding tools.

All components of ReactNative rely on native, while Android/iOS components and implementation are different, leading to many compatibility issues. Adaptation and bridging between different platforms leads to many functional costs/development costs and performance sacrifices, such as animation/gesture/data containers, etc.

Adaptation contrast

The widgets that Flutter provides are implemented and customized based on SKIA and are platform-independent, so they can maintain high cross-platform compatibility. Flutter eliminates differences from a more fundamental layer for future platform adaptability. Flutter stands on a broader and more controllable base platform for evolution and development. ReactNative always needs to follow the constraints of native development. The costs of bridging, smoothing differences, application layer adaptation, and performance optimization in specific scenarios are all high.

The Flutter engine +Dart language is likely to become the main UI development framework for Google’s Fuchsia system, which will make the best use of its cross-platform nature.

Advantages of Flutter:

● Hot Reload, using the IDE provided directly save the code and Reload, the phone or emulator can see the effect immediately, this point is very easy to debug.

● The concept of Widgets. For Flutter, all components in the mobile app are widgets, enabling an appealing and flexible interface design with a composable collection of Spaces, a rich animation library, and a layered and extensible architecture.

● High quality user experience for cross-platform devices with gPU-accelerated rendering engine and high performance native code runtime.

Disadvantages of Flutter:

● The development language is based on Dart, which adds a significant learning cost for developers.

● UI layout, the level is not obvious, not as direct as native XML writing, complicating the readability of the program.

• Flutter is a new framework. The current market application and community are not mature, and the libraries supported by Flutter are not as good as ReactNative and native.

● Dart code is aoT-compiled to Native, unlike ReactNative, which can be difficult to support hot updates, but based on the API architecture, hot updates should be implemented soon.

• Native components cannot be displayed in Flutter, causing many components to need to be redeveloped, which is not as flexible as ReactNative.

To sum up, the overall architecture of Flutter is revolutionary. Compared with other cross-platforms, it is truly cross-platform. The experience of all platforms is consistent and optimizes the user experience. For the future new operating system will be more adaptable, such as Fuchsia system, it is worth everyone to understand and learn, I believe that in the near future, it will gradually mature and become the mainstream development language.

Our team is also constantly updating, and will become the twin engines of jd multi-terminal integration platform together with JDReact engine in the future.

Resources: https://flutter.io/docs/

Long press to identify the two-dimensional code in the map for immediate attention