componentization

Componentization is a platitude problem, actually is not new

  • Componentization and modularization are the same thing
  • Different people have different definitions of it
  • Definition:
    • Breaking down multiple modules for development is componentization
    • The previous Android development is not using Gradle now, using Ant, do module split is more troublesome
    • Now with Gradle, it’s very easy to unpack modules. But modular development was around long before Gradle came along

Give me my personal opinion

Here’s front-end development

  • Componentization of the front end and componentization of mobile development are similar but different
  • For example, a small UI component on the front, like a custom UI in Android development, can be called a component, but obviously in mobile development we don’t think of it as a component,
    • The collection of components in the front end is called a component library or UI component library, such as AntD, elementUI, etc
    • Android also has UI component libraries such as QMUI
  • In Android development, we rely on a lot of modules, components and modules that I think can be unified but can also be broken down
    • First of all, there is no difference in the way they are implemented. They are all implemented through module dependencies
    • If you have to, you can do it in different dimensions
  • Taking a cue from the front end, in front end development, the Component folder is mostly used to hold UI components, so I’ll define it this way
    • I think the component is more UI, and there are mostly UI components inside
      • The reason for putting the UI together is to make it easy for developers to find and use it
      • In this way, the accumulated UI components do not have to fight independently, but also can be unified to manage
    • The module is more oriented to function. The module has a complete piece of business process. The purpose is to reduce the coupling with the main project and facilitate the call, that is, decoupling.
      • It may contain networks, images, asynchronous processing, and so on
      • Even in many cases, modules need to be packaged independently
  • I think modules are more granular than components, and their internal class files/resource files have richer responsibilities and categories (after all, components may only focus on the UI), and I think it’s a stretch to say how much code a component library has

pluggable

Some function modules of App are not packed into APK files in the traditional way, but are twice encapsulated into APK in another form, or downloaded on the network at the right time, and loaded dynamically when needed, which is called plug-in. These function modules apKS that are individually packaged twice are called “plug-ins”, and the apKS that are initially installed are called “hosts”. Plug-in is the further advance of componentization.

Plug-in basis: Reflection

Basic use of reflection

  • First, create a new utils folder in our plugin directory and write an utils class inside it
    class Utils { private static final String TAG = "Utils"; void shout(){ Log.d(TAG, "shout!!! "); }}Copy the code
  • Then create a new Activity using it under the Plugin package -> PluginActivity
  • Since Utils access is default, it cannot be instantiated outside the package, so reflection is used
    • For instantiation of a class, the instance needs to be instantiated through constructors that extend accesssetAccessible(true)
    • For method calls, you need to get the method and extend accesssetAccessible(true)
  • Here is the complete code
    public class PluginActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_plugin); / / use reflection try {/ / 1. Get the Class utilsClass = Class. Class.forname (" com. DSH. Txlessons. Plugin. Utils. Utils "); / / 2. Get the first Constructor Constructor utilsConstructor = utilsClass. GetDeclaredConstructors () [0]; / / 3. Expand accessibility default default package permissions - > public utilsConstructor. SetAccessible (true); / / 4. Create a class instance (via the constructor instance) Object utils = utilsConstructor. NewInstance (); / / 5. Access Method shoutMethod = utilsClass. GetDeclaredMethod (" its "); / / 6. Access shoutMethod expanding method. SetAccessible (true); Shoutmethod.invoke (utils); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }}}Copy the code

Purpose of reflection

Java provides visibility keywords such as public private to restrict visibility between code, so why provide reflection?

  • Visibility features are supported not so that code can’t be used by bad guys, but for simplicity of program development. For Security, visibility support provides Safety, not Security. That is, the visibility support makes the program less prone to bugs, not less prone to hacking.

  • Reflection support allows developers to override visibility limits to call their own apis in visibility exception scenarios. This is based on the assumption that developers are “knowledgeable and careful when using reflection”.

  • Therefore, visibility is not supported to defend against intruders, so reflection is not unreasonable.

Principle of plug-in: dynamic loading

A custom ClassLoader is used to load new dex files so that classes that the programmer does not have can be used. This is the principle of plug-in.

  1. So let’s change the code
  • First create a new module: “Phone & Tablet Module” -> pluginApp
  • Transplant the utils folder from app project to PluginApp project
  • Modify the PluginActivity reflection code under APP, modify the package name, other unchanged
    / / 1. Get the Class utilsClass = Class. Class.forname (" com. DSH. Pluginapp. Utils. Utils ");Copy the code
  • Run app, GG, error as follows

