个人博客

http://www.sxzhongrui.com

前言

记录一下NDK交叉编译以及so库导入到Android工程的简单步骤,以备将来参考。

环境

在Linux和Mac环境下,分别编译并输出so库。

Red Hat Enterprise Linux 8 64位使用GCC编译(也可以使用CLANG,这里使用GCC进行演示)

macOS Big Sur 11.3.1使用CLANG编译(也可以使用GCC,这里使用CLANG进行演示)

下载NDK

这里我们只演示下载NDK17。项目中Mac使用的NDK版本为NDK21

下载NDK

wget https://www.sxzhongrui.com/android/repository/android-ndk-r17c-linux-x86_www.sxzhongrui.com

对于NDK18及之后的NDK版本,建议使用CLANG进行编译。

解压NDK

解压android-ndk-r17c-linux-x86_www.sxzhongrui.com

解压后会得到android-ndk-r17c文件夹

编写头文件和c文件

GCC编译

#include "get.h"

int 获取(){
  返回666;
}
#include "get.h"

int 获取(){
  返回666;
}

CLANG合辑

#包括

int hi();

#include "hi.h"

int 你好(){
  返回888;
}

配置NDK

Linux(使用GCC编译)

编辑Home/User目录中的.bashrc

vim /home/wangyz/.bashrc

添加以下内容

#配置NDK目录
导出 NDK_HOME=/home/wangyz/NDK/android-ndk-r17c
# 将NDK目录添加到PATH
导出路径=$PATH:$NDK_HOME

# 用于 x86 CPU 架构的 gcc
导出 NDK_GCC_x86=$NDK_HOME/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-gcc

# 用于 x86_64 CPU 架构的 gcc
导出 NDK_GCC_x64=$NDK_HOME/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc

#gcc 用于 ARM CPU 架构
导出 NDK_GCC_ARM=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc

#gcc 适用于 ARM64 CPU 架构
导出 NDK_GCC_ARM_64=$NDK_HOME/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc

# x86 CPU架构配置sysroot、isystem,否则找不到头文件
导出 NDK_GCC_CONFIG_x86="--sysroot=$NDK_HOME/platforms/android-21/arch-x86 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/i686-linux-android"

# x86_64 CPU架构 配置sysroot、isystem,否则找不到头文件导出 NDK_GCC_CONFIG_x64="--sysroot=$NDK_HOME/platforms/android-21/arch-x86_64 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/x86_64-linux-android"

# ARM CPU架构 配置sysroot、isystem,否则找不到头文件
导出 NDK_GCC_CONFIG_ARM="--sysroot=$NDK_HOME/platforms/android-21/arch-arm -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/arm-linux-androideabi"

# ARM64 CPU架构配置sysroot、isystem,否则会找不到头文件
导出 NDK_GCC_CONFIG_ARM_64="--sysroot=$NDK_HOME/platforms/android-21/arch-arm64 -isystem $NDK_HOME/sysroot/usr/include -isystem $NDK_HOME/sysroot/usr/include/aarch64-linux-android"

Mac(用CLANG编译)

修改~/.bash_profile

vim ~/.bash_profile

添加以下内容

# NDK 目录
导出 NDK_HOME=/Users/ringle/Library/Android/sdk/ndk/21.1.6352462

# CLANG 目录
导出 CLANG=${NDK_HOME}/toolchains/llvm/prebuilt/-x86_64/bin

# 添加到路径
导出路径=${PATH}:${NDK_HOME}:${CLANG}

编译

这里是ARM64架构的编译所以

海湾合作委员会

$NDK_GCC_ARM_64 $NDK_GCC_CONFIG_ARM_64 -fPIC -shared get.c -o www.sxzhongrui.com

叮当声

aarch64-linux-android21-clang -fPIC -shared hi.c -o www.sxzhongrui.com

导入Android Studio

将其复制到项目中

在app/src/main目录下新建jniLibs目录,然后新建arm64-v8a目录,将编译好的www.sxzhongrui.com和www.sxzhongrui.com复制到该目录下

配置cmake

在app/src/main目录下新建cpp目录,新建CMakeLists.txt,配置如下:


# 有关将 CMake 与 Android Studio 结合使用的更多信息,请阅读
# 文档:https://www.sxzhongrui.com/studio/projects/add-native-code.html

# 设置构建本机库所需的 CMake 最低版本。

cmake_minimum_required(版本3.10.2)

# 声明并命名项目。

项目(“ndk”)

# 包含所有CPP文件
文件(GLOB allCPP *.cpp)

# 创建并命名一个库,将其设置为 STATIC
# 或 SHARED,并提供其源代码的相对路径。# 您可以定义多个库,CMake 会为您构建它们。
# Gradle 会自动将共享库与您的 APK 打包。

add_library( # 设置库的名称。
        本机库

        # 将库设置为共享库。
        共享

        # 提供源文件的相对路径。
        ${allCPP})

# 搜索指定的预构建库并将路径存储为
# 多变的。因为 CMake 在搜索路径中包含系统库
# 默认,只需要指定公共NDK库的名称
# 你要添加。 CMake 验证该库之前是否存在
# 完成构建。

find_library( # 设置路径变量的名称。
        日志库

        # 指定NDK库的名称
        # 你想要 CMake 定位。
        日志)

设置(CMAKE_CXX_FLAGS“${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}”)# 指定 CMake 应链接到目标库的库。你
# 可以链接多个库,比如你在这定义的库
# 构建脚本、预构建的第三方库或系统库。

target_link_libraries( # 指定目标库。
        本机库

        # 将目标库链接到日志库
        # 包含在 NDK 中。
        ${日志库}
        # 链接libn​​dk-mac
        ndk-mac
        # 链接libn​​dk-linux
        ndk-linux
        )

配置gradle

配置app模块下的build.gralde文件


安卓 {

    默认配置{
        //...
        
        外部NativeBuild {
            cmake {
                abiFilters“arm64-v8a”
            }
        }
        NDK {
            abiFilters“arm64-v8a”
        }
    }

    外部NativeBuild {
        cmake {
            路径“src/main/cpp/CMakeLists.txt”
            版本“3.10.2”
        }
    }
}

引用这么中的方法

在cpp目录下,新建native-lib.cpp

#包括
#包括
#包括

#define 标签“Wangyz”

#define LOG_I(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__);

extern "C" int get();

extern "C" int hi();

extern "C" JNIEXPORT jstring JNICALL
Java_com_wangyz_ndk_MainActivity_stringFromJNI(
        JNIEnv *env,jobobject /* 这个 */) {
    int a = get();
    LOG_I("你好:%d", a);

    int b = hi();
    LOG_I("嗨:%d", b);

    返回 env->NewStringUTF("hello");
}

活动中调用


公共类 MainActivity 扩展 AppCompatActivity {

    // 用于在应用程序启动时加载“native-lib”库。
    静止的 {
        System.loadLibrary(“ndk-mac”);
        System.loadLibrary(“ndk-linux”);
        System.loadLibrary(“native-lib”);
    }

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

        // 调用本地方法的示例TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * 由“native-lib”本机库实现的本机方法,
     * 与此应用程序一起打包。
     */
    公共本机字符串 stringFromJNI();
}