1, the preface
Starting from this chapter, we will start with the architectural design scheme of Alipay client, and disassemble the specific implementation of the client in “containerized framework design”, “network optimization”, “performance startup optimization”, “automatic log collection”, “RPC component design”, “mobile application monitoring, diagnosis and positioning”, etc. Lead you to further understand alipay in the client architecture of iteration and optimization process.
This section will introduce the basic idea of alipay Android container framework design.
1.1 Development Background
As Android apps become more powerful and complex in what they can do, it follows that:
-
Android program code and resources are more and more, the size of APK file is more and more large, Android program is more and more complex;
-
As applications iterate, projects expand, and teams grow in number, parallel development based on traditional architectural patterns becomes more difficult.
In addition, mobile clients often face the challenge of dynamic development; Emergency Bug repair and other operation and maintenance requirements; There are also some requirements for online operations, such as dynamic delivery of advertising, push access campaigns, etc. It would be a nightmare for traditional developers to have a client release every time there was an o&M or operational requirement.
Android developers are acutely aware of the importance of a robust, scalable client development framework that supports large-scale parallel development for platform-level client apps. In fact, the robustness and scalability of the client framework design can often achieve half the result in the face of the above requirements and difficulties, especially Android client developers will be deeply benefited.
Then, as a platform level Android client App, how to carry out the framework design, in order to meet the ever-changing difficulties and needs of the mobile Internet era?
1.2 Problems faced by platform-level client frameworks
No. | The problem | describe |
---|---|---|
1 | Project complexity is high, development, compilation, testing, integration are very difficult | Alipay App code 200W lines + |
2 | There are a lot of internal micro-applications (teams) of platform-level APPS, and the parallel development requirements are high | There are dozens of applications inside |
3 | APK size large | Alipay APP 60+M, resulting in the Rom of some manufacturers cannot be installed |
4 | There are various problems with the online version | For example, after the release, the UCSDK was exposed by the cloud platform |
5 | Online activity operation needs | Spring Festival red envelope sweep activity, the plan to dynamically push the new SO file to the client |
We can sum it up: platform-level client frameworks must address the two core issues of modularity and dynamics. (We’ll focus on modularity in this article, and we’ll look at dynamic capabilities in subsequent articles.)
1.3 Framework Design Principles
To solve the above modularity problem, we should follow the following principles to design the client framework:
-
According to the principles of basic technology level and client line of business, the client application program is divided into modules.
-
Each module is developed, maintained, tested and integrated by a small independent team or individual.
-
Modules should be completely decoupled from each other. Modules can rely on each other through interfaces.
-
Each module can be hot-swappable, and the insertion and removal of a single module does not affect the compilation and operation of the whole project.
2. Introduction to Quinox
The Quinox client framework is an implementation of the OSGi-like (like-As) framework. The word Quinox comes from Equinox, an implementation of the famous OSGi framework.
All client APPS based on this framework are built by building blocks one by one, which are called bundles.
3. Introduction to Bundle
3.1 What is a Bundle
Bundle is the basic modular unit of the OSGi specification, which is completely different from android.os.Bundle in Android. A Bundle in OSGi refers to the basic unit of a Java application, which is a modular unit (Jar format), the building block mentioned in the Introduction to Quinox. Applications developed on the Quinox container framework are also made up of bundles (in APK format).
This chapter describes the Bundle form from three different phases of project development:
period | form |
---|---|
Development period | Bundle engineering |
Build period | Bundle package |
The integration period | Integrate the client Bundle baseline |
3.2 Bundle engineering
For regular Android project development, there are usually two (two-level) types of code engineering
Project type | Library | Application |
---|---|---|
Project output | Aar | Apk |
There are three (level 3) types of code engineering for Android projects based on the Quinox container framework
Project type | Library |
Bundle Engineering package |
Application (Test package/installation package /Final APK) |
---|---|---|---|
Project output | Aar | Apk(.jar) | Apk |
There are three things to know about the Bundle project:
-
The Bundle project is very similar to the regular Android Application project: it also has multiple libraries (Android Modules) inside it; Its output is also in APK format.
-
Although the Bundle file is essentially in APK format, the APK cannot be run. Also, when the Bundle project is deployed to the MVN repository, its suffix will be changed to.jar.
-
The Application project (Portal project) based on Quinox is a process of combining bundles (APKs) into one (Final) APK. This is merging, not compiling, so generating the final APK will be very fast because compiling is distributed among bundles. Client programs developed based on Quinox need to use mPaaS custom build tools (that is, package plug-ins).
For the structure diagram of Bundle project, please refer to:
3.3 Bundle package
As mentioned above, the output of the Bundle project is also an APK file.
In the OSGi specification, bundles have many properties. The APK output from the Bundle project differs from the normal APK in that the mPaaS plugin generates a special file for all the Bundle properties to be read by the container in the APK.
In addition to the APK file, the Bundle project build results include:
-
AndroidMannifest.xml
-
Bundle interface package (a JAR package that contains and exposes the interface classes provided by the Bundle)
-
mapping.txt
Bundle files, after being built, are typically deployed to local/remote MVN repositories for reference by other Bundle projects or for integration by the Portal project.
3.4 Bundle baseline
As mentioned earlier, building a Final APK is essentially the process of merging a number of Budnle APKs into the Final APK, and these Bundle APKs are stored in the MVN repository.
So we call the set of gaVs (GroupId, ArtifactId, Vesion) of these bundles the baseline.
When a team/individual has implemented a Bundle project’s new feature and tested it to a releasable state, the version number in the baseline can be updated. We call this process baseline. We believe that the APK extracted from the baseline is stable and operational; Engineering packages without stable bundles should not be baselined.
The Bundle baseline mechanism can well isolate the interaction between modules and ensure the harmony and stability of the development environment between different teams, which meets the original intention of our previous design. Therefore, it can well support the parallel development of multiple teams.
3.5 Bundle Properties and Configuration Methods
For Bundle properties, we can refer to OSGi’s Bundle properties. The Bundle properties defined in the Quinox container are much simpler.
The following table lists all of the Bundle’s properties and configuration methods:
The name of the | instructions | The configuration method |
---|---|---|
Bundle-Name | The name of the Bundle, which exists as the key value. A Bundle with the same name cannot exist in the same client APK | Generated by the mPaaS plugin according to the Bundle project GAV GroupId, ArtifactId, with certain rules. |
Bundle-Version | The version number of the Bundle. The interface packages of each Bundle must be backward compatible with the API version. | Generated by the mPaaS plug-in from Version in the Bundle project GAV |
Init-Level | Have been abandoned | Set the parameter to 1 |
Package-Name | Have been abandoned | Set it to ” |
Component-Name | Android Component declared in the Bundle. This, like the export-Pacakges attribute, is the Bundle’s entry class. | Generated by the mPaaS plugin according to the Activity, Service, BroadcastReceiver, ContentProvider, etc defined in the androidmanifest.xml file |
Package-Id | The packageID of the Bundle project resource. For details, see section 4.2 | The packageId property must be set by the developer in the Bundle project. The value is set to [27, 127] if there are no resources, or to 27 if the Bundle is the root Bundle in the Bundle dependency tree. |
Contains-Dex | Does this Bundle contain code (classes.dex)? | The mPaaS plugin determines whether the Bundle contains the classes.dex node. Note: This property will be corrected to false for statically linked bundles because of the classes.dex merge into the main APK |
Contains-Res | Whether this Bundle contains resources (resources.arsc) | The mPaaS plugin determines whether the Bundle contains the resources.arsc file. |
Native-Library | Does this Bundle contain native so (lib/ XXX /libxxx.so)? | It is determined by the mPaaS plug-in according to the native SO file in the Bundle file. Note: When the Final APK is built, all the so files in the Bundle are merged into the Final APK when the Final APK is built, so this property will be fixed to NULL |
Required-Bundle |
List of bundles that this Bundle depends on: The format is Budnle-Name@Bundle-Version. |
This property is generated by the mPaaS plug-in depending on other Bundle interface packages based on the Bundle project. |
Export-Pacakges |
Bundle export packages (refer to OSGi export package concepts). The Quinox container loads classes from the corresponding Bundle based on the exported package. |
The property exportPackages must be set by the developer in the Bundle project. For example, a non-statically connected Bundle provides a class:
To be used as an interface by other bundles
Configure as an export package (reflection used classes should also be included in the export package). If there are multiple exported packages, separate them with commas (,). For performance reasons, export packages should not be set too many or too wide. |
4. Resource management
4.1 Resource Manager
As Android developers, we know through the Android. The content. res. The Resources object can get string, layout, graphics, animation, and other Resources.
On a Quinox container, it is impossible to manage multiple bundles using native resource management, so we have built a Bundle resource manager to handle the loading and calling of each Bundle instead of the native Android resource management logic.
However, since all bundles are compiled independently, it is highly likely that the resources in them will have the same resource ID. Therefore, when the same resource exists, there may be a conflict, so how to resolve the conflict of resource ids?
4.2 resource id
As Android programmers, we all know that a resource ID is an int that contains four bytes. It is generated by the AAPT tool when building APK projects and defined in R files.
public final class R { public static final class drawable { public static int xxx_bg=0x1e020000; } public static final class id { public static int xxx_id=0x1e050001; } public static final class layout { public static int xxx_layout=0x1e030000; } public static final class string { public static int xxx_str=0x1e040001; }}Copy the code
The meanings of these four bytes are as follows:
-
The first byte is pacakgeId.
-
The second byte is typeId. It represents different resource types such as strings, layouts, images, animations, etc.
-
The third and fourth bytes together are the ID of the resource name
As shown below:
As many readers have already learned, The Quinox framework’s solution to resource ID conflicts is to have the mPaaS packaging plug-in partition isolate each Bundle project using a modified AAPT tool that specifies a different packageId. This ensures that resource ids are not duplicated between bundles. This is why you need to specify the packageId in the Bundle project.
5. Containerization
For now, Quinox is not open source, so this chapter does not cover source code analysis.
We’ve talked a lot about bundles, but the whole core of containerization is how bundles are managed. This brings us to the container manager, whose main job is to coordinate bundles and add, delete, change and check various information.
After the application is started, our container manager reads the configuration information and generates instances of information for each Bundle.
5.1 Container Manager: Add and Delete
The Quinox container framework aims to solve the core problems of modularity and dynamics of Android client apps. The addition and deletion capabilities are more used to implement dynamic capabilities, facilitating the container to dynamically add and delete bundles. Since this article focuses on modularization capabilities, we will focus on the dynamic capabilities of containers in this section.
5.2 Container Manager: Changed
As for a container manager’s capabilities, Quinox takes advantage of these capabilities for startup optimization and adaptation, but we don’t have to analyze too much source code here.
5.3 Container Manager: Query
The container manager’s most frequently used functional interface is the query interface:
-
Query by BundleName (remember the require-bundle property of bundles?)
-
Query by packageId (non-27 Bundle)
-
Query by Android Component class Name (remember the Bundle’s component-name property?)
Through the query interface of the manager, we coordinate and communicate between bundles to complete the function of containerization.
5.4 Starting Components
In addition to the container manager, another important point is the component’s initiator. Quinox customizes the native Android Activity startup process to manage your Activity creation and lifecycle.
At the same time, since the Activity is created by our own launcher, we can also make some customized changes to the Activity, so that it can better adapt to the container system. For example, we can give our Activity a custom resource manager, manage the Activity stack and provide interfaces, and do some aspects of the Activity’s life cycle.
The custom component launcher also has the benefit of being able to run an Activity dynamically. Dynamic running refers to running activities that are not registered in the Manifest from the factory. This function is more to support the ability of the container to be dynamic.
Because the implementation logic of Activity dynamic operation involves more core technical points, so we do not carry out specific implementation analysis for the time being.
6, summary
Through this section, we have preliminarily understood the design ideas and corresponding modules of Android container framework. There are many technical points that we can’t cover because of space constraints.
We also look forward to your feedback on the design ideas and specific practices of Android container framework. Welcome to discuss and communicate with us.