Caused by: java.lang.ClassNotFoundException: Didn’t find class “com.dsh.pluginapp.utils.Utils” on path: DexPathList [[zip file “/ data/app/com. DSH. Mydemos – q8nYNkNjIWB0F6mdYX_Gvg = = / base. The apk”] – this error indicates that found no Utils to this class

2. The important point is that the above code reported an error because pluginApp is also an App project, which itself is also an APK after packaging, so the class loader of our App project cannot be loaded into the class (.dex) file in pluginApp. So the next problem to solve is how can apps get access to Utils plug-in solutions in pluginApp which is rude, which is to throw the plugin project files to the host project

So let’s try it out

  • In order to access the files in the plug-in project, first copy the APK after the plug-in project is run into the assets/ APk directory of the APP project
  • Now that we have the APK, we can load the classes in the APK through the DexClassLoader
  • Here is the code, with detailed comments
onCreate{ ... / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- pluggable use -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / 1. File apk = new File(getCacheDir()+"plugin.apk"); try (Source source = Okio.source(getAssets().open("apk/pluginapp-debug.apk")); BufferedSink sink = Okio.buffer(Okio.sink(apk));) { sink.writeAll(source); } catch (IOException e) { e.printStackTrace(); DexClassLoader classLoader = new DexClassLoader(apk.getPath(),getCacheDir().getPath(),null,null); / / 3. The reflection calls / / 1. Get the Class utilsClass. = this loadClass (" com. DSH. Pluginapp. Utils. Utils "); / / 2. Get the first Constructor Constructor utilsConstructor = utilsClass. GetDeclaredConstructors () [0]; / / 3. Expand accessibility default default package permissions - > public utilsConstructor. SetAccessible (true); / / 4. Create a class instance (via the constructor instance) Object utils = utilsConstructor. NewInstance (); / / 5. Access Method shoutMethod = utilsClass. GetDeclaredMethod (" its "); / / 6. Access shoutMethod expanding method. SetAccessible (true); Shoutmethod.invoke (utils); . }Copy the code
  • Run it and print the correct logShout at pluginApp

3. Now that normal classes can load, can activities load?

Look at some other blogs that can be achieved

  • Plug-in – pile-type Activity jump
  • Principle of Android plug-in (A) Activity plug-in
  • Android plug-in exploration (a) placeholder type (pile type) plug-in detailed explanation
  • Android plug-in exploration (2) Hook plug-in detailed explanation
  • Android plug-in exploration (3) LoadedApk plug-in

Flexible configuration of plug-ins

If we wanted the plug-in project to be both library and application, we could do this

  • Add a variable to your Project in Project/build.gradle
    Ext {fullBuild = false}Copy the code
  • You can then determine the type of package to be packed using variables in the plugin project pluginapp//build.gradle
    if (fullBuild){
        apply plugin: 'com.android.library'
    }else {
        apply plugin: 'com.android.application'
    }
    Copy the code

What’s the use of plugins?

  • Early: Solve dex 65535 problem. Google later came up with multidex to do just that
  • Lazy loading reduces software startup speed: it’s possible, but not necessarily fast
  • One: reduce the installation package size: yes
  • One said: project structure separation, dependence on complete isolation, convenient development and testing of multiple teams, to solve the problem of too high coupling of components: the use of modularization is enough, and module decoupling is not enough, plug-in can not solve this problem
  • Dynamic deployment: Yes
    • Android App Bundles: Are “modular releases”. Dynamic deployment may be supported in the future, but it will definitely need to be combined with app stores (i.e., Play Store, or more stores in the future)
  • Bug hotfix: Yes

About DEX:

  • Class: a Java compiled file. Each class corresponds to a class file
  • Dex :Dalvik EXecutable packages classes together, and a dex can contain multiple class files
  • Odex :Optimized DEX System optimization. For example, the call instruction of a method converts the virtual call to a specific Index, so that it is no longer searched during execution
  • Oat :Optimized Android File Type. The AOT strategy is used to pre-compile (interpret) the instructions for dex, so that the re-run stage does not have to go through the re-interpretation process, and the program can run faster
    • AOT: Ahead-of-time compilation