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

Hel*_*und 6 android android-ndk

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

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)
Run Code Online (Sandbox Code Playgroud)

在我的本机活动主类中,我尝试加载库:

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);
}
Run Code Online (Sandbox Code Playgroud)

这种实现的缺点是实际上并不是运行时加载,因为我还要使用JAVA机制在JNI启动时加载这个库.

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

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

Ale*_*ohn 12

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

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

  • 在C中实现等效的`System.LoadLibrary()`的主要问题是位置`/ data/data/<your.package>/lib`是一个未记录的实现细节,可能会在任何未来发生变化发布操作系统或由于其中一个OEM的一些调整. (4认同)
  • 感谢您的提示,我会检查一下.同时我解决了有关图书馆位置信息的问题.如果我将"/data/data/<your.package>/lib"视为库搜索路径,我可以成功使用dlopen加载外部预编译库. (2认同)