2012-08-02 45 views
5

首先我已經看過Load Java-Byte-Code at Runtime,這對於我到目前爲止被卡住的同一個位置是有幫助的。如何從android中的字節數組加載類?

我想從字節數組中加載一個類,以避免在磁盤上存儲文件。在這個例子中,爲了測試目的,我只是簡單地將.class文件讀入字節數組中,顯然這個文件仍然存儲在磁盤上,但它只是查看代碼是否可以工作。

我把這個字節數組,然後使用一個自定義ClassLoader與loadClass方法來加載一個類,但它不起作用。

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

下面是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; 
} 

而且我收到的錯誤是這樣的:

java.lang.UnsupportedOperationException:在無法加載此類型的類文件 的java.lang.VMClassLoader.defineClass(Native Method)

我提供了.class文件,.dex文件,.apk,.jar等等......我不知道wha t「類文件」它從我和它的文檔是不存在的。任何幫助都會很好,我一直試圖讓這項工作連續四天。

+0

http://stackoverflow.com/a/3024261/61855 – theomega 2012-08-04 08:12:35

+0

我仍然得到「UnsupportedOperationException異常」的相同的錯誤消息,即使使用DEX文件/ jar文件。你的例子最終會做什麼? – HumanCentipedeLinkedList 2012-08-06 17:29:01

+0

你是誰?我?如果你參考我的問題,你鏈接:我沒有使用Android的這個項目,所以沒有問題。 – theomega 2012-08-06 18:59:00

回答

1

確保您.dex文件是一個真正的DX-產生的Dalvik可執行文件,而不是Java .class文件的化身。如果使用.dex擴展名,則該文件必須是.dex文件;否則使用.jar擴展名作爲包含classes.dex條目的ZIP文件。

不是所有版本的Dalvik都可以從內存中加載類。您可以通過從文件系統加載類來解決此問題。有一個在DexMaker'sgenerateAndLoad方法的例子:

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不會運行JVM字節碼,而是運行Dalvik字節碼。所以,你的操作應該包括此行之前defineClass()

context.setOptimizationLevel(-1); 
+0

你可以進一步瞭解一下該怎麼做/如何使用它?我從快速谷歌搜索中看到的唯一例子是使用我不使用的Rhino。爲什麼不會加載.dex文件而不是.class? – HumanCentipedeLinkedList 2012-08-02 21:36:40

+0

我看了一些更多,並注意到[這](回答SO)(http://stackoverflow.com/questions/3022454/how-to-load-a-java-class-dynamically-on-android-dalvik)。我敢打賭它會幫助你。您將不得不將其存儲爲.dex – tolgap 2012-08-03 18:23:43

+0

我仍然收到.dex文件的「UnsupportedOperationException:無法加載此類文件」錯誤。我嘗試過.class,.dex,.apk和.jar,但都沒有成功。我究竟做錯了什麼? – HumanCentipedeLinkedList 2012-08-03 20:07:18

2

我有,你有同樣的問題。

我得到錯誤的原因「無法加載這種類型的文件」很簡單。

在平臺源中,與「defineClass」方法相關的「/dalvik/vm/native/java_lang_VMClassLoader.cpp」總是返回異常,如下所示。 (版本:ICS)

最後,我得出結論:我無法加載字節數組格式的.dex。

有沒有人可以使用字節數組加載.dex? (不使用文件)

/* 
* 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

看看這段代碼,看起來defineClass總是拋出不支持的操作異常,不管輸入什麼,這與您所說的一致。如果這就是爲什麼甚至允許它進入API? – HumanCentipedeLinkedList 2012-08-14 17:08:54

相關問題