2012-04-25 52 views
2

我正在开发一个开源的模拟器项目,它有多个可自定义的本地插件。这些插件被构建为本地共享对象库(.so文件),并通过JNI在本地和Java之间提供各种接口。我们需要一种在应用程序安装后随时导入这些.so文件的方法,而不是将APK分发到创建的每个插件中,为了让人们可以构建自己的自定义插件,我需要一种方法来随时导入这些.so文件。如何在Android中的运行时导入共享对象库?

我发现我可以将文件复制到文件夹/ data/data/[package_name],但不是lib /子文件夹(因为它属于“系统”组)。为了在Java中使用JNI接口,我必须调用System.loadLibrary(libname);但是,这似乎需要.so文件位于lib /子文件夹中。解决这个问题的唯一方法就是要求用户拥有一台根植设备。有没有另外一种方法来完成这个?

回答

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

$亚行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,跳过初始化

+0

啊哈,我不知道System.load是用于这个。猜猜我应该在发表问题之前进行研究。谢谢您的帮助! – paulscode 2012-04-27 01:51:35

1

分发您的插件,APK,以及通过IPC机制从主机到插件通信:

  • 广播Intents
  • 服务(命令或结合模式)
  • ContentProvider

作为一个附加奖励,如果插件需要比主机更多/不同的权限,则支持该插件。

不可否认,这将需要IPC,它会增加不重要的开销,将您指向粗粒度的插件通信协议。而且,它将使用更多的RAM(并且额外的CPU时间用于开销将耗尽更多的电池寿命)。

+0

它可以作为替代方案,但不是最好的解决方案。虽然,很高兴有选择。谢谢! – paulscode 2012-05-01 02:58:34

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(); 
+0

谢谢!实际上我有这个部分,但没有注意到它也可以在Java端完成。尽管如此,很高兴在这里有这个答案。谢谢! – paulscode 2012-05-01 02:56:54