Android dynamic loading Jar notes

foreword

Although the company's projects used dynamic loading technology, I didn't pay much attention to it. Today, I suddenly saw that dynamic loading is used in other people's apps, and I plan to learn about it.

Overview

Android uses the Dalvik virtual machine to load executable programs, so class-based jars cannot be loaded directly, but the class needs to be converted into dex bytecode to execute the code. The optimized bytecode file can be stored in a .jar, as long as the .dex is stored inside it .

Experimental procedure

Android Studio 为 IDE

1. Create a dynamic loading module
1.1 Create a new module in the project that needs to be dynamically loaded, and add a test class, as shown in the figure below,
write picture description here
where base-lib represents the dynamically loaded module, DynamicTest represents the class to be dynamically loaded, and the IDynamic class is used as the parent class of DynamicTest interface.
1.1.1. Create IDynamic interface

package com.lgf.plugin;

/**
 * 打包时不能打包此类
 */

public interface IDynamic {
    String show();
}

1.1.2 Create a DynamicTest class to implement the IDynamic interface

package com.lgf.base;

import com.lgf.plugin.IDynamic;

public class DynamicTest implements IDynamic {
    @Override
    public String show() {
        return "DynamicTest";
    }
}

1.2 Package the jar
Add the packaged task to the module's build.gradle

apply plugin: 'com.android.library'

android {
   ...省略一百字
}

dependencies {
     ...省略一百字
}

task buildJar(dependsOn: ['assembleRelease'], type: Jar) {
    archiveName = "origin.jar" // 打包普通jar的名字
    from('build/intermediates/classes/release/com/lgf/base/')
    into('com/lgf/base/')
    exclude 'com/lgf/plugin/IDynamic.class' // 去除IDynamic类
}

// 执行此方法生成dex的jar
task exportPluginJar(dependsOn: ['buildJar'], type: Exec) {
    def outJar = buildJar.archivePath.getAbsolutePath()
    commandLine "dx.bat", "--dex", "--output=\"build/libs/plugin.jar\"", "${outJar}"
}

1.3 Execute the following command in the command line window to generate plugin.jar in the build/libs directory of the module

gradlew exportPluginJar

Note: dx needs to be added to the system environment variables (to convert ordinary jars into jars containing dex, you can use the dx tool that comes with the Android SDK, and dx can be added to the system environment variables for easy use (note the big Some SDK dx files are in the platform-tools folder, and some are in the build-tools folder).

1.4 If you do not need steps 1.2 and 1.3, you can also manually type jar: go to the directory of the jar to be converted (it is assumed to be origin.jar here), and execute

dx --dex --output=plugin.jar origin.jar

You will find that a plugin.jar file is generated in this directory, which is the file that the android project can load.
1.5. Put the generated jar into the SD card of the mobile phone,
enter the build/libs directory of the module, and execute the following command

adb push plugin.jar  /sdcard

2. The main module uses dynamic loading
2.1 Copy the IDynamic class in the dynamic loading module to the main module, and the package name should be set to the same, as shown in Figure
write picture description here
2.2 below to achieve dynamic loading

package com.lgf.dynamicload.demo;

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import com.lgf.plugin.IDynamic;

import java.io.File;

import dalvik.system.DexClassLoader;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    // layout相应的View中使用onClick属性
    public void showMessage(View view) {
        // 此路径为插件存放路径
        File dexPathFile = new File(Environment.getExternalStorageDirectory() + File.separator + "plugin.jar");
        String dexPath = dexPathFile.getAbsolutePath();
        String dexDecompressPath = getDir("dex", MODE_PRIVATE).getAbsolutePath(); // dex解压后的路径
//        String dexDecompressPath = Environment.getExternalStorageDirectory().getAbsolutePath(); // 不能放在SD卡下,否则会报错
        /**
         * DexClassLoader参数说明
         * 参数1 dexPath:待加载的dex文件路径,如果是外存路径,一定要加上读外存文件的权限(<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> )
         * 参数2 optimizedDirectory:解压后的dex存放位置,此位置一定要是可读写且仅该应用可读写(安全性考虑),所以只能放在data/data下。本文getDir("dex", MODE_PRIVATE)会在/data/data/**package/下创建一个名叫”app_dex1“的文件夹,其内存放的文件是自动生成output.dex;如果不满足条件,Android会报错误
         * 参数3 libraryPath:指向包含本地库(so)的文件夹路径,可以设为null
         * 参数4 parent:父级类加载器,一般可以通过Context.getClassLoader获取到,也可以通过ClassLoader.getSystemClassLoader()获取到。
         */
        DexClassLoader dexClassLoader = new DexClassLoader(dexPath, dexDecompressPath, null, getClassLoader());
        Class libClazz = null;
        try {
            libClazz = dexClassLoader.loadClass("com.lgf.base.DynamicTest");
            IDynamic lib = (IDynamic) libClazz.newInstance();
            Toast.makeText(this, lib.show(), Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.3 Add permission
Since you want to read the files of the sd card, you need to add read permission

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Demo

refer to

Android dynamic loading
Android dynamic loading dex technology

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325758497&siteId=291194637