cmake编译NDK初体验

 本文用一个demo验证Android Studio如何编译生成一个C++动态库文件(so文件) 给 Java应用层使用。然后这个so库内部又如何调用 一个预有so库中的 C语言函数。


1. 新建一个NDK工程


 1.1  新建一个android studio Native C++工程

在main/cpp目录下默认有一个native-lib.cpp,还有一个CMakeList.txt文件(编译脚本),其中

native-lib.cpp实现了从JNI里返回一个C++字符串,具体代码如下:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring
Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv* env,jobject) {
    std::string hello = "Hello from cppmain";
    return env->NewStringUTF(hello.c_str());
}

其中env->NewStringUTF(hello.c_str());将C++字符串hello转换成了jstring类型(JNI可以传递给JAVA的字符串类型)

 1.2 配置build.gradle

我们把CMakeList.txt移动到app moudle的根目录下,即与app模块下的build.gradle放在同一目录下,在以下脚本3中设置cmake中的path(CMakeList.txt编译脚本的存放路径),path值直接就是CMakeList.txt。


 android--defaultcofig--下添加如下脚本
 
 脚本1:

   externalNativeBuild {
            cmake {
                abiFilters 'armeabi-v7a'
            }
   }
 注解:表示只编译armeabi-v7a CPU架构下已经存放的的so库。
 
 脚本2:
 
   ndk{
       abiFilters 'armeabi-v7a'
   }
   注解:表示只生成armeabi-v7a CPU架构下的so库,并打包到APP里。
 同时,添加这个脚本是为了解决这个问题:用android studio直接运行项目会报错,找不到最终生成的libnative-lib.so,只有build生成apk,然后传到手机上运行才不报错。
 添加了这个ndk脚本后就一切正常了。具体原因还需进一步研究下。
 
 脚本3(在android配置下添加):
 
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
            version "3.10.2"
        }
    }
注解:其中path是CMakeLists编译脚本文件的路径,以 path "CMakeLists.txt"为例,表示CMakeLists.txt文件在android studio工程的主app模块根目录下,与app模块的build.gradle文件在同一目录下。version "3.10.2"使用的CMake编译工具的版本。
    


2. 在native-lib.cpp中的stringFromJNI数里调用另一个so库libTest.so中的test()方法


2.1 修改native.cpp的stringFromJNI函数:调用test()

#include <jni.h>
#include <string>
#include <android/log.h>

extern "C"{
   extern int test();
}

extern "C" JNIEXPORT jstring
Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv* env,jobject) {
    std::string hello = "Hello from cppmain";
    __android_log_print(ANDROID_LOG_ERROR,"jni","libtest.so 里面的 test 方法:%d",test());
    return env->NewStringUTF(hello.c_str());
}

(1)相比之前加了这样代码:  __android_log_print(ANDROID_LOG_ERROR,"jni","libTest.so 里面的 test 方法:%d",test()); 折行代码用于打印日志,输出test()方法返回的int值。

(2)要调用test()方法,首先得用extern声明外部原型,因为test()函数的实现是在其它C语言文件里。加了一个extern "C"是因为test()是一个C语言程序,要在C++里调用C代码必须得声明关键字extern "C".


2.2 拷贝libTest.so库到我们新建的NDK项目中

将libTest.so复制到src/main/jniLibs/armeabi-v7a目录下,我们在此只编译armeabi-v7a CPU架构的so库


2.3 修改CMakeList.txt编译脚本,引入第三方库libTest.so,并链接到本地要生成的libnative-lib.so库

 脚本如下:

cmake_minimum_required(VERSION 3.10.2) 

#声明项目名  
project("ndktest")       

#将.C文件与C++(就是cpp)文件的查找路径赋值给一个变量source,多个文件路径用空格隔开。
file(GLOB source src/main/cpp/*.c src/main/cpp/*.cpp src/main/cpp/a/*.cpp )  

#将C/C++源码编译,生成一个本地so动态库,库名是native-lib,源码路径就是上面那个source变量的值,${source}取值,SHARED表示将cmake要编译生成的动态库(so文件)
add_library( # Sets the name of the library.
        native-lib
        SHARED
        ${source})   # 在此项目中也可直接在此填写  src/main/cpp/native-lib.cpp

 # 将下面的log库的路径赋值给log-lib, 用于target_link_libraries中链接到将要生成的本地native- lib库

find_library( 
        log-lib       
        log      # log库的路径,因为log为系统库,所以只需要名字,cmake就知道其路径了
        )
        
        
#配置第三方Test.so库的链接路径,我们的Test.so库放在了armeabi-v7a下,2.1中已经提到。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")


#将Test库,log库与本地将要生成的动态库链接在一起,这样native-lib库里的stringFromJNI函数就可以调用test()函数与log库中的__android_log_print()函数了。
target_link_libraries( # Specifies the target library.
        native-lib
        Test

        # Links the target library to the log library included in the NDK.
        ${log-lib}

        )
        
        
3. 在java层调用本地库native-lib.so中的JNI函数stringFromJNI

 public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
    public native String stringFromJNI();
}

  

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冉航--小虾米

希望得到您的鼓励和交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值