Я пытаюсь загрузить набор файлов JAR, которые собираются вместе для создания API.По какой-то причине я могу загружать только классы, не зависящие от определений в других JAR-файлах.Я начинаю подозревать, что загрузчики классов Android просто не обрабатывают реализацию интерфейса из одного файла JAR в другой.По этой причине я также распаковал классы в общий каталог, однако это тоже не работает.
Пожалуйста, смотрите следующий код.Извиняюсь за любые аномалии, но я попытался гарантировать, что он будет компилироваться прямо, если вставить в проект ADT под названием MyProj.
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import dalvik.system.PathClassLoader;
import android.content.Context;
// IPluginSource simply defines the method here at the top.
public class AndroidPluginSource implements IPluginSource
{
@Override
public void doSearching(ArrayList<ClassLoader> classLoaders, ArrayList<String> classNames)
{
String jarPaths = "";
// For each of the raw resources, JARs compiled into the 'res/raw' dir...
for (Field str : R.raw.class.getFields())
{
String resName = str.getName();
Logger.log(Level.FINE, "Resource: " + str);
try
{
// Copy the JAR file to the local FS.
InputStream is = MyProj.self.getResources().openRawResource(str.getInt(this));
OutputStream os = MyProj.self.openFileOutput(resName + ".jar", Context.MODE_PRIVATE);
copyData(is, os);
is.close();
os.close();
// Get JAR location.
String jarLoc = MyProj.self.getFilesDir() + File.separator + resName + ".jar";
// First attempt is just single classloaders, so we aren't suprised this won't work.
classLoaders.add(new PathClassLoader(jarLoc, MyProj.self.getClassLoader()));
//Logger.log(Level.FINE, " LOC: " + jarLoc);
// Keep running list of JAR paths, will that work?
if (jarPaths.length() > 0) jarPaths += File.pathSeparator;
jarPaths += jarLoc;
// We have to go through the JARs to get class names...
JarFile jar = new JarFile(jarLoc);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements())
{
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
if (entryName.endsWith(".class"))
{
classNames.add(toClassName(entryName));
Logger.log(Level.FINE, " ENT: " + entryName);
// ...while we're here lets get the class out as a file.
String classLoc = MyProj.self.getFilesDir() + File.separator + entryName;
Logger.log(Level.FINER, " CLS: " + classLoc);
File classFile = new File(classLoc);
classFile.delete();
classFile.getParentFile().mkdirs();
InputStream jis = jar.getInputStream(entry);
//OutputStream jos = MyProj.self.openFileOutput(classLoc, Context.MODE_PRIVATE);
OutputStream jos = new FileOutputStream(classFile);
copyData(jis, jos);
jos.close();
jis.close();
}
}
}
catch (Exception ex)
{
Logger.log(Level.SEVERE, "Failed plugin search", ex);
}
}
File f = MyProj.self.getFilesDir();
recursiveList(f, 0);
// So we have a class loader loading classes...
PathClassLoader cl = new PathClassLoader(VermilionAndroid.self.getFilesDir().getAbsolutePath(), ClassLoader.getSystemClassLoader());
classLoaders.add(cl);
// A JAR loader loading all the JARs...
PathClassLoader jl = new PathClassLoader(jarPaths, ClassLoader.getSystemClassLoader());
classLoaders.add(jl);
// And if edited as below we also have a DexLoader and URLClassLoader.
}
// This is just so we can check the classes were all unpacked together.
private void recursiveList(File f, int indent)
{
StringBuilder sb = new StringBuilder();
for (int x = 0; x < indent; x++) sb.append(" ");
sb.append(f.toString());
Logger.log(Level.INFO, sb.toString());
File[] subs = f.listFiles();
if (subs != null)
{
for (File g : subs) recursiveList(g, indent+4);
}
}
// Android helper copy file function.
private void copyData(InputStream is, OutputStream os)
{
try
{
int bytesRead = 1;
byte[] buffer = new byte[4096];
while (bytesRead > 0)
{
bytesRead = is.read(buffer);
if (bytesRead > 0) os.write(buffer, 0, bytesRead);
}
}
catch (Exception ex) {}
}
// Goes from a file name or JAR entry name to a full classname.
private static String toClassName(String fileName)
{
// The JAR entry always has the directories as "/".
String className = fileName.replace(".class", "").replace(File.separatorChar, '.').replace('/', '.');
return className;
}
}
Следующий код - то, откуда это вызывается.*
Спасибо за вашу помощь.
РЕДАКТИРОВАТЬ: Я также попытался добавить
URLClassLoader ul = null;
try
{
URL[] contents = new URL[jarURLs.size()];
ul = new URLClassLoader(jarURLs.toArray(contents), ClassLoader.getSystemClassLoader());
}
catch (Exception e) {}
classLoaders.add(ul);
..., что вызывает новое исключение - UnsupportedOperationException: не удается загрузить этот типфайла класса.
AND:
DexClassLoader dl = new DexClassLoader(jarPaths, "/tmp", null, getClass().getClassLoader());
classLoaders.add(dl);
Также не работает правильно, но спасибо за предложение Peter Knego
Я должен уточнитьчто в файлах JAR у меня есть:
JAR1:
public interface IThing
public class ThingA implements IThing
JAR2:
public class ThingB implements IThing