2012-08-02 18 views
5

Po pierwsze widziałem Load Java-Byte-Code at Runtime i było to pomocne, jeśli chodzi o dotarcie do mnie w tym samym miejscu, w którym utknąłem.Jak załadować klasę z tablicy bajtów w systemie Android?

Próbuję załadować klasę z tablicy bajtów, aby uniknąć przechowywania pliku na dysku. Do celów testowania w tym przykładzie po prostu czytam w pliku .class do tablicy bajtowej, więc oczywiście plik jest nadal przechowywany na dysku, ale wystarczy sprawdzić, czy kod może działać.

Biorę tę tablicę bajtów, a następnie używam niestandardowej metody ClassLoader z metodą loadClass do ładowania klasy, ale to nie działa.

byte[] bytearray = null; 
    try{  
    RandomAccessFile f = new RandomAccessFile("/sdcard/ClassToGet.dex", "r"); 
    bytearray = new byte[(int) f.length()]; 
    f.read(bytearray); 

    MyClassLoader classloader = new MyClassLoader(); 
    classloader.setBuffer(bytearray); 
    classloader.loadClass("com.pack.ClassIWant"); 
    } 

Oto realizacja ClassLoader:

public class MyClassLoader extends DexClassLoader { 

private byte[] buffer; 

    @Override 
    public Class findClass(String className){ 
    byte[] b = getBuffer(); 
    return this.defineClass(className, b, 0, b.length); 
    } 

public void setBuffer(byte[] b){ 
    buffer = b; 
} 
public byte[] getBuffer(){ 
    return buffer; 
} 

a błąd otrzymuję to:

java.lang.UnsupportedOperationException: nie można załadować tego typu klasy w pliku java.lang.VMClassLoader.defineClass (Metoda natywna)

Dostarczyłem go z plikami .class, plikami .dex, .apk, .jar, etc ... Nie mam pojęcia t "typ pliku klasowego", który chce ode mnie, a dokumentacja na nim jest nieistniejąca. Każda pomoc byłaby świetna Próbowałem dostać tę pracę przez cztery dni.

+0

http://stackoverflow.com/a/3024261/61855 – theomega

+0

ja wciąż otrzymuję ten sam komunikat o błędzie „UnsupportedOperationException”, nawet przy użyciu Dex plików/pliki jar. Co zrobiłeś ze swojego przykładu? – HumanCentipedeLinkedList

+0

Do kogo napijesz się? Mnie? Jeśli odnosisz się do mojego pytania, które łączysz: nie korzystałem z Androida w tym projekcie, więc nie ma w nim żadnych problemów. – theomega

Odpowiedz

1

upewnić się, że plik .dex jest prawdziwy DX produkowane Dalvik wykonywalny, a nie .class plik Java w przebraniu. Jeśli używasz rozszerzenia .dex, plik musi być plikiem .dex; w przeciwnym razie użyj rozszerzenia .jar dla pliku ZIP zawierającego wpis classes.dex.

Nie wszystkie wersje Dalvik mogą ładować klasy z pamięci. Możesz obejść ten problem, ładując klasę z systemu plików. Jest to przykład w DexMaker'sgenerateAndLoad metody:

byte[] dex = ... 

    /* 
    * This implementation currently dumps the dex to the filesystem. It 
    * jars the emitted .dex for the benefit of Gingerbread and earlier 
    * devices, which can't load .dex files directly. 
    * 
    * TODO: load the dex from memory where supported. 
    */ 
    File result = File.createTempFile("Generated", ".jar", dexCache); 
    result.deleteOnExit(); 
    JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result)); 
    jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME)); 
    jarOut.write(dex); 
    jarOut.closeEntry(); 
    jarOut.close(); 
    try { 
     return (ClassLoader) Class.forName("dalvik.system.DexClassLoader") 
       .getConstructor(String.class, String.class, String.class, ClassLoader.class) 
       .newInstance(result.getPath(), dexCache.getAbsolutePath(), null, parent); 
    } catch (ClassNotFoundException e) { 
     throw new UnsupportedOperationException("load() requires a Dalvik VM", e); 
    } catch (InvocationTargetException e) { 
     throw new RuntimeException(e.getCause()); 
    } catch (InstantiationException e) { 
     throw new AssertionError(); 
    } catch (NoSuchMethodException e) { 
     throw new AssertionError(); 
    } catch (IllegalAccessException e) { 
     throw new AssertionError(); 
    } 
