Android - Использование DexClassLoader для загрузки файла APK - PullRequest
19 голосов
/ 25 мая 2010

Я ударил немного стены. Любая помощь будет оценена. У меня есть приложение, которое я хочу использовать DexClassLoader для загрузки другого файла apk.

Вот мой код:

DexClassLoader dLoader = new DexClassLoader("/sdcard/download/test.apk","/sdcard/download",null,ClassLoader.getSystemClassLoader().getParent());
Class calledClass = dLoader.loadClass("com.test.classname");
Intent it=new Intent(this, calledClass);
it.setClassName("com.test", "com.test.classname");
startActivity(it);

Теперь я уже установил test.apk, поэтому при запуске приведенного выше кода работал нормально и запустил приложение. Однако я хочу быть в состоянии запустите это без test.apk уже установлен (как это было бы победить весь смысл приложения). Поэтому я удалил его и когда я снова запустил свое приложение, я получаю эту ошибку:

android.content.ActivityNotFoundException: Unable to find explicit
activity class {com.test/com.test.classname}; have you declared this
activity in your AndroidManifest.xml.

Так что я немного озадачен здесь. Эта деятельность объявлена ​​в Манифесте из apk я пытаюсь запустить. Я не могу заявить об этом в моих заявлениях Manifest. Есть идеи?

Спасибо, Крейг

Ответы [ 3 ]

11 голосов
/ 26 октября 2010

Попробуйте использовать PathClassLoader для Android :

    String packagePath = "com.mypackage";
    String classPath = "com.mypackage.ExternalClass";

    String apkName = null;
    try {
        apkName = getPackageManager().getApplicationInfo(packagePath,0).sourceDir;
    } catch (PackageManager.NameNotFoundException e) {
        // catch this
    }

    // add path to apk that contains classes you wish to load
    String extraApkPath = apkName + ":/path/to/extraLib.apk" 

    PathClassLoader pathClassLoader = new dalvik.system.PathClassLoader(
            apkName,
            ClassLoader.getSystemClassLoader());

    try {
        Class<?> handler = Class.forName(classPath, true, pathClassLoader);
    } catch (ClassNotFoundException e) {
        // catch this
    }
7 голосов
/ 17 августа 2014

Хотя вопрос старый, я отвечу, потому что я изо всех сил пытался найти четкий ответ на тот же вопрос для себя. Во-первых, я хотел бы подчеркнуть, что ясным требованием в вашем вопросе является загрузка класса из .apk, который еще не установлен на устройстве. Следовательно, вызов менеджера пакетов с помощью getPackageManager () и предоставление ему пути к пакету явно приведут к исключению NameNotFoundException, поскольку .apk , в котором есть пакет, не установлен на устройстве.

Таким образом, способ загрузки классов из файла .apk , который не установлен на устройстве (т. Е. У вас есть только файл .apk, хранящийся в каталоге на SDCARD), заключается в использовании DexClassLoader следующим образом:

1- Убедитесь, что у вас есть файл .apk в каталоге на вашей SDCARD. У меня есть Offloadme.apk в папке Download на моей SDCARD.

2- Добавьте разрешение на чтение в AndroidManifest.xml , чтобы приложение могло читать из манифеста.

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

3- Используйте следующие определения, чтобы определить путь к .apk, имя класса внутри apk и имя метода в этом классе, которое вы хотите вызвать:

final String apkFile =Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Offloadme.apk";
String className = "com.khaledalanezi.offloadme.SimpleCalculator";
String methodToInvoke = "add"; 

4- Используйте DexClassLoader , чтобы загрузить .apk и вызвать метод add в классе SimpleCalculator , используя отражение следующим образом:

    final File optimizedDexOutputPath = getDir("outdex", 0);

    DexClassLoader dLoader = new DexClassLoader(apkFile,optimizedDexOutputPath.getAbsolutePath(),
            null,ClassLoader.getSystemClassLoader().getParent());

    try {
        Class<?> loadedClass = dLoader.loadClass(className);
        Object obj = (Object)loadedClass.newInstance();
        int x =5;
        int y=6;
        Method m = loadedClass.getMethod(methodToInvoke, int.class, int.class);
        int z = (Integer) m.invoke(obj, y, x);              
        System.out.println("The sum of "+x+" and "+"y="+z);

    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InstantiationException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Обратите внимание, что в моем простом примере я добавил два числа, используя метод add , доступный в классе SimpleCalculator , загруженном из файла Offloadme.apk , хранящегося в моя SDCARD и я смогли напечатать правильный ответ 11.

0 голосов
/ 16 сентября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...