欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NDK与JNI开发(2)CMake方式开发

程序员文章站 2022-05-14 19:32:10
...

一:概述

在NDK与JNI开发(1)中我们看了使用ndk_build方式进行ndk的开发, 在 AS 中还有另外一种方式可以使用:即 CMake 方式。

二:CMake方式进行ndk和jni开发

NDK与JNI开发(2)CMake方式开发

AS3.3版本把支持c++的项目独立出来了,在Create New Project页面下拉就能看到了。。选择Native C++

NDK与JNI开发(2)CMake方式开发

选择Toolchain Default,下面两个选项也勾选上

NDK与JNI开发(2)CMake方式开发

目录结构

NDK与JNI开发(2)CMake方式开发

在 app中的build.gradle的defaultConfig{}后面有以下代码

externalNativeBuild {
      cmake {
          cppFlags "-std=c++11"
      }
  }

或者

externalNativeBuild {
      cmake {
          cppFlags ""
      }
  }

CMake 在编译 C/C++ 代码的时候,回根据上面的两种不同设置来使用C++的两种不同标准,C++11 或者默认标准

还有下面代码 指定 CMake的具体路径为当前项目的根路径,名字为 CMakeLists.txt。

externalNativeBuild {
      cmake {
          path "CMakeLists.txt"
      }
  }

除此之外,还可以增加其他配置属性,官网地址 https://cmake.org/documentation/  这里仅给出两个栗子。

栗子1: 制定ABI

ndk{
      moduleName "jnitest"//指定生成so库的名字,注意:也可以在CMakeLists中指定
      ldLibs "log", "z", "m"//添加依赖的Log库
      abiFilters "armeabi", "armeabi-v7a", "x86"指定特定的ABI架构
  }

栗子2: 指定生成so库的位置

//生成so到指定路径下
  sourceSets{
      main{
          jni.srcDirs = []
          jniLibs.srcDirs = ['libs']
      }
  }

 

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最低版本

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.
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../distribution)
#指定so库存存放的位置
set(CPP_DIR src/main/cpp)
#指定源文件的位置


add_library( # Sets the name of the library.
             #设置library的名字,也是加载时的库的名字,生成的so是libnative-lib.so
             native-lib

             # Sets the library as a shared library.
             #设置library是一个共享库
             SHARED

             # Provides a relative path to your source file(s).
             #指定需要编译的源代码的相对路径
            ${CPP_DIR}/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默认情况下包含搜索路径下的系统库文件,仅需要指定NDK的库文件的名字即可。
#CMake在编译时会确认该库文件是否存在。

find_library( # Sets the name of the path variable.
              #指定库文件路径的变量
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              #指定CMake需要加载的NDK库文件名字
              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.
#指定需要链接到自己生成库文件上的库。
#你可以链接多个库文件,如在这个脚本中自己定义的库,预编译的三方库,或者是系统的库文件

target_link_libraries( # Specifies the target library.
                       #指定链接到的目标库文件
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       #链接目标库文件到包含在NDK中的Log库上
                       ${log-lib} )


添加自定义cpp文件或者c文件, 定义MyMath.cpp文件

头文件

#ifndef JNITESTCMAKE_MYMATH_CPP_H
#define JNITESTCMAKE_MYMATH_CPP_H

int add(int numA,int numB);

#endif //JNITESTCMAKE_MYMATH_CPP_H

源文件

#include "MyMath.h"

int add(int numA,int numB) {

    return numA + numB;
}

很简单,就是计算两个数的和,然后需要修改 CMakeLists 文件,将 MyMath.cpp 添加进去(头文件不需要添加)

add_library( # Sets the name of the library.
             #设置library的名字,也是加载时的库的名字,生成的so是libnative-lib.so
             native-lib

             # Sets the library as a shared library.
             #设置library是一个共享库
             SHARED

             # Provides a relative path to your source file(s).
             #指定需要编译的源代码的相对路径
             ${CPP_DIR}/native-lib.cpp ${CPP_DIR}/MyMath.cpp)


说明

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            source1 [source2 ...])

 

  • 第一个参数是 so 库的名字,官方指出名称在工程中是唯一的。
  • STATIC代表静态类型,即编译后为 .a文件;
    SHARED 表示动态共享库,即编译后为 .so文件;
    MODULE 是一个插件,在运行时完成动态加载
  • 第三个参数,是我们要指定的源文件,这里的类型类似于 java 中的可变类型,可以指定多个文件,如又添加 MyMath.cpp,${CPP_DIR},表示取出我们自定义路径变量中值 src/main/cpp

 

完成以上配置后,再设置下布局,添加一个 Button,一个 TextView,cpp 文件中主要完成两个 int 相加工作,通过按钮点击,获取计算结果,并显示在 TextView 中,
native-lib.cpp文件
#include <jni.h>
#include "MyMath.h"

extern "C"
JNIEXPORT jint

JNICALL
Java_com_example_ralf_jnitest_1cmake_MainActivity_resultFromJNI(
        JNIEnv *env,
        jobject /* this */) {

   return add(3,2);
}

 

class MainActivity extends AppCompatActivity{

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

    private native int resultFromJNI();

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

        final TextView addTextView = findViewById(R.id.add_text);
        Button button = findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addTextView.setText("相加结果为:" + resultFromJNI());
            }
        });
    }

}
通过在 CMakeLists文件,我们就可以添加自定义的一些cpp文件,完成想要的功能。比如,一些重要算法的实现,并不像在java层实现,因为很容易被别人反编译,所以需要编译成so库,这样,就大大提高了APK的安全性能!