Как импортировать библиотеки общих объектов во время выполнения в Android?

Я разрабатываю проект эмулятора с открытым исходным кодом, и он имеет несколько настраиваемых собственных подключаемых модулей. Эти подключаемые модули построены как собственные библиотеки общих объектов (файлы .so) и имеют различные интерфейсы между собственным интерфейсом и Java через JNI. Вместо того, чтобы распространять APK с каждым когда-либо созданным подключаемым модулем и чтобы люди могли создавать свои собственные настраиваемые подключаемые модули, мне нужен способ импорта этих файлов .so в любое время после установки приложения.

Я обнаружил, что могу копировать файлы в папку / data / data / [package_name], но не в подпапку lib / (потому что она принадлежит группе "system"). Чтобы использовать интерфейсы JNI в Java, я должен вызвать System.loadLibrary (libname); Однако, похоже, для этого требуется, чтобы файл .so находился в подпапке lib /. Единственный способ обойти это, что я могу придумать, - это потребовать от пользователя иметь рутированное устройство. Есть ли другой способ добиться этого?


person paulscode    schedule 25.04.2012    source источник


Ответы (3)


Вместо этого используйте System.load ():

static
{
    final String[] libs = {
        "/data/data/com.foo.test/lib/liba.so",
        "/data/data/com.foo.test/lib/libb.so"
    };

    for (int i=0; i<libs.length; ++i)
    {
        Log.d(TAG, "Loading " + libs[i] + "...");
        System.load(libs[i]);
    }
}

$ adb logcat

D / LibTest (1022): загрузка /data/data/com.foo.test/lib/liba.so ...
D / dalvikvm (1022): попытка загрузить lib /data/data/com.foo. test / lib / liba.so 0x40512640
D / dalvikvm (1022): добавлена ​​общая библиотека /data/data/com.foo.test/lib/liba.so 0x40512640
D / dalvikvm (1022): нет JNI_OnLoad находится в /data/data/com.foo.test/lib/liba.so 0x40512640, без инициализации
D / LibTest (1022): загрузка /data/data/com.foo.test/lib/libb.so. ..
D / dalvikvm (1022): Попытка загрузить lib /data/data/com.foo.test/lib/libb.so 0x40512640
D / dalvikvm (1022): Добавлен общий доступ к lib / data / data /com.foo.test/lib/libb.so 0x40512640
D / dalvikvm (1022): JNI_OnLoad не найден в /data/data/com.foo.test/lib/libb.so 0x40512640, инициализация пропущена

person Owen    schedule 26.04.2012
comment
Ага, я не знал, что для этого использовался System.load. Думаю, мне следует провести исследование, прежде чем размещать вопрос. Спасибо за помощь! - person paulscode; 27.04.2012
comment
Разве для этого не требуется, чтобы библиотеки были в data / data / com.foo.test / lib / liba.so? как добавить файлы в этот каталог? - person bobbyg603; 10.07.2020

Распространяйте свои плагины в виде APK и общайтесь от хоста к плагинам через механизмы IPC:

  • трансляция Intents
  • службы (шаблоны команд или привязки)
  • ContentProvider

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

По общему признанию, для этого потребуется IPC, который добавляет нетривиальные накладные расходы, направляя вас в направлении общего протокола связи плагинов. И он будет использовать больше оперативной памяти (а дополнительное время процессора для накладных расходов приведет к увеличению времени автономной работы).

person CommonsWare    schedule 25.04.2012
comment
Это нормально как альтернатива, но не лучшее решение. Тем не менее, неплохо иметь варианты. Спасибо! - person paulscode; 01.05.2012

Вы можете использовать dlopen для загрузки файла so с помощью c ++. Я использую этот код в C ++ для загрузки файлов в любую папку.

// KGEmain function pointer
typedef void (*KGEmain) ();

std::string strPluginName = "/data/data/com.kge.android/lib/lib";
strPluginName += appname;
strPluginName += ".so";

void* handle = dlopen(strPluginName.c_str(), RTLD_LAZY);

const char* error;

if (!handle)
{
    LOGE("can't load the %s plugin. (%s)", strPluginName.c_str(), dlerror());
    return;
}
// Clear any exiting error
dlerror();

// Load the KGEmain function
pFn = (KGEmain)dlsym(handle, "KGEmain");
if ((error = dlerror()) != NULL || !pFn)
{
    LOGE("KGEmain function dose not find in %s plugin.\n%s", strPluginName.c_str(), error);
    return;
}

pFn();
person kochol    schedule 29.04.2012
comment
Спасибо! У меня действительно была эта часть, но я не заметил, что это можно сделать и на стороне Java. Тем не менее, хорошо, что здесь есть этот ответ, для полной картины. Спасибо! - person paulscode; 01.05.2012