Android12 开发JNI流程

注:默许你以及装置好NDK开发的所有环境,包括cmake插件

一.Android studio主动创立demo剖析

1.新建一个Project,挑选Native C++项目类创立;

2.项目会默许创立出3个要害文件,cpp目录native-lib.cppCMakeList.txt MainActivity.

Android studio定义so库并生成aar给第三方调用

3.剖析一下这三个类的要害代码,理解了再进行仿照

1.MainActivity.java

package com.android.projectforblog;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.android.projectforblog.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
    // Used to load the 'projectforblog' library on application startup.
    static {
        System.loadLibrary("projectforblog");
    }
    private ActivityMainBinding binding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        // Example of a call to a native method
        TextView tv = binding.sampleText;
        tv.setText(stringFromJNI());
    }
    /**
     * A native method that is implemented by the 'projectforblog' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}
  • System.loadLibrary("projectforblog") 加载so库,这个库是项目build“app->build->intermediates->cmake”目录下生成的,在CMakeLists.txt中声明界说的名字

  • stringFromJNI是本地办法的声明,java代码能够直接调用它,它调用projectforblog库中对应的头文件声明,头文件声明办法再调用对应的c文件;假如c库中没有对应的.h头文件,则会直接调用对应的.c/.cpp文件


2.native-lib.cpp

#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_android_projectforblog_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
  • extern “C” :一方面externC/C++言语中表明函数和全局变量作用规模(可见性)的要害字,该要害字告诉编译器,其声明的函数和变量能够在本模块或其它模块中运用;另一方面,这是一个C++言语的特殊语法,用于指定函数的称号不需求进行C++的命名规则修饰。被extern "C"修饰的变量和函数是依照C言语方法编译和衔接的

  • JNIEXPORT 是jni.h中的一个被界说的宏,用于指定函数的可见性和调用约好。 它会根据操作系统的不同,打开为不同的要害字。例如,在 Windows 平台上为__declspec(dllexport) 要害字,用于指定函数的导出;在 Linux 平台上,它会打开为 attribute((visibility("default"))) 要害字,用于指定函数的可见性

  • JNICALL 是jni.h中的一个被界说的宏。意思为JNI调用某办法

  • Java_com_android_projectforblog_MainActivity_stringFromJNI指JNICALL调用的办法名,也是java中的native办法名。命名规则:"Java"+包名+类名+办法名


3.CMakeLists.txt

# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.22.1)
# Declares and names the project.
project("projectforblog")
add_library( # Sets the name of the library.
        projectforblog
        # 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.
        projectforblog
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

CMakeLists.txt 是一个 CMake 工程的装备文件,用于描绘项目的编译、链接和装置等相关信息。在 CMakeLists.txt 文件中,能够运用一些参数来装备工程的各个方面,以下是一些常用的参数阐明:

  • CMAKE_MINIMUM_REQUIRED:指定 CMake 的最低版别要求,一般填你下载cmake的版别名字

  • PROJECT:指定项目的称号。

  • INCLUDE_DIRECTORIES:指定头文件查找途径,例如 include_directories(“${CMAKE_CURRENT_SOURCE_DIR}/include”)

    Android studio定义so库并生成aar给第三方调用
  • ADD_LIBRARY:能够用来增加 normal libraryimported library 两种类型的库文件。 Normal library 是指在当前 CMake 项目中编译生成的库文件,能够运用 add_library 指令来创立。它能够是静态库(.a 或 .lib)或动态库(.so 或 .dll)。静态库是在编译时链接到方针程序中的库,而动态库是在运行时动态加载的库。

    假定咱们有一个名为 mylib 的 C++ 库,包括两个源文件 foo.cpp 和 bar.cpp,需求编译成静态库和动态库。能够运用以下 CMakeLists.txt 文件来创立 normal library,CMakeLists.txt

    # SHARED意味着编译生成动态库
    add_library(mylib_static STATIC foo.cpp bar.cpp)
    # SHARED意味着编译生成动态库
    add_library(mylib_shared SHARED foo.cpp bar.cpp)
    
    Android studio定义so库并生成aar给第三方调用
  • Imported library 是指在当前 CMake 项目外部编译生成的库文件,能够运用 add_library 指令的 IMPORTED 参数来创立。在运用时,需求通过 target_link_libraries 指令将其链接到方针文件中。

    假定咱们有一个名为 libcurl 的第三方库,已经编译成了 libcurl.a 静态库和 libcurl.so 动态库。现在咱们需求在咱们的 C++ 项目中链接这个库。能够运用以下 CMakeLists.txt 文件来创立 imported library:

    # CMakeLists.txt
    add_library(curl STATIC IMPORTED)
    set_target_properties(
        curl 
        PROPERTIES IMPORTED_LOCATION 
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libcurl.a
    )
    target_link_libraries(curl)
    
    Android studio定义so库并生成aar给第三方调用

注:上面只写了静态库.a的规则写法,动态库的直接改成.so就好了,运用 set_target_properties 指令设置其 IMPORTED_LOCATION 特点为 libcurl.a 的途径

  • TARGET_LINK_LIBRARIES:指定链接的库文件。

  • SET:设置变量的值,例如#set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)

  • LINK_DIRECTORIES:指定库文件查找途径。

  • INSTALL:指定装置规则。

  • FIND_PACKAGE:查找外部库文件的位置和版别信息。

  • MESSAGE:输出音讯。

  • ADD_EXECUTABLE:增加可执行文件。 以上是一些常用的 CMakeLists.txt 参数阐明。在实际运用中,能够根据项目的需求来挑选和装备相应的参数。


4.build之后生成的so库,理论上这个so库也是能够供给给其他应用进行调用

Android studio定义so库并生成aar给第三方调用

二.总结

1.上面的demo剖析展现了怎么通过Android Studio自己创立一个so库,demo中创立的官方默许demo在build之后就能够看到有so库,咱们
进行二次修改,引入其他c文件/.h文件糅合后重新build就能够得到咱们想要的so库。
2.怎么引用其他第三方的so库;
3.怎么引用第三方供给的c代码和.h文件,这个其实便是把so的源码给咱们自己交融,差别仅仅在于add_library{}时要设置不一样的参数。