ClassLoader

Android ClassLoader has some different dynamic loading mechanisms based on Android plug-in development

The Android plug-in,

After changing my job, the company’s project is quite large, and many places have used plug-in. Plug-in simply means to package some functions into special files such as APK and DEX, and then load the plug-in when the host APP needs to use this function. Plug-ins can not only achieve some functions of hot plug; And there is no need to install the APP, just download it when it is in use, so as to reduce the host APK volume; You can also update functionality by updating plug-ins. Plugins are a mature technology, and many large companies are developing their products using plugins. There are also a number of mature plug-in frameworks, such as DynamicAPK, RePlugin, Small, etc

The principle of plug-in

Android has PathClassLoader and DexClassLoader:

  • The PathClassLoader is used to load dex, APK, and class files under data/app. This directory corresponds to some applications we installed
  • DexClassLoader can be used to load external dex, APK, and class files

We can now load dex and APK files from other places and use the corresponding class files

We also need to get the resource file

AssetManager assets = new AssetManager(); // Add apk path to AssetManager if (asset.addAssetPath (resDir) == 0){return null; } // create a Resource object r = new Resources(assets, metrics, getConfiguration(), compInfo);Copy the code

Access to plug-in resources can be achieved by adding the path of the plug-in APK to the AssetManager.

Specific implementation, because AssetManager is not a public class, it needs to be created by reflection, and part of the Rom created Resource class has been modified, so it needs to consider the compatibility of different ROMs.

Another problem is that the plug-in’s activity is not registered. We register an empty activity in the host to load the activity in the plug-in app. This activity is called ProxyActivity. We also need to configure the ProxyActivity

class ProxyActivity : AppCompatActivity() {/** * name of the activity to jump to */ private var className = "" private var appInterface: appInterface? = null override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) /** * step1: Class = intent.getStringExtra("className") /** * step2: Classloader.loadclass (className) * class.forname (className) * because the plugin app is not installed! / var activityClass = classLoader.loadClass(className) var constructor = activityClass.getConstructor() var instance = constructor.newInstance() appInterface = instance as? AppInterface appInterface? .attach(this) var bundle = Bundle() appInterface? .onCreate(bundle) } override fun onStart() { super.onStart() appInterface? .onStart() } override fun onResume() { super.onResume() appInterface? .onResume() } override fun onDestroy() { super.onDestroy() appInterface? .onDestroy() } override fun getClassLoader(): This {/ / don't use this system, using dexClassLoader load return PluginManager. GetInstance () getDexClassLoader () as? ClassLoader ? : super.getClassLoader() } override fun getResources(): Resources {/ / no system Resources, implement a Resources return PluginManager. GetInstance (). GetResources ()? : super.getResources() } }Copy the code

Also, when using a context, you need to use the ProxyActivity context because the plug-in doesn’t have a context and needs to rely on the host context

Android hot update

Hot repair is also a popular technology. There are many hot repair frameworks, such as Ali AndFix (native solution, which does not need cold start), QZONE (Dex subcontract scheme), Meituan Robust (Instant Run hot plug principle) and wechat Tinker. The principles of these frameworks are different. Tinker implements hot repair through ClassLoader.

Qzone super patch, “super patch” in many cases means the patch file is very large, and loading such a large folder in memory to build an Element object and insert it into the front of the array takes time, no doubt impression of the application launch speed. Therefore, Tinker proposed another idea. Tinker’s idea is as follows: by comparing the repaired class.dex with the original class.dex, Tinker creates the differential package patch file patch.dex. Dex will be merged with the original class.dex to generate a new file fix_class.dex, and the contents of the original dexPathList will be replaced with the new fix_class.dex, which can be said to fundamentally eliminate the bug. If you are interested, you can check out DexDiff/DexPatch, which analyzes Tinker source code for Android