NDK--CMakeLists配置第三方so库

2021-01-10 17:20:52

参考地址 NDK--CMakeLists配置第三方so库

当我们创建一个NDK工程时,会自动创建一个CMakeLists.txt的文件,在AS中c++的编译器是使用LLVM,规则为cmake,今天来学习下cmake的基本套路
首先,我创建了两个NDK工程,第一个工程为lib,为第二个工程提供so库

我们修改cpp文件,新增一个求和方法
#include <jni.h>#include <string>int sum(int a, int b) {
    return a + b;}
由于我们这个工程要提供so库,所以在CMakeLists中改下编译出来的so库名称:test-lib

编译下,找到生成的so库文件夹,复制到第二个工程

如果想要指定平台可以在gradle中配置:

在defaultConfig目录里面 ndk { abiFilters "armeabi","x86" }

复制到libs下

AS中默认存放so库的目录需要在src/main中创建一个jniLibs的文件夹,也可以通过gradle配置,指定目录

在app.gralde中的android目录下 sourceSets.main { jniLibs.srcDirs = ['libs'] jni.srcDirs = [] }

这边使用的是libs目录作为so库的存放目录,接下来我们来配置第二个工程的CMakeLists
1.首先,为了以后方便使用,我们为so库的路径设置一个别名
#设置so库路径set(my_lib_path ${CMAKE_SOURCE_DIR}/../../../libs)
${CMAKE_SOURCE_DIR}为CMakeLists文件的当前路径,以后我们就可以直接使用my_lib_path了
2.第二步,我们配置导入的so库
#将第三方库作为动态库引用add_library(test-lib
        SHARED
        IMPORTED)
这边我们只需要修改库的名称(test-lib)就可以了,其他的复制粘贴
3.第三步,配置第三方库的路径,这边就要用到我们开始定义的my_lib_path别名了
#指定第三方库的绝对路径set_target_properties(test-lib
        PROPERTIES IMPORTED_LOCATION
        ${my_lib_path}/${ANDROID_ABI}/libtest-lib.so)
同样的,我们只需要关注上一步定义好的名称和连接的so库的绝对路径,另外,关于${ANDROID_ABI}的说明:系统会自动根据apk安装时的平台,自动将相应平台下的so库导入
target_link_libraries( # Specifies the target library.
        native-lib
        test-lib
        
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
完整CMakeLists:
cmake_minimum_required(VERSION 3.4.1)#设置so库路径set(my_lib_path ${CMAKE_SOURCE_DIR}/libs)#将第三方库作为动态库引用add_library(test-lib
        SHARED
        IMPORTED)#指定第三方库的绝对路径set_target_properties(test-lib
        PROPERTIES IMPORTED_LOCATION
        ${my_lib_path}/${ANDROID_ABI}/libtest-lib.so)add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp)find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)target_link_libraries( # Specifies the target library.
        native-lib
        test-lib
        
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

接下来,我们开始使用导入的库中的方法:求和方法

1.首先,创建一个.h文件,声明导入方库的方法:

//// Created by aruba on 2020/4/13.//#ifndef NDKAPPLICATION_TEST_LIB_H
#define NDKAPPLICATION_TEST_LIB_H//申明外部 函数 外部属性extern int sum(int a, int b);#endif //NDKAPPLICATION_TEST_LIB_H
2.在需要使用的cpp中引入头文件,并调用
#include <jni.h>#include <string>#include <android/log.h>#include <assert.h>#include "test-lib.h"#define TAG "C++"#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))extern "C"JNIEXPORT jstring JNICALL native_stringFromJNI(JNIEnv *env, jclass type) {

    return env->NewStringUTF("C++");}JNIEXPORT jint JNICALL native_sum(JNIEnv *env, jclass type, jint a, jint b) {

    return sum(a, b);}static const JNINativeMethod gMethods[] = {
        {
                "stringFromJNI", "()Ljava/lang/String;", (void *) native_stringFromJNI        },
        {
                "sum", "(II)I", (void *) native_sum        }};static int registerNatives(JNIEnv *env) {
    LOGI("registerNatives begin");
    jclass clazz;
    //找到java的类
    clazz = env->FindClass("com/aruba/ndkapplication/JniUtils");

    if (clazz == NULL) {
        LOGI("clazz is null");
        return JNI_FALSE;
    }

    if (env->RegisterNatives(clazz, gMethods, NELEM(gMethods)) < 0) {
        LOGI("RegisterNatives error");
        return JNI_FALSE;
    }

    return JNI_TRUE;}JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    LOGI("jni_OnLoad begin");

    JNIEnv *env = NULL;

    if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
        LOGI("ERROR: GetEnv failed\n");
        return -1;
    }

    assert(env != NULL);

    registerNatives(env);

    return JNI_VERSION_1_4;}
