我怎样才能在一个Android应用程序动态加载一个jar文件(4.0.3) [英] How can i Load a jar file dynamically in an android application (4.0.3)
问题描述
我有一个Android应用程序有加载动态类,一个罐子类的不确定数目实现的接口。
其实,我看到一个目录,列出所有的jar文件,这些文件是在这个目录下 我打开jar文件的清单,并找到相关的类,并列出它们。 及后,我instancied一个dexClassLoader加载所有jar文件,并找到,如果我已经找到了manisfest的类实现我的接口。 像这样我可以拥有所有这些实现我的接口,不知道他们在begginning
类要重新开始,我有类罐子它实现我的界面列表,但该列表是未知的我的Android应用程序,并通过我。瓶类的列表可以每次我启动我的应用程序的时间改变了。
但是,当我试图创建它失败的DexClassLoader。我一直空指针
DexClassLoader类加载器=新DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(),空,ClassLoader.getSystemClassLoader());
为了使我的测试我使用的模拟器。我抄我的DDMS的文件拷贝到目录 /data/data/com.example.Myappli/JarFilesDirectory / *。罐
请注意,我的jar文件内容的DEX文件
我读了很多东西这件事。一些权限问题 我曾尝试每一件事情,但没有找到解决办法
有人可以帮助我请!
一个jar文件的清单在这里含量
清单-版本:1.0
模块级:com.example.asktester.AskPeripheral
下面我code:
公共类ModuleLoader组件{
私有静态列表<网址>网址=新的ArrayList<网址>();
私有静态列表<字符串> getModuleClasses(字符串的文件夹)
{
名单<字符串>类=新的ArrayList<字符串>();
//我们列出的jar文件
文件[]文件=新的文件(文件夹).listFiles(新ModuleFilter());
对于(F文件:文件)
{
jar文件的JarFile = NULL;
尝试
{
//我们打开jar文件
jar文件=新的jar文件(F);
//我们恢复清单
舱单舱单= jarFile.getManifest();
//我们恢复类
字符串moduleClassName = manifest.getMainAttributes()的getValue(模块级)。
classes.add(moduleClassName);
urls.add(f.toURI()的toURL());
}
赶上(IOException异常E)
{
e.printStackTrace();
}
最后
{
如果(jar文件!= NULL)
{
尝试
{
jarFile.close();
}
赶上(IOException异常E)
{
e.printStackTrace();
}
}
}
}
返回班;
}
私有静态类ModuleFilter实现的FileFilter {
@覆盖
公共布尔接受(档案文件){
返回file.isFile()&安培;&安培; file.getName()与toLowerCase()的endsWith(罐)。。;
}
}
私有静态类加载器的类加载器;
公共静态列表< IPeripheral> loadModules(字符串的文件夹,上下文CurrentContext)抛出IOException异常,ClassNotFoundException异常
{
名单< IPeripheral>模块=新的ArrayList< IPeripheral>();
名单<字符串>类= getModuleClasses(文件夹);
最终文件dexInternalStoragePath =新的文件(CurrentContext.getDir(地塞米松,Context.MODE_PRIVATE),ask.dex);
文件dexOutputDir = CurrentContext.getDir(地塞米松,Context.MODE_PRIVATE);
最终文件dexClasses =新的文件(CurrentContext.getDir(地塞米松,Context.MODE_PRIVATE),ASK.jar);
DexFile dexFile = DexFile.loadDex(dexClasses.getAbsolutePath(),dexOutputDir.getAbsolutePath(),0);
DexClassLoader类加载器=新DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(),空,ClassLoader.getSystemClassLoader());
//类<> MyClass的= classLoader.loadClass(com.example.asktester.AskPeripheral);
如果(IPeripheral.class.isAssignableFrom(MyClass的)){
类< IPeripheral> castedClass =(类< IPeripheral>)MyClass的;
IPeripheral模块= castedClass.newInstance();
modules.add(模块);
}
}
赶上(ClassNotFoundException的E1)
{
e1.printStackTrace();
}
赶上(InstantiationException E)
{
e.printStackTrace();
}
赶上(IllegalAccessException E)
{
e.printStackTrace();
}
}
返回模块;
}
我找到了解决我的问题。
要加载动态罐子,其中实现Android应用程序的接口类,需要一些工作要在罐子做的:
-
在罐子创建您自己的manisfest,并把这些信息
清单-版本:1.0 模块级:com.example.myjar.MyPeripheral
-
使用Eclipse导出你的罐子,把参数,它使用自己的manisfest
-
创建相关的罐子classes.dex (该文件所需要的Dalvik虚拟机,只需罐子不能由Dalvik虚拟机读)
DX --dex --output = C:\ classes.dex C:\ MyJar.jar
要当心,在DEX文件的名称必须是 classes.dex
-
添加文件classes.dex在jar文件
AAPT添加C:\ MyJar.jar C:\ classes.dex
-
您还必须有写入的Dalvik缓存目录的权
亚行外壳搭配chmod 777 /数据/达尔维克缓存
每次做吧,你重新发布你的模拟器
-
把这个jar文件到模拟器例如在SD卡
-
使用一个PathClassLoader加载jar文件
dalvik.system.PathClassLoader myClassLoader =新dalvik.system.PathClassLoader(/ SD卡/ MyJar.jar,ModuleLoader.class.getClassLoader());
注:在Eclipse的LogCat中为您提供了precious信息。别忘了看它的消息
下面,code:
我的界面
包com.example.StandartPeripheral;
公共接口IPeripheral {
公共布尔初始化();
公共布尔配置();
公共布尔的execute();
公共字符串的GetName();
}
MyPeripheral它实现了接口
公共类MyPeripheral实现IPeripheral {
//公共静态无效的主要(字串[] args){}
私人最终字符串PeripheralName =MyPeripheral;
公共布尔初始化()
{
的System.out.println(初始化);
返回true;
};
公共布尔配置()
{
的System.out.println(配置!);
返回true;
};
公共布尔的execute()
{
的System.out.println(执行!);
返回true;
};
公共字符串的GetName()
{
返回PeripheralName;
}
}
如何动态加载jar文件
包com.example.ModuleLoader;
进口的java.io.File;
进口java.io.FileFilter中;
进口java.io.IOException异常;
进口java.lang.reflect.InvocationTargetException;
进口java.lang.reflect.Method中;
进口的java.net.URL;
进口java.net.URLClassLoader的;
进口的java.util.ArrayList;
进口java.util.Iterator的;
进口的java.util.List;
进口java.util.jar.JarFile中;
进口java.util.jar.Manifest中;
进口android.annotation.Sup pressLint;
进口android.content.Context;
进口com.example.StandartPeripheral.IPeripheral;
公共类ModuleLoader组件{
私有静态列表<网址>网址=新的ArrayList<网址>();
//检索的JAR文件包含在目录文件夹中的未知列表
//我的情况下,它是在SD卡的文件夹
//链接创建Eclipse的仿真器SD卡目录
// http://blog.lecacheur.com/2010/01/14/android-avoir-acces-a-une-carte-memoire-dans-lemulateur/
//获取所有这些jar文件的类和他们的URL(位置)
私有静态列表<字符串> getModuleClasses(字符串的文件夹)
{
名单<字符串>类=新的ArrayList<字符串>();
//我们列出的jar文件
文件[]文件=新的文件(文件夹).listFiles(新ModuleFilter());
对于(F文件:文件)
{
jar文件的JarFile = NULL;
尝试
{
//我们打开jar文件
jar文件=新的jar文件(F);
//我们恢复清单
舱单舱单= jarFile.getManifest();
//我们恢复我们的外设类名拜我们的清单
字符串moduleClassName = manifest.getMainAttributes()的getValue(模块级)。
classes.add(moduleClassName);
urls.add(f.toURI()的toURL());
}
赶上(IOException异常E)
{
e.printStackTrace();
}
最后
{
如果(jar文件!= NULL)
{
尝试
{
jarFile.close();
}
赶上(IOException异常E)
{
e.printStackTrace();
}
}
}
}
返回班;
}
私有静态类ModuleFilter实现的FileFilter {
@覆盖
公共布尔接受(档案文件){
返回file.isFile()&安培;&安培; file.getName()与toLowerCase()的endsWith(罐)。。;
}
}
//这个函数加载jar文件到Dalvik的系统
//使用其名称检索相关类
//并试试就知道了,如果加载的类实现我们的接口
公共静态列表< IPeripheral> loadModules(字符串的文件夹,上下文CurrentContext){
名单< IPeripheral>模块=新的ArrayList< IPeripheral>();
名单<字符串>类= getModuleClasses(文件夹);
INT索引= 0;
对于(字符串C:班)
{
尝试
{
dalvik.system.PathClassLoader myClassLoader =新dalvik.system.PathClassLoader(urls.get(指数)的ToString(),ModuleLoader.class.getClassLoader());
类<> moduleClass =的Class.forName(C,真实,myClassLoader);
//检查和强制转换为接口,然后用它
如果(IPeripheral.class.isAssignableFrom(moduleClass))
{
@燮pressWarnings(未使用)
类< IPeripheral> castedClass =(类< IPeripheral>)moduleClass;
IPeripheral模块=(IPeripheral)moduleClass.newInstance();
modules.add(模块);
}
指数++;
}
赶上(ClassNotFoundException的E1)
{
e1.printStackTrace();
}
赶上(InstantiationException E)
{
e.printStackTrace();
}
赶上(IllegalAccessException E)
{
e.printStackTrace();
}
}
返回模块;
}
}
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 and list all the jar files which are in this directory I open the manifest of the jar file and find the associated class and list them. And after, i instancied a dexClassLoader to load all the jar files and to find if the classes i have found in the manisfest implement my interface. Like this I can have all the class which implemented my interface without knowing them at the begginning
To resume, i have a list of class jar which implement my interface but the list is unknown by my android application and by me. The list of jar class can changed each time i launch my application.
But when i tried to create the DexClassLoader it is failed. I have always a null pointer
DexClassLoader classLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
To make my test i used the emulator. I have copied with my DDMS the jar files into the directory /data/data/com.example.Myappli/JarFilesDirectory/*.jar
Notice that my jar file contents the dex file
I read a lot of thing about this. Some permissions issues I have tried every thing but not found the solution
Can someone help me please !!!
here the content of a manifest of a jar file
Manifest-Version: 1.0
Module-Class: com.example.asktester.AskPeripheral
Here my code :
public class ModuleLoader {
private static List<URL> urls = new ArrayList<URL>();
private static List<String> getModuleClasses(String folder)
{
List<String> classes = new ArrayList<String>();
//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
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");
}
}
private static ClassLoader classLoader;
public static List<IPeripheral> loadModules(String folder, Context CurrentContext) throws IOException, ClassNotFoundException
{
List<IPeripheral> modules = new ArrayList<IPeripheral>();
List<String> classes = getModuleClasses(folder);
final File dexInternalStoragePath = new File(CurrentContext.getDir("dex", Context.MODE_PRIVATE),"ask.dex");
File dexOutputDir = CurrentContext.getDir("dex", Context.MODE_PRIVATE);
final File dexClasses = new File(CurrentContext.getDir("dex", Context.MODE_PRIVATE),"ASK.jar");
DexFile dexFile = DexFile.loadDex(dexClasses.getAbsolutePath(), dexOutputDir.getAbsolutePath(), 0);
DexClassLoader classLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader());
//Class<?> myClass = classLoader.loadClass("com.example.asktester.AskPeripheral");
if(IPeripheral.class.isAssignableFrom(myClass )){
Class<IPeripheral> castedClass = (Class<IPeripheral>)myClass ;
IPeripheral module = castedClass.newInstance();
modules.add(module);
}
}
catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
}
return modules;
}
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<URL> urls = new ArrayList<URL>();
// 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<String> getModuleClasses(String folder)
{
List<String> classes = new ArrayList<String>();
//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<IPeripheral> loadModules(String folder, Context CurrentContext) {
List<IPeripheral> modules = new ArrayList<IPeripheral>();
List<String> 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<IPeripheral> castedClass = (Class<IPeripheral>)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;
}
}
这篇关于我怎样才能在一个Android应用程序动态加载一个jar文件(4.0.3)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!