个人博客
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 中。
${日志库}
# 链接libndk-mac
ndk-mac
# 链接libndk-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();
}