android studio cmake构建ndk(三)

本文详细介绍如何在Android Studio 2.2版本中利用CMake进行NDK开发,包括配置环境、创建项目、编写C/C++代码及调试技巧等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:
NDK开发 从入门到放弃(七:Android Studio 2.2 CMAKE 高效NDK开发)

一、下载相关工具:

setting –> android sdk –> SDK tools –>
选中cmake、LLDB、ndk,然后apply点击OK、

这里写图片描述

(1)The Android Native Development Kit (NDK) : 让你能在 Android 上面使用 C 和 C++ 代码 的工具集。
(2)CMake 外部构建工具。如果你准备只使用 ndk-build 的话,可以不使用它。
(3)LLDB : 是一个高效的c/c++的调试器,Android Studio中也可以使用LLDB调试NDK程序。

二、新建项目

1、勾选“支持c++环境支持”,next

Android Studio升级到2.2版本之后,在创建新的project时,界面上多了一个Include C++ Support的选项。勾选它之后将会创建一个默认的C++与JAVA混编的Demo程序。

这里写图片描述

2、默认C++ Standard,
勾选Exceptions Support和Runtime Type Information Support,
finish。

这里写图片描述

C++ Standard
选择C++库,指定编译库的环境,其中
Toolchain Default使用的是默认的CMake环境;
C++ 11也就是C++环境,支持C++11特性
两种环境都可以编库

Exceptions Support (-fexceptions):
如果你想使用有关 C++ 异常处理的支持,就勾选它。勾选之后,Android Studio 会在 module 层的 build.gradle 文件中的 cppFlags 中添加 -fexcetions 标志。

Runtime Type Information Support (-frtti):
如果你想支持 RTTI,那么就勾选它。勾选之后,Android Studio 会在 module 层的 build.gradle 文件中的 cppFlags 中添加 -frtti 标志。

3、新建项目后发现比一般项目多了一些内容:

这里写图片描述

(a). externalNativeBuild —> cmake编译好的文件, 显示支持的各种硬件等信息。系统生成。

(b). cpp —> 存放C/C++代码文件,native-lib.cpp文件是该Demo中自带的,可更改。需要自己编写。

(c). CMakeLists.txt —> CMake脚本配置的文件。需要自己配置编写。

CMakeLists.txt的解释:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

# 设置在编译本地库时我们需要的最小的cmake版本,AndroidStudio自动生成,我们几乎不需要自己管。
cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

#配置so库信息(为当前脚本文件添加库)
add_library( # Sets the name of the library.
             # 设置编译生成的本地库的名字为native-lib,
             # 自定义库名,System.loadLibrary调用时可用。
             native-lib

             # Sets the library as a shared library.
             # 表示编译生成的是动态链接库
             SHARED

             # Provides a relative path to your source file(s).
             # 表示参与编译的文件的路径,这里面可以写多个文件的路径。
             src/main/cpp/native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

# 用来添加一些我们在编译我们的本地库的时候需要依赖的一些库,由于cmake已经知道系统库的路径,
# 所以我们这里只是指定使用log库,然后给log库起别名为log-lib便于我们后面引用,
# 此处的log库是我们后面调试时需要用来打log日志的库,是NDK为我们提供的。
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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

# 关联我们自己的库和一些第三方库或者系统库,这里把我们把自己的库native-lib库和log库关联起来。
target_link_libraries( # Specifies the target library.
                       native-lib

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

注意:两个library(add_library和target_link_libraries)的名字(需一致)以及一个cpp文件的路径,彼此需要对应一致,当我们自己定义library以及自己创建cpp文件时需要对应修改。

这里写图片描述

其中,add_library方法和target_link_libraries方法一一对应,当有多个库,多个C/C++文件时,可写多组add_library方法和target_link_libraries方法。

app module里面多了两段话:

这里写图片描述

mainactivity的内容:

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

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

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

native-lib.cpp中内容:


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

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

新建完成后即可运行ndk的调用demo。

CMake方式的NDK开发步骤:

1、新建cpp目录,写好C/C++代码。
2、创建且配置CMakeLists.txt文件。
3、build.gradle文件中根据情况进行配置,CMakeLists.txt文件的路径必须配置。
4、java代码中即可调用C/C++代码,运行程序。
5、project的build.gradle文件中,gradle版本不能低于2.2,否则会报错。

mainactivity中新建native方法:

public native String stringFromJNI2();

alt+enter:

这里写图片描述

新建test1.cpp:将刚才创建的内容拷贝进来,并编写内容:
注意:extern “C”不可少,没有的话一定要添加。

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

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

cmakeLists.txt文件中:

cmake_minimum_required(VERSION 3.4.1)

add_library( native-lib
             SHARED
             src/main/cpp/native-lib.cpp )

add_library( test1
             SHARED
             src/main/cpp/test1.cpp )

find_library(log-lib
              log )

target_link_libraries( native-lib
                       ${log-lib} )

target_link_libraries( test1
                       ${log-lib} )

mainactivity调用库和方法:

    static {
        System.loadLibrary("test1");
    }

    tv.setText(stringFromJNI2());

运行项目即可。

生成的so库位置:

这里写图片描述

CMake的优势

1、可以直接的在C/C++代码中加入断点,进行调试
2、java引用的C/C++中的方法,可以直接ctrl+左键进入
3、对于include的头文件或者库,也可以直接进入
4、不需要配置命令行操作,手动的生成头文件,不需要配置android.useDeprecatedNdk=true属性

报错:

java.lang.UnsatisfiedLinkError: 
No implementation found for java.lang.String com.example.administrator.myndkdemo.MainActivity.stringFromJNI2() 
(tried Java_com_example_administrator_myndkdemo_MainActivity_stringFromJNI2 
and Java_com_example_administrator_myndkdemo_MainActivity_stringFromJNI2__)

解决办法:添加extern “C”

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

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

extern是编程语言中的一种属性,它表征了变量、函数等类型的作用域(可见性)属性,是编程语言中的关键字。
extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。
加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值