Как я могу загрузить файл jar динамически в приложении Android (4.0.3)

У меня есть приложение для Android, которое должно загружать динамически класс, неопределенное число класса jar, который реализовал интерфейс.

На самом деле, я смотрю на каталог и перечисляю все файлы jar, которые находятся в этом каталоге. Я открываю манифест файла jar и нахожу соответствующий класс и перечисляю его. И после этого я установил dexClassLoader для загрузки всех файлов jar и поиска, если классы, которые я нашел в manessest, реализуют мой интерфейс. Таким образом, я могу иметь весь класс, который реализовал мой интерфейс, не зная их при начале

Чтобы возобновить работу, у меня есть список классов jar, которые реализуют мой интерфейс, но список неизвестен моим приложением android и мной. Список классов jar может меняться каждый раз, когда я запускаю свое приложение.

Но когда я пытался создать DexClassLoader, это не удалось. У меня всегда есть нулевой указатель

DexClassLoader classLoader = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),dexOutputDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader()); 

Чтобы выполнить мой тест, я использовал эмулятор. Я скопировал с моими DDMS файлы jar в каталог /data/data/com.example.Myappli/JarFilesDirectory/*.jar

Обратите внимание, что мой файл jar содержит файл dex

Я много читал об этом. Некоторые проблемы с разрешениями я пробовал все, но не нашел решение

Может кто-то мне помочь, пожалуйста !!!

Здесь содержание манифеста файла jar

Манифест-версия: 1.0

Модуль-класс: com.example.asktester.AskPeripheral

Здесь мой код:

Открытый класс 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; } 

Я нашел решение своей проблемы.

Чтобы загрузить динамически jar, классы, которые реализуют интерфейс в приложении Android, необходимо выполнить некоторые задания в банке:

  • Создайте свой собственный manessest для банки и поместите эту информацию

      Manifest-Version: 1.0 Module-Class: com.example.myjar.MyPeripheral 
  • Экспортируйте свою банку с помощью eclipse и введите параметр, который использует свой собственный manessest

  • Создайте class.dex, связанный с jar (этот файл необходим Dalvik VM, просто jar не может быть прочитан dalvik VM)

     dx --dex --output=C:\classes.dex C:\MyJar.jar 

Будьте осторожны, имя файла dex ДОЛЖНО БЫТЬ class.dex

  • Добавьте файл classes.dex в файл jar

     aapt add C:\MyJar.jar C:\classes.dex 
  • Вы также должны иметь право на запись в каталог кеша dalvik

      adb shell chmod 777 /data/dalvik-cache 

    Делайте это каждый раз, перезагружая свой эмулятор

  • Поместите этот файл jar в эмулятор, например, на SD-карту

  • Используйте PathClassLoader для загрузки файла jar

     dalvik.system.PathClassLoader myClassLoader = new dalvik.system.PathClassLoader("/Sdcard/MyJar.jar", ModuleLoader.class.getClassLoader()); 

NB: LogCat в Eclipse дает вам ценную информацию. Не забудьте посмотреть его сообщения

Ниже приведен код:

Мой интерфейс :

 package com.example.StandartPeripheral; public interface IPeripheral { public boolean Initialize(); public boolean configure(); public boolean execute(); public String GetName(); } 

MyPeripheral, который реализует интерфейс

 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; } } 

Как динамически загружать файлы jar

 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; } } 

Также было бы неплохо использовать ClassLoader, а не загрузчик класса пути Dalvik:

  ClassLoader cl = new DexClassLoader(url, ApplicationConstants.ref_currentActivity.getFilesDir().getAbsolutePath(), null, ModuleList.class.getClassLoader()); 

Где url – это местоположение файла, который вы загружаете «из». ApplicationConstants.ref_currentActivity – это просто класс активности – моя реализация довольно сложна из-за динамической модульной загрузки – поэтому мне нужно было отслеживать ее таким образом, но другие, возможно, просто используют «это», если этот класс уже является активностью.

Причина MAIN для использования загрузчика классов по сравнению с dalvik – заключается в том, что он не требует, чтобы файлы записывались в кеш, и поэтому разрешение chmod 777 / data / dalvik-cache не требуется – и, конечно же, вы также не захотите Необходимо пропустить эту команду из корневого каталога на корневом телефоне.

Всегда лучше не заставлять пользователей заставлять их использовать, просто потому, что это требует ваше приложение. Особенно, если ваше приложение является более профессиональным «ориентированным на компанию», – обычно применяются правила работы с использованием корневых телефонов.

Если у кого-то есть вопросы по модульной загрузке, пожалуйста, не стесняйтесь спрашивать. Основа моего текущего кода – все благодаря Вирджини Войрин, а также мои собственные модификации. Всем удачи!

Intereting Posts
Подтверждение подписки Google возвращает код ошибки 400 Недействительный Добавьте определенное количество времени в текущее время и напишите его Ошибка при приложению PhoneGap при съемке новой фотографии с помощью плагина камеры Ошибка QNetwork при использовании Qt lib с собственным приложением JNI для Android Является ли Android requestLayout () правильным для анимации макета? Правильный способ остановить IntentService Как добавить заголовок в пользовательский диалог? Пример входа в Android с использованием метода POST с использованием REST API Сбой панели состояния панели инструментов Кросс-платформенное обновление в реальном времени для мобильных телефонов Следующие классы не могли быть созданы: android.support.design.widget.CoordinatorLayout Xamarin Android Player / Visual Studio: застрял в «Начальном эмуляторе» Вертикальный свиток Android-библиотеки MuPDF TabWidget мерцает, когда клавиатура скрывает андроид Может ли индийский разработчик загружать платные приложения на рынок Android?