Recent learning plug-in, see all kinds of brain pain, now write some notes with your own hands for future review, there are incorrect understanding, please point out
Loading classes is accomplished through the class loader ClassLoader, which has several classloaders, as follows
pathClassLoader can be understood as loading activities written by itself, such as TestActivity extends Activity, which is then printed out directly in onCreat in TestActivity as getClassLoader
pathClassLoader
DexClassLoader can be understood as loading system classes, such as those under android.app.activity
First hand-drawn process of loading a class, a little confused, let's take a look, draw according to your own understanding
The main thing here is the parental delegation mechanism. The benefit is security, which prevents duplicate loading. When loading a class first, call the loadClass method. In the loadClass method, call the findloadedclass() method first. Find it from the loaded class, return it directly, and call the loadClass method of parent if it is not found. Parent is not a parent class here, it means the parent class. In the upper class, the findloadedclass() method is called first.The findloadedclass () is still findloadedclass (), and through recursion, always finds the top BootClassLoader, which loads its findclass without findloadedclass, passes through the object pathList.findclass of DexPathList in the findclass of BaseDexClassLoader, and then enters the DexPathList, and findclass method passes through the object dexElements of Element[], and loops for fiNdclass, one dex file for each element you get
Attach the code to load the plug-in below
public class LoadPluginUtils { private final static String apkPath = "/sdcard/test-debug.apk"; public static void start(Context context){ try { Class<?> dexpathClass = Class.forName("dalvik.system.DexPathList"); Field dexElements = dexpathClass.getDeclaredField("dexElements"); dexElements.setAccessible(true); Class<?> basedexClass = Class.forName("dalvik.system.BaseDexClassLoader"); Field pathList = basedexClass.getDeclaredField("pathList"); pathList.setAccessible(true); /** * Get the element array in the plug-in * The first parameter is the path, the path where the plug-in is placed * The second parameter is the upper-level classLoader, where context.getClassLoader() is the BootClassloader */ PathClassLoader pathClassLoader = new PathClassLoader(apkPath, context.getClassLoader()); //Gets the properties of the pathList in the pathClassLoader object Object pluginPathList = pathList.get(pathClassLoader); //Gets the properties of dexElements in the pluginPathList object Object[] pluginElement = (Object[]) dexElements.get(pluginPathList); //Get the element array in the host PathClassLoader classLoader = (PathClassLoader) context.getClassLoader(); Object hostPathList = pathList.get(classLoader); Object[] hostElement = (Object[]) dexElements.get(hostPathList); //Then combine the two element s into one Object[] arr = (Object[]) Array.newInstance(hostElement.getClass().getComponentType(), hostElement.length + pluginElement.length); System.arraycopy(hostElement,0,arr,0,hostElement.length); System.arraycopy(pluginElement,0,arr,hostElement.length,pluginElement.length); //The merged array is then assigned to the host dexElements property dexElements.set(hostPathList,arr); } catch (Exception e) { e.printStackTrace(); } } }
Advanced items are loaded in the application.
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); LoadPluginUtils.start(this); } }
Then at the place where it was called
Class<?> aClass = Class.forName("com.example.test.Test"); Method print = aClass.getMethod("print"); print.invoke(null);
Remember to put the plugin in sdcard