2

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

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

4

3 回答 3

2

使用 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]);
    }
}

$亚行日志猫

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

于 2012-04-26T14:30:12.370 回答
1

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

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

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

诚然,这将需要 IPC,它增加了不平凡的开销,引导您朝着粗粒度的插件通信协议的方向发展。而且,它会消耗更多的 RAM(额外的 CPU 时间会消耗更多的电池寿命)。

于 2012-04-25T23:20:37.593 回答
1

您可以使用 dlopen 使用 c++ 加载 so 文件。我在 c++ 中使用此代码将 so 文件加载到任何文件夹中。

// 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();
于 2012-04-29T15:24:39.133 回答