Использование DexClassLoader в Android для загрузки нескольких файлов.APK в качестве плагинов

Я занимаюсь разработкой фреймворка / приложения в Android (5.0+), который должен иметь возможность устанавливать дополнительные "плагины"/ приложения без участия пользователя.

Я начал изучать DALVIK/ART DexClassLoader для реализации этой функциональности. Поначалу, похоже, все работает хорошо, мне удалось загрузить первый плагин.apk (который я собираю в Android-студии с обычной сборкой gradle), и он разрешил класс плагина, который я затем продолжил делать экземпляром. Однако когда код попадает во второй плагин, он не может загрузить класс плагина. Я думаю, что это связано с загрузчиком классов. Я получаю исключение ClassNotFoundException. Кто-нибудь знаком с этой проблемой?

private static Object ParseZipFile(Context context, File file) {
    String path = file.getParentFile().getAbsolutePath() + "/" + getFilenameWithoutExtension(file) +"Install";
    unzipPlugin(file, path); // /Download/Framework/plugins/someplugin.zip -> /Download/Framework/plugins/someplugin
    String configPath = path+"/plugin.config";
    String className = getClassNameFromConfig(configPath);
    if (className == null) {
        System.out.println("No plugin.config found in .zip");
        return null;
    }
    File apkPath = new File(path);
    File [] files = apkPath.listFiles(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".apk");
        }
    });
    for(File apkFile: files) {
        File dexOutputDir = context.getDir("dex", Context.MODE_PRIVATE);
        DexClassLoader dexClassLoader = new DexClassLoader(apkFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null, context.getClassLoader());

        try {
            return GetPluginClass(dexClassLoader, className);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
    return null;
}

private static Object GetPluginClass(DexClassLoader classloader, String className) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {

    Log.v("loadDexClasses", "Searching for class : " + className);
    Class<?> classToLoad = classloader.loadClass(className);
    Object plugin = classToLoad.newInstance();
    return plugin;
}

Контекст - это контекст службы Android, на которой выполняется код управления плагином.

Вот трассировка стека

02-04 10:12:21.118 8304-8304/se.company.framework W/System.err: java.lang.ClassNotFoundException: Didn't find class "se.company.isa.IsaPlugin" on path: DexPathList[[zip file "/storage/emulated/0/Download/Framework/plugins/isaInstall/isa.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
02-04 10:12:21.118 8304-8304/se.company.framework W/System.err:     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at se.company.pluginlib.PluginManager.GetPluginClass(PluginManager.java:204)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at se.company.pluginlib.PluginManager.ParseZipFile(PluginManager.java:151)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at se.company.pluginlib.PluginManager.loadDexClasses(PluginManager.java:122)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at fi.iki.elonen.SimpleWebServer.initPlugin(SimpleWebServer.java:125)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at fi.iki.elonen.SimpleWebServer.<init>(SimpleWebServer.java:111)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at se.company.framework.HttpdService.onStartCommand(HttpdService.java:33)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3010)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.app.ActivityThread.-wrap17(ActivityThread.java)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1442)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.os.Looper.loop(Looper.java:148)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5417)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
02-04 10:12:21.119 8304-8304/se.company.framework W/System.err:     Suppressed: java.lang.ClassNotFoundException: Didn't find class "se.company.isa.IsaPlugin" on path: DexPathList[[zip file "/data/app/se.company.framework-1/base.apk"],nativeLibraryDirectories=[/data/app/se.company.framework-1/lib/arm64, /vendor/lib64, /system/lib64]]
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:         ... 16 more
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:         Suppressed: java.lang.ClassNotFoundException: se.company.isa.IsaPlugin
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.Class.classForName(Native Method)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:     at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:             ... 17 more
02-04 10:12:21.120 8304-8304/se.company.framework W/System.err:         Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available

1 ответ

Решение

Я обнаружил проблему, она не имела никакого отношения к коду. Приведенный выше код работает как задумано.

Другие вопросы по тегам