在java中调用
package com.aruba.ndkapplication;public class JniUtils {
    static {
        System.loadLibrary("native-lib");
    }
    
    public static native String stringFromJNI();

    public static native int sum(int a, int b);}
public class MainActivity extends AppCompatActivity {

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(JniUtils.sum(10, 20) + "");
    }}


  • 2019-12-04 10:46:26

    nuxt.js项目中全局捕获异常并生成错误日志全过程

     需求:客户在使用过程中页面报错时,可以生成错误记录传回服务器,以便改进。   步骤:     一.全局捕获异常,     二.发送到服务端,     三.生成错误日志。   一.全局捕获异常 如图,vue提供了errorHandle这个方法来处理全局异常,更多详细内容参见官网。

  • 2019-12-04 10:47:59

    nuxt.js项目中全局捕获异常并生成错误日志全过程

     需求:客户在使用过程中页面报错时,可以生成错误记录传回服务器,以便改进。   步骤:     一.全局捕获异常,     二.发送到服务端,     三.生成错误日志。   一.全局捕获异常 如图,vue提供了errorHandle这个方法来处理全局异常,更多详细内容参见官网。

  • 2019-12-04 10:48:18

    vue 项目资源文件 static 和 assets 不说区别直接使用?

    assets中资源会webpack构建压缩到你代码中,而static文件直接引用。 static 中长存放类包、插件等第三方的文件,assets里放属资源文件比如自己资源图片、css文件、js文件。 引入资源的方式static文件夹可以使用~/static/方式引入, assets文件夹可以使用 ~@/assets 方式引入

  • 2019-12-05 17:01:36

    Vue 结合 Axios 接口超时统一处理

    当网路慢的时候。又或者公司服务器不在内地的时候,接口数据请求不回来超时报错的情况相信大家肯定遇到过的,这里我把我公司项目请求超时的处理方法分享下,希望看过后有帮助。

  • 2019-12-05 17:13:40

    JS模板工具lodash.template的简单用法

    lodash是从underscore分支的一个项目,之前我写了一篇JS模板工具underscore.template的简单用法,lodash跟underscore很相似,这也简单介绍一下lodash的template方法。 先把underscore的文章中用过的代码贴过来,把underscore的js文件换成lodash的js,其他一字不改,然后我们试试:

  • 2019-12-06 10:47:29

    date-fns日期工具的使用方法详解

    isToday() 判断传入日期是否为今天 isYesterday() 判断传入日期是否为昨天 isTomorrow() 判断传入日期是否为 format() 日期格式化 addDays() 获得当前日期之后的日期 addHours() 获得当前时间n小时之后的时间点 addMinutes() 获得当前时间n分钟之后的时间 addMonths() 获得当前月之后n个月的月份 subDays() 获得当前时间之前n天的时间 subHours() 获得当前时间之前n小时的时间 subMinutes() 获得当前时间之前n分钟的时间 subMonths() 获得当前时间之前n个月的时间 differenceInYears() 获得两个时间相差的年份 differenceInWeeks() 获得两个时间相差的周数 differenceInDays() 获得两个时间相差的天数 differenceInHours() 获得两个时间相差的小时数 differenceInMinutes() 获得两个时间相差的分钟数