Analysis of Android dynamic Dex Loading Mechanism

Source: Internet
Author: User

Analysis of Android dynamic Dex Loading Mechanism
1. What is a class loader?

Is the class loader Java? A very important concept in. The class loader is responsible for loading the byte code of the Java class to the Java Virtual Machine.
The Java virtual machine uses the Java class as follows: the Java source code (. java file) is converted to the Java byte code (. class file) after being compiled by the Java compiler ). The Class Loader reads Java byte code and converts it to an instance of the java. lang. Class. Each such instance is used to represent a Java class. You can use the newInstance () method of this instance to create an object of this class. The actual situation may be more complex. For example, Java byte code may be dynamically generated by tools or downloaded over the network.
 

2. Dalvik Virtual Machine class loading mechanism the Dalvik virtual machine is like other Java virtual machines. When running a program, you must first load the corresponding class into the memory. In Java standard virtual machines, class loading can be read from class files or binary streams in other forms. Therefore, we often use this, when the program is running, manually load the Class to achieve the purpose of dynamic code loading and execution. However, Dalvik virtual machines are not standard Java virtual machines after all. Therefore, they share the same content in the Class loading mechanism, there are also differences. Let's take a look at the following figure about the Android Classload mechanism.

Unlike JVM, Dalvik virtual machines cannot be directly loaded using ClassCload. dex and Android derive two classes from ClassLoader: DexClassLoader and PathClassLoader. The two classes are the key to loading dex files. The differences between the two are:

1. DexClassLoader: you can load jar/apk/dex and load uninstalled apk from the SD card;
2. PathClassLoader: to input the Path for storing the apk in the system, you can only load the installed apk file.

Preparations 1. Open the Android studio new project: The project directory is like this: how to use the Dynamically Loaded class, there are generally two ways, one is to use reflection call, I will not introduce this method much. Another way is to use interface programming to call the corresponding method, after all. dex files are maintained by ourselves, so we can abstract methods into public interfaces and copy these interfaces to the main project, you can use these interfaces to call the method of Dynamically Loaded instances. Next we create a new package named dynamic under the source package, and then create an interface dynamic under Dynamic. There is an interface method in it, which is called sayHello (). A String is returned, at that time, we can use Toast to pop up Dynamic. java:
package wangyang.zun.com.mydexdemo.dynamic;/** * Created by WangYang on 2016/3/11. */public interface Dynamic {    String sayHello();}
Next we create an impl package and implement the Dynamic interface, DynamicImpl. java:
package wangyang.zun.com.mydexdemo.dynamic.impl;import wangyang.zun.com.mydexdemo.dynamic.Dynamic;/** * Created by WangYang on 2016/3/11. */public class DynamicImpl implements Dynamic {    @Override    public String sayHello() {        return new StringBuilder(getClass().getName()).append(" is loaded by DexClassLoader").toString();    }}
It is easy to output a sentence, "DynamicImpl is loaded by DexClassLoader. "for a specific project directory, click Build> make project. The corresponding classes file is generated in the build \ intermediates \ classes \ debug directory. Now, we need to convert the DynamicImpl class into a Dalvik identifiable dex file, in two steps: 1. export DynamicImpl as a jar package; 2. dx. the jar tool converts the jar package to a dex file. At the time of completing the first step, I encountered some trouble. Because eclipse is based on ant and has a visualization tool, it can directly export the jar package of the specified file, but android studio does not work, what should I do? You can use gradle task to package and open the build. gradle file in the app directory. Remember that it is not the build. gradle file in the root directory, and add the following code:
// Delete dynamic. jar Package task clearJar (type: Delete) {delete 'libs/dynamic. jar'} // package the task makeJar (type: org. gradle. api. tasks. bundling. jar) {// specify the generated jar name baseName 'dynamic '// Where to package the class file from ('build/intermediates/classes/debug/wangyang/zun/com/mydexdemo/dynamic/ ') // The directory structure after the jar package is into ('wangyang/zun/com/mydexdemo/dynamic /') // remove the directories and files that do not need to be packaged ('test/', 'dynamic. class ', 'buildconfig. class ', 'R. class ') // remove the file exclude {it. name. startsWith ('R $ ') ;}} makeJar. dependsOn (clearJar, build)

