如何在Android中运行时导入共享对象库?

时间:2012-04-25 22:55:44

标签: android android-ndk java-native-interface shared-libraries

我正在开发一个开源模拟器项目,它有多个可自定义的本机插件。这些插件构建为本机共享对象库(.so文件),并通过JNI在本机和Java之间具有各种接口。而不是使用每个创建的插件分发APK,并且为了允许人们构建他们自己的自定义插件,我需要一种在安装应用程序后随时导入这些.so文件的方法。

我发现我可以将文件复制到文件夹/ data / data / [package_name],但不能复制到lib /子文件夹(因为它归“system”组所有)。要在Java中使用JNI接口,我必须调用System.loadLibrary(libname);但是,这似乎要求.so文件位于lib /子文件夹中。我能想到的唯一方法是要求用户拥有一个root设备。还有另一种方法可以实现这个目标吗?

3 个答案:

答案 0 :(得分:1)

将您的插件分发为APK,并通过IPC机制从主机与插件进行通信:

  • 广播Intents
  • 服务(命令或绑定模式)
  • ContentProvider

作为附带奖励,如果插件需要比主机更多/不同的权限,则支持此功能。

不可否认,这将需要IPC,它增加了非常重要的开销,引导您朝着粗粒度插件通信协议的方向发展。并且,它会消耗更多的RAM(并且额外的CPU时间用于开销将耗费更多的电池寿命)。

答案 1 :(得分:1)

改为使用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):在/data/data/com.foo.test/lib/liba.so 0x40512640中找不到JNI_OnLoad,跳过初始化
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):添加了共享库/data/data/com.foo.test/lib/libb.so 0x40512640
D / dalvikvm(1022):在/data/data/com.foo.test/lib/libb.so 0x40512640中找不到JNI_OnLoad,跳过init

答案 2 :(得分:1)

您可以使用dlopen使用c ++加载so文件。 我在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();