NDK(23) 使用CMake 构建 c/c++代码库

1.官网

  https://developer.android.com/studio/projects/add-native-code.html

  https://developer.android.google.cn/ndk/guides/cmake

  https://developer.android.google.cn/studio/projects/configure-cmake

2.android studio 安装相关工具

  1. 在打开的项目中,从菜单栏选择 Tools > Android > SDK Manager
  2. 点击 SDK Tools 标签。
  3. 选中 LLDBCMake 和 NDK 旁的复选框,如图所示.

    

3.新建支持c/c++的项目

  1. 在android studio 3.4.1 新建向导里选 Native C++ 模板.

2.选择想要使用的c++标准,如C++14.

3.最后 生成的项目如下:

其中:

    • CMakeLists.txt 是cmake构建工程要用的项目配置文件.
    • native-lib.cpp是源文件

4.编辑代码,使用本地程序....

4.在现有项目中添加 c/c++库

4.1 创建 jni目录

  项目名(或者File) ---> 右键 --->  New ---> Folder ---> JNI Folder

4.2 创建 CMakeLists.txt文件 

  在上一步上创建的jni目录(当前版本目录名是cpp) 右键 ---> New ---> File 输入CMakeLists.txt

4.3 配置CMakeLists.txt 文件

 1 # Sets the minimum version of CMake required to build your native library.
 2 # This ensures that a certain set of CMake features is available to
 3 # your build.
 4 
 5 cmake_minimum_required(VERSION 3.10.2)
 6 
 7 #set(CMAKE_SYSTEM_NAME Android)
 8 #set(CMAKE_SYSTEM_VERSION 21) # API level
 9 #set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
10 #set(CMAKE_ANDROID_NDK /home/Jei/android/sdk/ndk/22.1.7171670)
11 #set(CMAKE_ANDROID_STL_TYPE gnustl_static)
12 
13 add_library             (nal SHARED test.c native.cpp)
14 
15 include_directories     (include/crypto)
16 add_library             (crypto STATIC IMPORTED)
17 set_target_properties   (crypto PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libcrypto.a)
18 
19 include_directories     (include/openssl)
20 add_library             (openssl STATIC IMPORTED)
21 set_target_properties   (openssl PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libssl.a)
22 
23 include_directories     (include/curl)
24 add_library             (curl STATIC IMPORTED)
25 set_target_properties   (curl PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libcurl.a)
26 
27 find_library            (log-lib log)
28 
29 target_link_libraries   (nal crypto openssl curl ${log-lib} )

    cmake命令官网 : https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html 

set

设置宏

add_library()

向您的 CMake 构建脚本添加源文件或库

1 add_library( # Specifies the name of the library.
2              native-lib
3 
4              # Sets the library as a shared library.
5              SHARED
6 
7              # Provides a relative path to your source file(s).
8              src/main/cpp/native-lib.cpp )
 

include_directories

指定头文件的路径

1 add_library(...)
2 
3 # Specifies a path to native header files.
4 include_directories(src/main/cpp/include/)
find_library()

添加引用的NDK 库

1 find_library( # Defines the name of the path variable that stores the
2               # location of the NDK library.
3               log-lib
4 
5               # Specifies the name of the NDK library that
6               # CMake needs to locate.
7               log )
target_link_libraries()

链接多个库

1 target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
 add_library()

将其它源代码编译到本地库中.

1 add_library( app-glue
2              STATIC
3              ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )
4 
5 # You need to link static libraries against your shared native library.
6 target_link_libraries( native-lib app-glue ${log-lib} )
 

set_target_properties

和 IMPORTED

IMPORTED不是个函数,只是add_library的参数,添加其他预构建的本地库 

然后,您需要使用 set_target_properties() 命令指定库的路径.

4.4 关联Gradle与 CMakeLists.txt  

  右键点击您想要关联的模块(例如 app 模块),并从菜单中选择 Link C++ Project with Gradle。关联到之前创建的CMakeLists.txt,点OK.

  

4.5 完成本地的c/c++代码工作

MainActivity.java 

 1 public class MainActivity extends AppCompatActivity {
 2 
 3     // Used to load the 'native-lib' library on application startup.
 4     static {
 5         System.loadLibrary("native-lib");
 6     }
 7 
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12 
13         // Example of a call to a native method
14         TextView tv = findViewById(R.id.sample_text);
15         tv.setText(stringFromJNI());
16     }
17 
18     /**
19      * A native method that is implemented by the 'native-lib' native library,
20      * which is packaged with this application.
21      */
22     public native String stringFromJNI();
23 }

native-lib.cpp

 1 #include <jni.h>
 2 #include <string>
 3 
 4 extern "C" JNIEXPORT jstring JNICALL
 5 Java_com_example_cpp14_MainActivity_stringFromJNI(
 6         JNIEnv* env,
 7         jobject /* this */) {
 8     std::string hello = "Hello from C++";
 9     return env->NewStringUTF(hello.c_str());
10 }