Open the terminal window of AS: run the cd app to enter the app directory, execute gradle makeJar, and wait until Build Successfully appears. Then, the libs/dynamic will appear under the build directory. jar file. This file is the jar package we want to use. We can open it using jd-gui to see if it is only the DynamicImpl class. Step 2, Use dx provided by sdk. jar to export dynamic. jar is converted to the recognizable dex format of Dalvik. The new sdk has converted dx. jar is stored in the build-tools \ 23.0.2 \ lib directory. We can enter this directory under dos or under Android studio terminal, and then run the following command: Dx -- dex -- output = dynamic_dex.jar dynamic. jar Output is your output directory. By default, it is in the current root directory. After the execution is complete, we will generate the dex file that can be executed by the Davilk virtual machine in the current directory, because this command will package the dex file at the same time, the suffix is jar. We use jd-gui to open dynamic. jar and dynamic_dex.jar. As you can see, the packaged file is actually a classes. dex file. The work we have to do so far is ready, and the next step is to use this dex file in the demo. 2. Delete the newly created impl package and files in the package: because we want to use the IDynamic implementation class under dex, we need to delete the IDynamic under the current project. java files and impl packages to avoid running errors. At the same time, we need to put the generated dynamic_dex.jar file under the assets Directory and copy it to the app/data directory. The deleted project directory is as follows: the FileUtils class Copies files from the assets Directory to the app/data/cache directory. The source code is as follows:
Public class FileUtils {public static void copyFiles (Context context, String fileName, File desFile) {InputStream in = null; OutputStream out = null; try {in = context. getApplicationContext (). getAssets (). open (fileName); out = new FileOutputStream (desFile. getAbsolutePath (); byte [] bytes = new byte [1024]; int I; while (I = in. read (bytes ))! =-1) out. write (bytes, 0, I);} catch (IOException e) {e. printStackTrace () ;}finally {try {if (in! = Null) in. close (); if (out! = Null) out. close ();} catch (IOException e) {e. printStackTrace () ;}} public static boolean hasExternalStorage () {return Environment. getExternalStorageState (). equals (Environment. MEDIA_MOUNTED);}/*** get cache path ** @ param context * @ return cache File path */public static File getCacheDir (Context context) {File cache; if (hasExternalStorage () {cache = context. getExternalCacheDir ();} else {cache = Context. getCacheDir ();} if (! Cache. exists () cache. mkdirs (); return cache ;}}
Open MainActivity:
Public class MainActivity extends AppCompatActivity {private Dynamic dynamic; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); // Add a click event findViewById (R. id. tx ). setOnClickListener (new View. onClickListener () {@ Override public void onClick (View v) {loadDexClass () ;}}) ;}/ *** load the class in the dex file and call the sayHello Method */Private void loadDexClass () {File cacheFile = FileUtils. getCacheDir (getApplicationContext (); String internalPath = cacheFile. getAbsolutePath () + File. separator + "dynamic_dex.jar"; File desFile = new File (internalPath); try {if (! DesFile. exists () {desFile. createNewFile (); FileUtils. copyFiles (this, "dynamic_dex.jar", desFile) ;}} catch (IOException e) {e. printStackTrace ();} // load dex class DexClassLoader dexClassLoader = new DexClassLoader (internalPath, cacheFile. getAbsolutePath (), null, getClassLoader (); try {Class libClazz = dexClassLoader. loadClass ("wangyang.zun.com. mydexdemo. dynamic. impl. IDynamic "); dynamic = (D Ynamic) libClazz. newInstance (); if (dynamic! = Null) Toast. makeText (this, dynamic. sayHelloy (), Toast. LENGTH_LONG). show () ;}catch (Exception e) {e. printStackTrace ();}}}
The program runs as follows: Now, let's talk about the principle of the Android Dex dynamic loading mechanism. Next, I will analyze the basic principle of implementing hotfix through Dex.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.