2012-04-25 35 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