问题
I am developing an open-source emulator project, and it has multiple, customizable native plug-ins. These plug-ins are built as native shared object libraries (.so files), and have various interfaces between native and Java through JNI. Rather than distribute the APK with every single plug-in ever created, and in order to allow folks to build their own custom plug-ins, I need a method of importing these .so files any time after the app has been installed.
I've found that I can copy files to the folder /data/data/[package_name], but not to the lib/ sub-folder (because it is owned by the "system" group). To utilize the JNI interfaces in Java, I must call System.loadLibrary( libname ); However, this seems to require the .so file to be located in the lib/ sub-folder. The only way around this I can think of is to require the user to have a rooted device. Is there another way to accomplish this?
回答1:
Use System.load() instead:
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): Loading /data/data/com.foo.test/lib/liba.so...
D/dalvikvm( 1022): Trying to load lib /data/data/com.foo.test/lib/liba.so 0x40512640
D/dalvikvm( 1022): Added shared lib /data/data/com.foo.test/lib/liba.so 0x40512640
D/dalvikvm( 1022): No JNI_OnLoad found in /data/data/com.foo.test/lib/liba.so 0x40512640, skipping init
D/LibTest ( 1022): Loading /data/data/com.foo.test/lib/libb.so...
D/dalvikvm( 1022): Trying to load lib /data/data/com.foo.test/lib/libb.so 0x40512640
D/dalvikvm( 1022): Added shared lib /data/data/com.foo.test/lib/libb.so 0x40512640
D/dalvikvm( 1022): No JNI_OnLoad found in /data/data/com.foo.test/lib/libb.so 0x40512640, skipping init
回答2:
Distribute your plugins as APKs, and communicate from the host to the plugins via IPC mechanisms:
- broadcast
Intents - services (command or binding patterns)
ContentProvider
As a side bonus, if a plugin needs more/different permissions than the host, this is supported.
Admittedly, this will require IPC, which adds non-trivial overhead, steering you in the direction of a coarse-grained plugin communication protocol. And, it will use up more RAM (and the extra CPU time for the overhead will use up more battery life).
回答3:
You can use dlopen for loading a so file with c++. I use this code in c++ to load so files in any folder.
// 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();
来源:https://stackoverflow.com/questions/10324956/how-do-i-import-shared-object-libraries-at-runtime-in-android