android 调用第三方so库

首先要知道这个第三方的so库是不是按jni标准写的,如果是那就简单了,直接写个native调用就行了。如果不是那就比较麻烦了,必须要把这个so库里面的函数封装一下在调用,下面进入正题。

假设这个库放在/system/vendor/lib下面,名字为libtest.so,我们要调用的方法是get_status,我分别列出在第三方的app和framewok怎样调用。

首先是在第三方app的调用,这里的核心就是使用dlopen函数,然后使用dlsym找到这个函数,最后在调用这个函数。这还是公司的一个前辈教我的,真心不懂c.....

//定义LOGE打印
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
//定义一个指针函数,我这里没有传参数,如果需要的话可以在这里加参数
typedef int (*CAC_FUNC)();
//定义一个so库的路径
#define LIB_CACULATE_PATH "/system/vendor/lib/libtest.so"
Java_com_flycom_jnitest_MainActivity_intFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    LOGD("cac_func: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    void *handle;
    char *error;
    int r;
    CAC_FUNC cac_func = NULL;
    handle=dlopen(LIB_CACULATE_PATH,RTLD_LAZY);

    LOGD("cac_func: %s","handle");
    if (!handle) {
        LOGD("cac_func2: %s","EXIT_FAILURE");
        exit(EXIT_FAILURE);
    }
    //清除之前存在的错误
    dlerror();
    //获取一个函数
    LOGD("cac_func2: %s","get_status");
    *(void **) (&cac_func) = dlsym(handle, "get_status");
   
    if ((error = dlerror()) != NULL)  {
        LOGD("cac_func: %s","error");
        exit(EXIT_FAILURE);
    }
   //调用这个函数
    r =  (*cac_func)();

    LOGD("cac_func: %d\n", r);
    //关闭动态链接库
    dlclose(handle);
    return r;

}

然后用System.loadLibrary加载自己的这个库,写个native调用就行了。

 static {
        System.loadLibrary("native-lib");
 }
 public native int intFromJNI();

下面来说说遇到的坑

在调用时出现了这个错误,网上有大神解决了,主要是因为没有权限。

E/linker: library "/system/vendor/lib/libkphproxy.so" ("/vendor/lib/libkphproxy.so") needed or dlopened by "/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/lib/arm/libnative-lib.so" is not accessible for the namespace: [name="classloader-namespace", ld_library_paths="", default_library_paths="/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/lib/arm:/data/app/com.flycom.jnitest-mKVoy6YOwxW_DNa_RgRhMQ==/base.apk!/lib/armeabi-v7a", permitted_paths="/data:/mnt/expand:/data/data/com.flycom.jnitest"]

在framework/vendor/etc目录下的public.libraries.txt,从这个文件的名字就可以大概知道其中的意义了如果没有的话可以新建一个,把你调用的so库名字加进去,注意必须是全名,例如我的libtest.so。在system/etc文件夹下面也有这个文件,当然是针对system/lib的so库,如果你想访问system/lib的so库请在这里添加。

接下来说下在framework层的添加,例如我想加在com_android_server_SystemServer.cpp

jni的调用是一样的,

static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
    using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
    using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
    using ::android::frameworks::sensorservice::V1_0::ISensorManager;
    using ::android::frameworks::sensorservice::V1_0::implementation::SensorManager;
    using ::android::hardware::configureRpcThreadpool;

    status_t err;

    configureRpcThreadpool(5, false /* callerWillJoin */);

    JavaVM *vm;
    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Cannot get Java VM");

    sp<ISensorManager> sensorService = new SensorManager(vm);
    err = sensorService->registerAsService();
    ALOGE_IF(err != OK, "Cannot register %s: %d", ISensorManager::descriptor, err);

    sp<ISchedulingPolicyService> schedulingService = new SchedulingPolicyService();
    err = schedulingService->registerAsService();
    ALOGE_IF(err != OK, "Cannot register %s: %d", ISchedulingPolicyService::descriptor, err);
}
//这里的名字随便取
static jint android_server_SystemServer_verifyStatus(JNIEnv*, jobject /* clazz */) {
	LOGD("cac_func2: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    
  LOGD("cac_func: %s","Java_com_flycom_jnitest_MainActivity_intFromJNI");
    void *handle;
    char *error;
    int r;
    CAC_FUNC cac_func = NULL;
    handle=dlopen(LIB_CACULATE_PATH,RTLD_LAZY);

    LOGD("cac_func: %s","handle");
    if (!handle) {
        LOGD("cac_func2: %s","EXIT_FAILURE");
        exit(EXIT_FAILURE);
    }
    //清除之前存在的错误
    dlerror();
    //获取一个函数
    LOGD("cac_func2: %s","get_status");
    *(void **) (&cac_func) = dlsym(handle, "get_status");
   
    if ((error = dlerror()) != NULL)  {
        LOGD("cac_func: %s","error");
        exit(EXIT_FAILURE);
    }
   //调用这个函数
    r =  (*cac_func)();

    LOGD("cac_func: %d\n", r);
    //关闭动态链接库
    dlclose(handle);
    return r;
}

这里遇到的坑就比较多了,注意函数一定要注册,否则找不到方法,第一个参数跟第三个参数好理解,关键的第二个参数"()I",这个括号里面是传入的参数,我的方法没有返回值,所以是空的,后面的“I”代表返回类型是int,这个可以在网上找到。

/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    /* name, signature, funcPtr */
    { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
    { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
	{ "verifyStatus", "()I", (void*) android_server_SystemServer_verifyStatus },
};

在这里调用是不需要在public.libraries.txt给权限的。然后有一个更奇葩的问题,就是我在framewoke层调用同样的函数,返回结果竟然跟app的结果不一样,这个问题困扰了我一天。最后问了提供so库的商家,才发现是权限的问题发火

在app中调用已经加了权限,而在system_server中没加权限,在device/mediatek/sepolicy/bsp/non_plat/system_server.te文件中加入访问的权限

allow system_server tkcore_admin_device:chr_file  { ioctl read write open };
最后终于调用成功。。。。


  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt for Android中,调用第三方可以通过以下步骤实现: 1. 将第三方的文件(通常是一个文件或者是一个.so文件)添加到Qt项目的目录中,可以放在项目的根目录下或者是一个单独的文件夹中。 2. 在项目的.pro文件中添加文件的路径和依赖项。可以通过使用LIBS参数来指定文件路径,例如:LIBS += -L/path/to/library -lmylibrary。另外,如果文件有依赖文件,可以使用DEPLOYMENT参数指定依赖文件的路径,例如:DEPLOYMENT += path/to/dependency。 3. 在Qt代码中引用第三方。使用#include指令将的头文件引入到Qt代码中,例如:#include <mylibrary.h>。然后就可以使用中提供的函数和类了。 需要注意的是,调用第三方时,需要确保文件的兼容性和正确性。特别是在使用跨平台的时,需要检查是否支持Android平台,并且要确保所使用的文件与Qt版本和Android NDK版本兼容。 此外,Qt for Android还提供了JNI(Java Native Interface)的支持,可以通过JNI来调用Java代码和使用Java。这种方式可以更深入地与Android系统交互,并且能够访问更多的Android API和功能。 总而言之,Qt for Android调用第三方需要将文件添加到项目中,并在项目配置文件中设置路径和依赖项。然后使用#include指令引入的头文件,并通过提供的函数和类来使用第三方的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值