如何在NDK上将本机运行时库与dlopen集成?

时间:2013-03-30 13:37:32

标签: android android-ndk

对于我的本机c ++项目,我要设置预编译共享库的运行时加载,可以在启动时使用配置由客户端更改。什么是在Android上调用dlopen的正确方法?无论我做什么,如果我没有在我的Android.mk文件中将此库定义为预编译库,dlopen就永远不会打开任何共享库:

LOCAL_PATH := $(call my-dir)

LOCAL_CFLAGS += -DDEBUG 
LOCAL_CFLAGS += -DANDROID 

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar/bar.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/bar
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := native_activity
LOCAL_SRC_FILES := main.cpp

LOCAL_LDLIBS := -llog 
LOCAL_LDLIBS += -landroid 

LOCAL_SHARED_LIBRARIES := bar

LOCAL_STATIC_LIBRARIES += android_native_app_glue

include $(BUILD_SHARED_LIBRARY)
$(call import-module, android/native_app_glue)

在我的原生活动主类中,我尝试使用:

加载库
void* lib = dlopen("/system/lib/armeabi-v7a/libbar.so", RTLD_NOW);
if (lib == NULL) {
    fprintf(stderr, "Could not dlopen(\"libbar.so\"): %s\n",
    dlerror());
    exit(1);
}else{
    LOGI("Library successfully loaded!");

    if (dlsym(lib, "bar") == NULL) {
        fprintf(stderr, "Symbol 'bar' is missing from shared library!!\n");        
    }else{
        LOGI("Library symbol found!"); 
    }

    int x = bar(25);
    LOGI("Bar return value: %i", x);
}

这个实现的缺点是它不是真正的运行时加载,因为我还要使用JAVA机制在JNI启动时加载这个库。

如果我从Android.mk中删除了bar库预编译定义,请在启动时禁用JNI加载,并将预编译库的副本添加到应该存在的systems / lib文件夹中(使用预编译定义存储它的位置相同) ,库的加载失败。我检查了apk包,它包含了我在lib文件夹中手动复制的库,如预期的那样。

为什么这不起作用?是否可以执行外部预编译库的严格本机运行时库加载?确保我的库添加到apk包的最佳方法是什么?

1 个答案:

答案 0 :(得分:12)

Android上的最佳策略是从Java加载所有本机库,即使您根据某些运行时规则选择要加载的库。您可以使用 dlsym(0,...)然后访问那里的导出函数。

APK构建器将获取它在libs/armeabi-v7a中找到的所有 .so 文件,安装程序会将它们解压缩到/data/data/<your.package>/lib目录。