kotlin版本:

 1 class NotifyService : Service() {
 2     external fun native()
 3     init{
 4         System.loadLibrary("alive-lib")
 5     }
 6     fun cantStartRemoteService(){
 7         Logger.e("NotifyService","cantStartRemoteService")
 8         //...    
 9     }
10     ...
11 }

native层:

 1 #include <jni.h>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cstdio>
 5 #include <android/log.h>
 6 
 7 
 8 #define LOGE(TAG,...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
 9 
10 extern "C"
11 JNIEXPORT void JNICALL
12 Java_com_example_sjjg_alive_NotifyService_native(JNIEnv *env, jobject thiz) {
13     printf("hello native");
14     LOGE("alive-lib","NotifyService_native");
15     jclass clz = env->GetObjectClass(thiz);
16 
17     /*fun cantStartRemoteService()*/
18     jmethodID method = env->GetMethodID(clz,"cantStartRemoteService","()V");
19     env->CallVoidMethod(thiz,method);
20 }

 

5.在 Gradle 中使用 CMake 变量

  https://developer.android.com/ndk/guides/cmake.html#variables

 1 android {
 2   ...
 3   defaultConfig {
 4     ...
 5     // This block is different from the one you use to link Gradle
 6     // to your CMake or ndk-build script.
 7     externalNativeBuild {
 8 
 9       // For ndk-build, instead use ndkBuild {}
10       cmake {
11 
12         // Passes optional arguments to CMake.
13         arguments "-DANDROID_TOOLCHAIN=clang","--D__ANDROID_API__=30","-DANDROID_STL=c++_static"
14 
15         // Sets optional flags for the C compiler.
16         cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
17 
18         // Sets a flag to enable format macro constants for the C++ compiler.
19         cppFlags "-fexceptions", "-frtti","-std=c++11"
20       }
21     }
22   }
23 
24   buildTypes {...}
25 
26     ...
27 }

6.指定本地库的cpu架构

  默认情况下,Gradle 会针对 NDK 支持的 ABI 将您的原生库构建到单独的 .so 文件中,并将其全部打包到您的 APK 中。如果您希望 Gradle 仅构建和打包原生库的特定 ABI 配置,您可以在模块级 build.gradle 文件中使用 ndk.abiFilters 标志指定这些配置.

 1 apply plugin: 'com.android.application'
 2 
 3 android {
 4     compileSdkVersion 28
 5     defaultConfig {
 6         applicationId "com.example.tocpp5"
 7         minSdkVersion 15
 8         targetSdkVersion 28
 9         versionCode 1
10         versionName "1.0"
11         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12         // This block is different from the one you use to link Gradle
13         // to your CMake or ndk-build script.
14         externalNativeBuild {
15             // For ndk-build, instead use ndkBuild {}
16             cmake {
17                 // Passes optional arguments to CMake.
18                 arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
19 
20                 // Sets optional flags for the C compiler.
21                 cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
22 
23                 // Sets a flag to enable format macro constants for the C++ compiler.
24                 cppFlags "-D__STDC_FORMAT_MACROS"
25 
26                 abiFilters 'armeabi-v7a','arm64-v8a'
27 
28             }
29         }
30         ndk {
31             // Specifies the ABI configurations of your native
32             // libraries Gradle should build and package with your APK.
33             abiFilters 'x86', 'x86_64', 'armeabi-v7a','arm64-v8a'
34         }
35     }
36     buildTypes {
37         release {
38             minifyEnabled false
39             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
40         }
41     }
42     externalNativeBuild {
43         cmake {
44             path file('src/main/jni/CMakeLists.txt')
45         }
46     }
47 }
48 
49 dependencies {
50     implementation fileTree(dir: 'libs', include: ['*.jar'])
51     implementation 'androidx.appcompat:appcompat:1.0.2'
52     implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
53     testImplementation 'junit:junit:4.12'
54     androidTestImplementation 'androidx.test:runner:1.2.0'
55     androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
56 }

  在 defaultConfig.externalNativeBuild.cmake {} 

  或 

  defaultConfig.externalNativeBuild.ndkBuild {} 块

  中配置另一个 abiFilters 标志。Gradle 会构建defaultConfig.ndk中的 ABI 配置,不过仅会打包在 defaultConfig.cmake或者ndkBuild{} 块中指定的配置。

 

   注: 非特殊情况下,只保留  'arm64-v8a'  (64位)和 'armeabi-v7a' (32位) 就够用了。 参考微信的apk。

7.NDK中支持的库

   https://developer.android.google.cn/ndk/guides/stable_apis

 

posted @ 2019-06-30 22:47  f9q  阅读(668)  评论(0编辑  收藏  举报