首先我已经看过Load Java-Byte-Code at Runtime,这对我到目前为止所处的同一地点有帮助。
我正在尝试从字节数组加载一个类,以避免在磁盘上存储文件。出于测试目的,在这个例子中,我只是将.class文件读入一个字节数组,所以显然文件仍然存储在磁盘上,但只是看看代码是否可以工作。
我接受这个字节数组然后使用带有loadClass方法的自定义ClassLoader来加载一个Class,但它不起作用。
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:无法加载此类类文件 at java.lang.VMClassLoader.defineClass(Native Method)
我已经提供了.class文件,.dex文件,.apk,.jar等...我不知道它想要什么类型的“类文件”,并且它上面的文档是不存在的。任何帮助都会很棒我一直试图让这项工作连续四天。
答案 0 :(得分: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();
}
答案 1 :(得分:1)
确保您的.dex
文件是真正的dx生成的Dalvik可执行文件,而不是伪装的Java .class
文件。如果您使用.dex
扩展名,则该文件必须是.dex
文件;否则对包含.jar
条目的ZIP文件使用classes.dex
扩展名。
并非所有版本的Dalvik都可以从内存中加载类。您可以通过从文件系统加载类来解决此问题。 DexMaker's generateAndLoad
方法中有一个示例:
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();
}
答案 2 :(得分:0)
Android不运行JVM字节码,而是运行Dalvik字节码。因此,您的操作应在defineClass()
context.setOptimizationLevel(-1);