2014-12-07 47 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); 
}