天天看點

Android 動态加載DEX

1). 建立項目并建立Dynamic接口

/**
 * 接口
 * Created by mazaiting on 2018/6/26.
 */

public interface Dynamic {
  String say();
}
           

2). 建立接口的實作類DynamicImpl

/**
 * 動态實作類
 * Created by mazaiting on 2018/6/26.
 */

public class DynamicImpl implements Dynamic {
  @Override
  public String say() {
    return "mazaiting";
  }
}
           

3). 編譯

Build -> Make Project, 生成的檔案位于

Android 動态加載DEX

圖1.png

4). Gradle任務建立

在app/build.gradle檔案中追加

// 删除dynamic.jar包任務
task clearJar(type: Delete) {
    delete('libs/dynamic.jar')
}

// 打包任務
task makeJar(type: org.gradle.api.tasks.bundling.Jar) {
    // 指定生成jar名稱
    baseName 'dynamic'
    // 打封包件的位置
    from('build\\intermediates\\classes\\debug\\com\\mazaiting\\dynamicjar\\')
    // 打包到jar後的目錄結構
    into('com/mazaiting/dynamicjar/')
    // 去掉不需要打包的目錄和檔案
    exclude('text/','Dynamic.class','R.class','BuildConfig.class')
    // 去掉R$開頭的檔案
    exclude { it.name.startsWith('R$') }
}

makeJar.dependsOn(clearJar, build)
           

5). 在Terminal控制台運作

# 檢視所有任務
gradlew tasks --all
# 執行任務
gradlew makeJar
           

6). 生成jar

Android 動态加載DEX

圖2.png

7). dex打包

将打包好的jar檔案拷貝到android的安裝目錄中的

\sdk\build-tools\26.0.1\

目錄下,使用

dx --dex --output=dynamic_temp.jar dynamic.jar

進行壓縮

這條指令首先将dynamic.jar編譯成dynamic.dex檔案,然後再将dynamic.dex檔案壓縮成dynamic_temp.jar,當然也可以壓縮成.zip格式或者直接編譯成.apk檔案都可以。

8). 将生成的dynamic_dex.jar檔案導入Android工程的assets檔案夾下,并删除Dynamic接口的實作包

Android 動态加載DEX

圖3.png

9). 使用

public class MainActivity extends AppCompatActivity {
  /**緩存檔案夾*/
  private File mCacheDir;
  /**目标檔案*/
  private String mInternalPath;
  
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    copyFile();
    setContentView(R.layout.activity_main);
  }
  
  /**
   * 拷貝檔案
   */
  private void copyFile() {
    // 擷取緩存路徑
    mCacheDir = FileUtil.getCacheDir(getApplicationContext());
    // 擷取dex檔案存儲路徑
    mInternalPath = mCacheDir.getAbsolutePath() + File.separator + "dynamic.jar";
    File file = new File(mInternalPath);
    // 判斷檔案是否存在
    if (!file.exists()) {
      try {
        // 建立新檔案
        file.createNewFile();
        // 拷貝檔案
        FileUtil.copyFiles(this, "dynamic_dex.jar", file);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  
  /**
   * 動态加載按鈕,布局檔案隻有一個按鈕
   */
  public void loadDex(View view) {
    loadDex();
  }
  
  /**
   * 動态加載
   */
  private void loadDex() {
    // 建立DexClassLoader
    // 第一個參數:dex壓縮檔案的路徑
    // 第二個參數:dex解壓縮後的檔案路徑
    // 第三個參數:C/C++依賴的本地庫檔案
    // 第四個參數:上一級的類加載器
    DexClassLoader dexClassLoader = new DexClassLoader(
            mInternalPath, mCacheDir.getAbsolutePath(), null, getClassLoader());
    try {
      // 加載的類名為jar檔案中的完整類名
      Class clazz = dexClassLoader.loadClass("com.mazaiting.dynamicjar.impl.DynamicImpl");
      Dynamic dynamic = (Dynamic) clazz.newInstance();
      if (null != dynamic) {
        Toast.makeText(this, dynamic.say(), Toast.LENGTH_SHORT).show();
      }
    } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
      e.printStackTrace();
    }
  }
}
           

10). 運作項目

Android 動态加載DEX

圖4.png

代碼下載下傳