Как добавить динамическую библиотеку в Android?

Я хочу добавить не-родную общую библиотеку для Android, чтобы каждое приложение на устройстве могло ее использовать. Я имею в виду использование упакованных классов, подобно основной библиотеке, как если бы они присутствовали в самом приложении.

Я изучил исходный код Android, чтобы выяснить способ добавления нового пути к приложению ClassLoader и выяснил, что он создан во время запуска, и нет способа изменить пути позже. Я могу использовать свой собственный ClassLoader, но все, что я получу после загрузки класса, будет ссылкой на объект Class. Таким образом, я буду вынужден работать через механизм отражения, который медленнее, чем встроенная система выполнения.

Есть ли способ организовать общую библиотеку на Android?

Обновление:, чтобы быть понятным здесь, мне не нужно взаимодействие между приложениями. Мне нужны классы, которые я могу использовать в любом приложении. Также статические библиотеки не очень подходят моим потребностям, потому что это раздувает приложения.

Ответ 1

Недавнее сообщение в блоге Android объясняет, что именно мне нужно:

Dalvik VM предоставляет разработчикам возможность выполнять пользовательскую загрузку классов. Вместо загрузки исполняемых файлов Dalvik ( "dex" ) из местоположения по умолчанию приложение может загружать их из альтернативных мест, таких как внутреннее хранилище или по сети.

Ключ должен использовать DexClassLoader для загрузки необходимой библиотеки. После этого код можно получить либо через интерфейсы, либо с помощью отражения.

Ответ 2

Существует два способа создания динамической библиотеки загрузки в Android

  • используйте sharedUserId в AndroidManifest для ваших приложений и проекта библиотеки

  • использовать dalvik.system.DexClassLoader для загрузки библиотеки

Код библиотеки:

Он содержит только код Java без каких-либо конкретных точек входа в Android. AndroidManifest.xml просто содержит этот атрибут android:sharedUserId

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testlib"
    android:sharedUserId="com.example.testlib"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" />

    <application android:label="@string/app_name"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/AppTheme">

    </application>

</manifest>

TestCore.java

package com.example.testlib;

public class TestCore implements ITestCore{
    private int count = 0;
    public String testString(String arg) {
        String res = arg + " " + count;
        count++;
        return res;
    }
}

Пример кода приложения

Приложение, использующее библиотеку. Вот только AndroidManifest.xml и TestApplication.java, которые делают трюк. Все остальные сотрудники приложения, как обычно,

AndroidManifest.xml

Будьте осторожны, чтобы использовать одно и то же значение android: sharedUserId в AndroidManifest.xml в качестве библиотеки one

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testapp"
    android:sharedUserId="com.example.testlib"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme"
        android:name=".TestApplication" >
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="android.app.Activity" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
                <category android:name="android.intent.category.DEFAULT"/>
                </intent-filter>
        </activity>
    </application>

</manifest>

ITestCore.java

Интерфейс библиотеки должен быть объявлен в приложении, чтобы избежать отражения использования

package com.example.testlib;

public interface ITestCore {
    String testString(String arg);
}

TestApplication.java

В приложении onCreate обработчик происходит реальная работа

package com.example.testapp;

import com.example.testlib.ITestCore;
import dalvik.system.DexClassLoader;
import android.app.Application;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;

public class TestApplication extends Application {
    ClassLoader libClassLoader;

    @Override
    public void onCreate() {
        PackageManager pm = getPackageManager();
        String libSrcPath = null;
        for (ApplicationInfo app : pm.getInstalledApplications(0)) {
            if (app.packageName.equals("com.rhomobile.testlibrary")) {
                libSrcPath = app.sourceDir;
                Log.d("TestApplication", ">>>>>>>>>>>>>>> package: " + app.packageName + ", sourceDir: " + app.sourceDir);
            }
        }
        try {
            libClassLoader = new DexClassLoader(libSrcPath, getDir("dex", 0).getAbsolutePath(), null, getClassLoader());
            Class<?> clazz = libClassLoader.loadClass("com.rhomobile.testlib.TestCore");            
            try {
                ITestCore core = (ITestCore)clazz.newInstance();
                String str = core.testString("TestApplication 1:");
                Log.i("TestApplication", ">>>>>>>>>>>>>>> output: " + str);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            Log.e("TestApplication", libClassLoader.toString());
            e.printStackTrace();
        }
    }
}

Ответ 4

Даже если вы получите объект класса, модель безопасности (связующее) на Android запретит приложениям читать в другой каталог приложений.

Лучшее, что вы можете сделать на не-корневом телефоне, - это создавать библиотеки через Intents.