如何在Android中的运行时导入共享对象库?
我正在开发一个开源的模拟器项目,它有多个可自定义的本地插件。这些插件被构建为本地共享对象库(.so文件),并通过JNI在本地和Java之间提供各种接口。我们需要一种在应用程序安装后随时导入这些.so文件的方法,而不是将APK分发到创建的每个插件中,为了让人们可以构建自己的自定义插件,我需要一种方法来随时导入这些.so文件。如何在Android中的运行时导入共享对象库?
我发现我可以将文件复制到文件夹/ data/data/[package_name],但不是lib /子文件夹(因为它属于“系统”组)。为了在Java中使用JNI接口,我必须调用System.loadLibrary(libname);但是,这似乎需要.so文件位于lib /子文件夹中。解决这个问题的唯一方法就是要求用户拥有一台根植设备。有没有另外一种方法来完成这个?
使用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]);
}
}
$亚行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):添加了共享lib/data/data//data/data/com.foo.test/lib/liba.so 0x40512640
D/dalvikvm(1022):没有在/data/data/com.foo.test/lib/liba.so中找到JNI_OnLoad 0x40512640,跳过初始化
D/LibTest(1022):加载/data/data/com.foo.test/lib/libb.so ...
D/dalvikvm(1022):试图加载lib/data/data/com (1022):添加共享库/data/data/com.foo.test/lib/libb.so 0x40512640
D/dalvikvm(1022):否在/data/data/com.foo.test/lib/libb.so 0x40512640中找到JNI_OnLoad,跳过初始化
分发您的插件,APK,以及通过IPC机制从主机到插件通信:
- 广播
Intents
- 服务(命令或结合模式)
ContentProvider
作为一个附加奖励,如果插件需要比主机更多/不同的权限,则支持该插件。
不可否认,这将需要IPC,它会增加不重要的开销,将您指向粗粒度的插件通信协议。而且,它将使用更多的RAM(并且额外的CPU时间用于开销将耗尽更多的电池寿命)。
它可以作为替代方案,但不是最好的解决方案。虽然,很高兴有选择。谢谢! – paulscode 2012-05-01 02:58:34
你可以使用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();
谢谢!实际上我有这个部分,但没有注意到它也可以在Java端完成。尽管如此,很高兴在这里有这个答案。谢谢! – paulscode 2012-05-01 02:56:54
啊哈,我不知道System.load是用于这个。猜猜我应该在发表问题之前进行研究。谢谢您的帮助! – paulscode 2012-04-27 01:51:35