This abstract is selected from Ren Yugang’s “Exploration of Android Development Art”, introduces the principle and three key issues of Android plug-in technology, and gives an open source plug-in framework initiated by the author.

Dynamic loading (also known as plug-in technology) plays an important role in technology-driven companies as projects grow larger and larger to reduce application memory and CPU usage, as well as to enable hot plugging, which means updating certain modules without releasing a new version. Dynamic loading is a very complex technology, here basically introduces the three basic problems of the technology of dynamic loading, as for the realization of the complete dynamic loading technology refer to the author of open source plug-in framework DL (https://github.com/singwhatiwanna/dynamic-load-apk). Multiple developers contributed code together during the project.

Different plug-in schemes have their own characteristics, but they must solve three fundamental problems: resource access, Activity lifecycle management and ClassLoader management. Before introducing them, we should first understand the concept of host and plug-in. Host refers to ordinary APK, while plug-in generally refers to dex or APK after processing. In the mainstream plug-in framework, APK with special management is used as plug-in, and the processing method is often related to compilation and packaging. In addition, many plug-in frameworks need to use the concept of proxy Activity, plug-in Activity is mostly started with a proxy Activity to achieve.

1. Access to resources

As we know, when the host program calls the uninstalled plug-in APK, a big problem is how to access resources. Specifically, any resources in the plug-in starting with R are not accessible. This is because there are no resources for the plug-in in the host program, so it is not possible to load resources for the plug-in through R, and the program will throw an exception: the resource corresponding to such and such id cannot be found.

To solve this problem, some people propose that the resources in the plug-in are preset in the host program, although this can solve the problem, but it will have some disadvantages. First, it requires the host and plug-in to hold the same resource at the same time, increasing the size of the host APK. Second, under this model, resources need to be copied into the host program every time a plug-in is released, which means that the host program needs to be updated every time a plug-in is released, which goes against the idea of plug-ins.

Because the purpose of pluginization is to reduce the size of the host apK package while reducing the frequency of the host program’s updates and allowing free loading of modules, this approach is not desirable, and it limits the important feature of the plug-in’s online updates. Another option is to extract the resources from the plug-in and then read them through the file stream, which is theoretically possible but practically difficult. Firstly, different resources have different file stream formats, such as images and XML. Secondly, the resources loaded for different devices may be different, and how to select the appropriate resources is also a problem to be solved. Based on these two points, this method is not recommended, because it is difficult to implement. To facilitate resource management of plug-ins, here is a reasonable approach.

As we know, the Activity is primarily done with ContextImpl. The Activity has a member variable called mBase, which is of type ContextImpl. Notice that there are two abstract methods in the Context that appear to be related to resources, but are actually used by the Context to get resources. The actual implementation of these two abstract methods is in ContextImpl, which means that the resource problem can be solved by implementing these two methods.



The specific implementation method is given below. The first step is to load resources in APK, as shown below.



From the loadResources() implementation, we can see that the way to loadResources is by reflection. By calling the addAssetPath method in AssetManager, we can load a resource from apk into the Resources object. Because addAssetPath is a hidden API we can’t call it directly, so we can only do it through reflection. Apk can be a ZIP file or a resource directory. Apk is a ZIP file, so the apk path is directly passed to it and the resource is loaded into AssetManager. The problem is solved by creating a new Resources object through the AssetManager that can access the Resources in the plug-in APK.



Then implement getAssets() and getResources() in the proxy Activity, as shown below. See the implementation details of the DL open source plug-in framework for more details about what surrogate activities mean.



With these two steps, resources in the plug-in can be accessed through R.

2. Manage the Activity lifecycle

There are a variety of ways to manage the Activity lifecycle, and here are just two: reflection and interface. The method of reflection is easy to understand. First, we use Java reflection to get various Activity lifecycle methods, such as onCreate, onStart, onResume, etc. Then we call the corresponding plug-in Activity lifecycle methods in the proxy Activity, as shown below.



Using reflection to manage the life cycle of a plug-in Activity has its drawbacks, both because reflection code can be complex to write and because there is a performance overhead associated with excessive use of reflection. The interface approach addresses the weaknesses of reflection by extracting the Activity lifecycle method as an interface (such as DLPlugin) and then calling the plug-in Activity lifecycle method by proxy. This completes plug-in Activity lifecycle management and does not use reflection, which solves the performance problem. The declaration of the interface is also relatively simple. Here is the declaration of DLPlugin:



Simply call the plug-in Activity lifecycle method in the proxy Activity as follows, which completes the plug-in Activity lifecycle management.



It should be easy to understand the interface approach to managing the plug-in Activity lifecycle from the above code, where mRemoteActivity is the implementation of DLPlugin.

3. Plug-in ClassLoader management

In order to better support multiple plug-ins, it is necessary to reasonably manage the DexClassLoader of each plug-in, so that the same plug-in can use the same ClassLoader to load classes, so as to avoid type conversion errors caused by multiple classLoaders loading the same class. In the following code, you can ensure that the classes in different plug-ins do not interfere with each other by storing the classloaders for different plug-ins in a HashMap.



In fact the technical details of plug-in is very much, it is not a chapter content can describe clearly, additional plug-in into as a core technology, requires developers to have a deeper knowledge of the development of language can understand very well, so the content of this section is to give readers more have a perceptual knowledge of pluggable development, the details need the reader to study, You can also learn in depth through the DL plug-in framework.

Baichuan.taobao.com is the wireless open platform of Alibaba Group. Through the opening of “technology, business and big data”, baichuan.taobao.com provides high cohesion, open, industry-leading technology product matrix, mature business components and perfect service system in mobile scenes. Help mobile developers quickly build apps, accelerate the process of APP commercialization, and empower mobile developers and mobile entrepreneurs in an all-round way.

        About Alibaichuan