我正在开发一个开源模拟器项目,它有多个可自定义的本机插件。这些插件构建为本机共享对象库(.so文件),并通过JNI在本机和Java之间具有各种接口。而不是使用每个创建的插件分发APK,并且为了允许人们构建他们自己的自定义插件,我需要一种在安装应用程序后随时导入这些.so文件的方法。
我发现我可以将文件复制到文件夹/ data / data / [package_name],但不能复制到lib /子文件夹(因为它归“system”组所有)。要在Java中使用JNI接口,我必须调用System.loadLibrary(libname);但是,这似乎要求.so文件位于lib /子文件夹中。我能想到的唯一方法是要求用户拥有一个root设备。还有另一种方法可以实现这个目标吗?
答案 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();