我怎样才能在一个Android应用程序动态加载一个jar文件(4.0.3) [英] How can i Load a jar file dynamically in an android application (4.0.3)

查看:129
本文介绍了我怎样才能在一个Android应用程序动态加载一个jar文件(4.0.3)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Android应用程序有加载动态类,一个罐子类的不确定数目实现的接口。

其实,我看到一个目录,列出所有的jar文件,这些文件是在这个目录下 我打开jar文件的清单,并找到相关的类,并列出它们。 及后,我instancied一个dexClassLoader加载所有jar文件,并找到,如果我已经找到了manisfest的类实现我的接口。 像这样我可以拥有所有这些实现我的接口,不知道他们在begginning

要重新开始,我有类罐子它实现我的界面列表,但该列表是未知的我的Andr​​oid应用程序,并通过我。瓶类的列表可以每次我启动我的应用程序的时间改变了。

但是,当我试图创建它失败的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