I have an android application which has to load dynamically class ,an undefined number of a jar class which implemented an interface.
In fact, I look at a directory
I found the solution to my issue.
To load dynamically jar, classes which implement an interface in an android application, some jobs need to be done in the jar :
Create your own manisfest for the jar and put this information
Manifest-Version: 1.0
Module-Class: com.example.myjar.MyPeripheral
Export your jar using eclipse and put in parameter that it uses its own manisfest
Create the classes.dex associated to the jar (this file is needed by the Dalvik VM, simply jar can not be read by the dalvik VM)
dx --dex --output=C:\classes.dex C:\MyJar.jar
Be carefull, the name of the dex file MUST BE classes.dex
Add the file classes.dex in the jar file
aapt add C:\MyJar.jar C:\classes.dex
You need also to have the right to write into the dalvik cache directory
adb shell chmod 777 /data/dalvik-cache
Do it each time, your relaunch your emulator
put this jar file into the emulator for example on the SDcard
Use a PathClassLoader to load the jar file
dalvik.system.PathClassLoader myClassLoader = new dalvik.system.PathClassLoader("/Sdcard/MyJar.jar", ModuleLoader.class.getClassLoader());
NB : the LogCat in Eclipse gives you precious information. Do not forget to look at its messages
Below, the code :
My interface :
package com.example.StandartPeripheral;
public interface IPeripheral {
public boolean Initialize();
public boolean configure();
public boolean execute();
public String GetName();
}
MyPeripheral which implements the interface
public class MyPeripheral implements IPeripheral {
//public static void main(String[] args) {}
private final String PeripheralName = "MyPeripheral";
public boolean Initialize()
{
System.out.println("Initialize ");
return true;
};
public boolean configure()
{
System.out.println("Configure !");
return true;
};
public boolean execute()
{
System.out.println("Execute !");
return true;
};
public String GetName()
{
return PeripheralName;
}
}
How to load dynamically the jar files
package com.example.ModuleLoader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import com.example.StandartPeripheral.IPeripheral;
public class ModuleLoader {
private static List urls = new ArrayList();
// to retrieve the unknown list of jar files contained in the directory folder
// in my case it was in the SDCard folder
// link to create a SDCard directory on the Eclipse emulator
// http://blog.lecacheur.com/2010/01/14/android-avoir-acces-a-une-carte-memoire-dans-lemulateur/
// retrieve the classes of all this jar files and their URL (location)
private static List getModuleClasses(String folder)
{
List classes = new ArrayList();
//we are listing the jar files
File[] files = new File(folder).listFiles(new ModuleFilter());
for(File f : files)
{
JarFile jarFile = null;
try
{
//we open the jar file
jarFile = new JarFile(f);
//we recover the manifest
Manifest manifest = jarFile.getManifest();
//we recover the class name of our peripherals thanks to ours manifest
String moduleClassName = manifest.getMainAttributes().getValue("Module-Class");
classes.add(moduleClassName);
urls.add(f.toURI().toURL());
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if(jarFile != null)
{
try
{
jarFile.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
return classes;
}
private static class ModuleFilter implements FileFilter {
@Override
public boolean accept(File file) {
return file.isFile() && file.getName().toLowerCase().endsWith(".jar");
}
}
//This function loads the jar file into the dalvik system
// retrieves the associated classes using its name
// and try to know if the loaded classes are implementing our interface
public static List loadModules(String folder, Context CurrentContext) {
List modules = new ArrayList();
List classes = getModuleClasses(folder);
int index = 0;
for(String c : classes)
{
try
{
dalvik.system.PathClassLoader myClassLoader = new dalvik.system.PathClassLoader(urls.get(index).toString(), ModuleLoader.class.getClassLoader());
Class> moduleClass = Class.forName(c, true, myClassLoader);
//check and cast to an interface, then use it
if(IPeripheral.class.isAssignableFrom(moduleClass))
{
@SuppressWarnings("unused")
Class castedClass = (Class)moduleClass;
IPeripheral module = (IPeripheral)moduleClass.newInstance();
modules.add(module);
}
index++;
}
catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
return modules;
}
}