2014-12-07 49 views
10

到Android 5.0之前,我能夠加載動態使用DexClassLoader並調用loadClass()方法DEX文件,但最新的Android版本,我得到一個ClassNotFoundException負載DEX文件動態在Android 5.0

下面是我在做什麼:

  1. 生成DEX文件。

    ../android-sdk/android-sdk-linux_86/build-tools/21.1.1/dx --dex --output=bin/output.dex bin/output.jar 
    
  2. 創建一個DexClassLoader。

    DexClassLoader cl = new DexClassLoader(
    dexFile.getAbsolutePath(), 
    odexFile.getAbsolutePath(), 
    null, 
    mContext.getClassLoader()); 
    
  3. 呼叫cl.loadClass("myMethod");

我知道,ART使用dex2oat生成是由ART加載ELF文件,但在步驟2中,我產生ODEX文件,所以我也不是什麼ART需要在運行時加載DEX文件,任何人都可以幫助我嗎?

+0

爲什麼你需要在運行時加載一個文件DEX? 5.0本機支持多個dex文件。 – ianhanniballake 2014-12-07 23:55:48

+1

DEX文件包含敏感信息,並且在資產目錄中進行了加密。當我需要使用它時,它會被解密,然後在運行時加載。 – garibay 2014-12-08 15:24:49

+1

@garibay你能解決這個問題嗎?我遇到同樣的問題,這隻適用於Dalvik。 – cdroid 2015-06-07 15:34:17

回答

3

更新

這適用於的Dalvik和ART:new DexClassLoader(jarredDex.getAbsolutePath(), context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), null, context.getClassLoader());其中jarredDex是一個jar文件與classes.dex。罐子可以通過運行dx --dex --output=filename.jar your/classes/dir獲得。


原來的答覆

我從this article了一個代碼示例。但ART使用PathClassLoader而不是Dalvik的DexClassLoader。此代碼是在模擬器測試與Android 6和小蜜與Android 5.1和正常工作:

// Before the secondary dex file can be processed by the DexClassLoader, 
// it has to be first copied from asset resource to a storage location. 
File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE), SECONDARY_DEX_NAME); 
try (BufferedInputStream bis = new BufferedInputStream(getAssets().open(SECONDARY_DEX_NAME)); 
    OutputStream dexWriter = new BufferedOutputStream(new FileOutputStream(dexInternalStoragePath))) { 

    byte[] buf = new byte[BUF_SIZE]; 
    int len; 
    while((len = bis.read(buf, 0, BUF_SIZE)) > 0) { 
     dexWriter.write(buf, 0, len); 
    } 
} catch (IOException e) { 
    throw new RuntimeException(e); 
} 

try { 
    PathClassLoader loader = new PathClassLoader(dexInternalStoragePath.getAbsolutePath(), getClassLoader()); 
    Class<?> toasterClass = loader.loadClass("my.package.ToasterImpl"); 
    Toaster toaster = (Toaster) toasterClass.newInstance(); 
    toaster.show(this, "Success!"); 
} catch (ReflectiveOperationException e) { 
    throw new RuntimeException(e); 
}