0

Android nie uruchamia kodu JVM, ale kod bajtowy Dalkina. Więc operacja powinna zawierać tę linię przed defineClass()

context.setOptimizationLevel(-1); 
+0

Czy mógłbyś podać więcej szczegółów na temat tego, co to robi/jak z niego korzystać? Jedyne przykłady, które widzę z szybkiego wyszukiwania w Google, to używanie Rhino, którego nie używam. Dlaczego zamiast pliku .class nie wystarczy załadowanie pliku .dex? – HumanCentipedeLinkedList

+0

Zajrzałem jeszcze raz i zauważyłem odpowiedź [this] (http://stackoverflow.com/questions/3022454/how-to-load-a-java-class-dynamically-on-android-dalvik) na SO. Założę się, że to ci pomoże. Będziesz musiał przechowywać go jako .dex – tolgap

+0

Wciąż otrzymuję ten sam błąd "UnsupportedOperationException: nie mogę załadować tego typu pliku klasy" również dla plików .dex. Próbowałem .class, .dex, .apk i .jar i żaden nie działa. Co ja robię źle? – HumanCentipedeLinkedList

2

Mam ten sam problem, który masz.

Powód, dla którego pojawia się błąd "nie można załadować tego typu pliku klasy" jest prosty.

W źródle platformy "/dalvik/vm/native/java_lang_VMClassLoader.cpp", która jest powiązana z metodą "defineClass" zawsze zwraca wyjątek w następujący sposób. (wersja: ICS)

Wreszcie doszedłem do wniosku, że nie mogę załadować .dex w formacie tablicy bajtowej.

Czy jest ktoś, kto może załadować .dex przy użyciu tablicy bajtów? (Nie przy użyciu plików)

/* 
* static Class defineClass(ClassLoader cl, String name, 
*  byte[] data, int offset, int len) 
*  throws ClassFormatError 
* 
* Convert an array of bytes to a Class object. 
*/ 
static void Dalvik_java_lang_VMClassLoader_defineClass(const u4* args, JValue* pResult) 
{ 
    Object* loader = (Object*) args[0]; 
    StringObject* nameObj = (StringObject*) args[1]; 
    const u1* data = (const u1*) args[2]; 
    int offset = args[3]; 
    int len = args[4]; 
    char* name = NULL; 

    name = dvmCreateCstrFromString(nameObj); 
    ALOGE("ERROR: defineClass(%p, %s, %p, %d, %d)", 
     loader, name, data, offset, len); 
    dvmThrowUnsupportedOperationException(
     "can't load this type of class file"); 

    free(name); 
    RETURN_VOID(); 
} 

/* 
* static Class defineClass(ClassLoader cl, byte[] data, int offset, 
*  int len) 
*  throws ClassFormatError 
* 
* Convert an array of bytes to a Class object. Deprecated version of 
* previous method, lacks name parameter. 
*/ 
static void Dalvik_java_lang_VMClassLoader_defineClass2(const u4* args, JValue* pResult) 
{ 
    Object* loader = (Object*) args[0]; 
    const u1* data = (const u1*) args[1]; 
    int offset = args[2]; 
    int len = args[3]; 

    ALOGE("ERROR: defineClass(%p, %p, %d, %d)", 
     loader, data, offset, len); 
    dvmThrowUnsupportedOperationException(
     "can't load this type of class file"); 

    RETURN_VOID(); 
} 
+0

Patrząc na ten kod, wydaje się, że defineClass ZAWSZE zgłasza nieobsługiwany wyjątek operacji, bez względu na to, jakie dane wejściowe są zgodne z tym, co powiedziałeś. Jeśli tak, to dlaczego nawet pozwolić na to w API? – HumanCentipedeLinkedList

Powiązane problemy