On April 14, 2018, Senior Android engineer Jiawei Chen delivered a speech titled “Rambling Android componentization and Web” at the 2018 Internet Developers Conference. As the exclusive video partner, IT mogul Said (wechat ID: Itdakashuo) is authorized to release the video through the review and approval of the host and the speaker.

Read the words: 3326 | 9 minutes to read

Guest Speech video and PPT:t.cn/Rr62oSm

Abstract

This sharing is mainly about the principle and practice of Android componentization and Android Web.

Android dynamic introduction

Dynamic evolution

The dynamic of Android mainly includes three parts, namely componentization, plug-in and modularization. Modularity is easy to understand. It refers to the breaking up of a function into separate modules for decoupling. The most common modules are the network module and the download module. The concepts of plug-in and componentization are fuzzy, and the definitions of different frameworks are different, and the boundaries between them are not obvious.

The figure above shows the understanding diagram of addinization and componentization of an App. The left side represents componentization and the right side represents addinization. Componentized robot is composed of multiple components, plug-in robot is a whole can be distributed.

This diagram looks fine at first glance, but there are still bugs. For example, when a part of the componentized robot becomes big enough, it can actually detach and become a new robot, and when the plug-in robot becomes weaker and weaker, it can also evolve from a single component. In general, the boundary between componentization and pluginization is not obvious, but is conceptually defined depending on the perspective of the site and the approach to the problem.

Problems to be solved in making Android dynamic

Dynamic Android needs to solve four problems, namely Dex loading, resource loading, SO loading, four components loading. Below are the specific parts of Android covered by these four questions.

Dex is the product of android compilation. Java is compiled into class files, and Android compresses these class files to get a Dex. Android resources are more, there are pictures, layout files, animation and so on. SO is a dynamically linked library for Android, usually written in C or C++. The four components of Android, Activity, Service, Content Provider, BroadcastReceiver, must be declared in the androidmanifest.xml configuration file to be loaded normally.

The mainstream dynamic framework

At present, the mainstream dynamic frameworks include Atlas, RePlugin, DroidPlugin and VirtualAPK. Except Atlas defines itself as a componentized framework, the other three define themselves as a plug-in framework. According to personal observation, the main difference lies in the treatment of the four components of Android. Atlas defines these components first and then deals with them through packaging. But last year Atlas also did some plug-in processing, which makes all four of the current frameworks involve plug-ins.

Componentization and plug-in

I believe that we all often encounter the situation that some requirements of products need to be launched urgently. However, unlike H5 development, App can be released at any time and needs to be released through numerous channels. If dynamic release can be achieved, it will have a better promotion effect on the evolution and dynamic development of the whole product.

In addition, it is also important to reduce the package size. Generally, for the same App, the package size of iOS will be larger than that of Android, because iOS cannot dynamically deliver local code, and the domestic Android channel audit is relatively loose. Another concern is hot fixes, which allow us to fix online bugs in real time.

The three points mentioned above are the common purpose of componentization and plug-in, but they are achieved in different ways. General components are packaged with the main project, plug-ins can be packaged independently, and other components need to be packaged to do more work.

Principle of dynamic loading

Dynamic loading of App ideas and so on

As mentioned earlier, one of the problems plugins solve is Dex loading. In Java, class files can be loaded through the ClassLoader, and Android provides BaseDexClassLoader. There are many dexfiles in BaseDexClassLoader, which is the file description of Dex. To realize class loading, you can directly plug the DexFile of the plug-in into BaseDexClassLoader. This approach is called a single-class loader.

Android system classes are loaded by BootClassLoader. PathClassLoader inherits from BootClassLoader and loads App classes. Altlas replaces the PathClassLoader with its own ClassLoader — DelegateClassLoader, where all class loads go through DelegateClassLoader, Each plug-in is loaded by a separate PluginClassLoader, and the lookup of these classes is done by the DelegateClassLoader. This approach is a multi-class loader.

Dynamic loading of App resources

Android assigns each resource a 32-bit Int ID in hexadecimal when packaging. 0x is followed by something like PPTTEEEE, where TT stands for category, EEEE for entry, and PP for all packaged resource ids in Android is 7F.

There are two ways to load resources in Android. The first is resource isolation. This means that each plugin loads Resources from a different resource object. This is to avoid resource conflicts caused by the same resource ID.

The second resource loading method is resource partition, which can change the PP of the resource ID by modifying the android packaging tool, so as to avoid the purpose of ID duplication.

Comparing these two approaches, the advantage of resource isolation is that you do not need to modify the packaging tools, which are written in C++ and are cumbersome to maintain (aapt2 already support resource partitioning). The advantage of a resource partition is resource sharing because it can share a single Resource object while avoiding resource conflicts.

Dynamic loading four components of App loading

There are also two ways to load the four components. One way is to merge the Menifest information into the main APP by merging the manifest information, such as manually copying or packaging it. The other is to declare the four components empty and then start them through the Hock drop system entry.

Google is playing with dynamics

Although dynamic frameworks are very popular in China, they are not so keen on it in other countries. They still use React Native.

Domestic dynamic framework is mainly to study how to achieve the purpose through reflection call or Hock off system API, but there are risks in the system API call, because each version of the private API changes are quite big. For this reason, Google also provides a dynamic framework — Instant, which is loaded through Google Play Service, which has the characteristics of plug-in and component. Resource partition is completed through AAPT2, and the Activity Service is started in the way of embedded and proxy for the loading of the four components.

The Web is changed to introduce

Generally, active pages of apps are developed using H5, because H5 can be dynamically updated. However, the H5 is still not as good as Native in terms of experience, animation and some advanced features.

Componentization is also a problem. In the latest release of Android P, access to private apis is restricted and apps crash when accessed. There are some technical ways to overcome this limitation, but there is another way — SPA (single-page application). For the Web side SPA, it only has an HTML file, and then it is rendered by JS to achieve the purpose of page hopping in an HTML.

Let’s take a look at Webization in Android.

First, React Native. React Native each page is a View, and all pages are in the Activity. It switches the View to jump to the page.

Android provides a layout container called Fragment. An Activity can host many fragments. Switching fragments can also achieve the effect of page switching. This is the Web of Android Native.

Core principles of the Android Web

The core of the Android Native Web implementation is multi-class loaders, resource isolation, and context replacement.

You cannot use a single classloader because you want to ensure that naming and obfuscation rules do not appear with the same class name. Multiple class loaders use different classloaders to load plug-ins, so there is no need to worry about duplicate naming.

Context replacement refers to replacing the Fragment Context with our own custom Context. All classes and resources in the Fragment are accessed through the Context. You can use custom Context to dynamically load external plug-ins for activities.