一、前言
前面文章写过了,使用NDK交叉编译C/C++文件为静态库和动态库,在安卓中调用,当时环境在windows上,不知道是不是环境原因导致动态库无法使用,这次电脑环境为纯Ubuntu系统,再来重走一下来时路...
二、编译动态库
方式一(只在Ubuntu上使用)
假设,你的电脑上已经安装了NDK了
查看NDK版本
bash
ls ~/Android/Sdk/ndk/
这个是AS默认创建的SDK路径,如果你电脑上有NDK的话,会有以下输出:21.4.7075529 23.1.7779620
1. 选择NDK版本
建议使用较新的
bash
export NDK_HOME=~/Android/Sdk/ndk/23.1.7779620
2. 创建项目目录结构
bash
mkdir -p native-lib/jni
cd native-lib
3. 准备源文件
将test.c
文件放入jni
目录,内容如下:
bash
#include <stdio.h>
#include <android/log.h>
int test_function() {
__android_log_print(ANDROID_LOG_INFO, "NativeLib", "Hello from C!");
return 20250429;
}
4. 创建编译配置文件
创建jni/Android.mk
bash
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testlib
LOCAL_SRC_FILES := test.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
创建jni/Application.mk
bash
APP_ABI := armeabi-v7a arm64-v8a
APP_PLATFORM := android-21
5. 编译动态库
bash
$NDK_HOME/ndk-build
编译会有以下内容输出:
bash
xaye@orange:~/dev/native-lib$ $NDK_HOME/ndk-build
[armeabi-v7a] Compile thumb : testlib <= test.c
[armeabi-v7a] SharedLibrary : libtestlib.so
[armeabi-v7a] Install : libtestlib.so => libs/armeabi-v7a/libtestlib.so
[arm64-v8a] Compile : testlib <= test.c
[arm64-v8a] SharedLibrary : libtestlib.so
[arm64-v8a] Install : libtestlib.so => libs/arm64-v8a/libtestlib.so
此时的目录结构为:
bash
libs/
├── arm64-v8a/
│ └── libtestlib.so
├── armeabi-v7a/
│ └── libtestlib.so
obj/ (中间文件)
方式一,编译动态库结束!
方式二(Ubuntu和Windows上都可)
在安卓项目中编译
项目目录结构通常如下:
bash
你的Android项目/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/ # Java代码
│ │ │ ├── cpp/ # C/C++代码(可选)
│ │ │ └── jniLibs/ # 预编译的.so文件(如果不用CMake直接编译)
│ ├── build.gradle # 模块配置
│ └── CMakeLists.txt # (推荐位置)CMake配置文件
└── ...
-
在
app/
目录下创建CMakeLists.txt
(如果不存在) -
将你的
test.c
文件放在app/src/main/cpp/
目录下 -
修改
app/build.gradle
:
bash
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
// 指定ABI(可选)
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
CMakeLists.txt
内容:
bash
cmake_minimum_required(VERSION 3.4.1)
add_library(testlib SHARED src/main/cpp/test.c)
find_library(log-lib log)
target_link_libraries(testlib ${log-lib})
然后编译项目 生成debug apk,在下面目录就可以找到生成的动态库
方式二,编译动态库结束!
三、验证动态库在安卓项目中使用
写一个 .cpp
(JNI桥接层),在 .cpp
中 extern "C"
引用 .so
里面的函数,然后正常JNI导出给Java调用!
将编译好的动态库,放到如下目录中:
bash
app/src/main/jniLibs/arm64-v8a/libtestlib.so
app/src/main/jniLibs/armeabi-v7a/libtestlib.so
在cpp 目录下,创建 native_bridge.cpp
文件,内容如下:
bash
#include <jni.h>
extern "C"
// 声明你.so里暴露的C函数
int test_function();
extern "C"
JNIEXPORT jint JNICALL
Java_com_xaye_testcompiler_NativeLib_test_1function(JNIEnv *env, jclass thiz) {
// 调用.so里的原生函数
return test_function();
}
-
这里
Java_com_xaye_testcompiler_NativeLib_test_1function
是标准 JNI 规范。 -
写一个JNI包装方法,在里面调用
.so
里的test_function()
。
配置 CMakeLists.txt 来链接你的 .so
在你的 CMakeLists.txt
里:
bash
cmake_minimum_required(VERSION 3.4.1)
# 指向你的 .so 和头文件
add_library(testlib SHARED IMPORTED)
set_target_properties(testlib PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libtestlib.so
)
# 编译自己的 native_bridge.cpp
add_library(native-bridge SHARED native_bridge.cpp)
# 链接你的 native-bridge 依赖 testlib.so
target_link_libraries(native-bridge testlib log)
-
testlib.so
放在app/src/main/jniLibs/armeabi-v7a/
或arm64-v8a/
下。 -
native-bridge
是你自己编译出来的新.so
,Android系统加载的是你这层。 -
修改
app/build.gradle
:
bash
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
// 指定ABI(可选)
abiFilters "arm64-v8a", "armeabi-v7a"
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}
注意,CMakeLists.txt
放在了src/main/cpp/
下,这里的路径要和实际的一样!
Java 层使用方式:
java
package com.xaye.testcompiler;
public class NativeLib {
static {
System.loadLibrary("native-bridge"); // 只加载你编译的这个桥接so!
}
public static native int test_function();
}
调用:
java
int result = NativeLib.test_function();
Log.d("TEST", "C 函数返回值: " + result);
结果:

最后
回头看下,也没有那么复杂,大致流程就是正确编译出动态库,由于安卓调用C/C++代码,需要JNI,所以再写个.cpp文件,链接动态库和安卓代码,这个桥接作用的.cpp文件,就是使用JNI技术,桥接代码就是CMakeLists.txt
,结束!