2014-12-07 29 views
10

Prima di Android 5.0 ero in grado di caricare i file DEX dinamicamente utilizzando DexClassLoader e chiamando il metodo loadClass() ma con l'ultima versione di Android ottengo un ClassNotFoundException.Carica dinamicamente il file DEX su Android 5.0

Ecco quello che sto facendo:

  1. Genera file DEX.

    ../android-sdk/android-sdk-linux_86/build-tools/21.1.1/dx --dex --output=bin/output.dex bin/output.jar 
    
  2. Creare un DexClassLoader.

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

Sono consapevole del fatto che l'arte utilizza dex2oat per generare un file ELF che è il caricata da ART, ma nella fase 2 sto generando un ODEX file in modo che non sono ciò deve essere fatto in ART per caricare un file DEX in fase di esecuzione, qualcuno può aiutarmi?

+0

Perché avete bisogno di caricare un file DEX in fase di esecuzione? 5.0 supporta più file dex in modo nativo. – ianhanniballake

+1

Il file DEX contiene informazioni riservate ed è crittografato nella directory delle risorse. Quando ho bisogno di usarlo, è decodificato e quindi caricato in fase di runtime. – garibay

+1

@garibay sei riuscito a risolvere questo problema? Sto avendo lo stesso problema, questo funziona solo su Dalvik per me. – cdroid

risposta

3

Aggiornamento

Questo funziona sia su Dalvik e ARTE: new DexClassLoader(jarredDex.getAbsolutePath(), context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), null, context.getClassLoader()); dove jarredDex è un file jar con classes.dex. Jar può essere ottenuto eseguendo dx --dex --output=filename.jar your/classes/dir.


risposta originale

ho preso un esempio di codice da this article. Ma ART utilizza PathClassLoader invece di Dalvik DexClassLoader. Questo codice è testato su emulatore con Android 6 e Xiaomi con Android 5.1 e funziona bene:

// 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); 
}