Android 官方建議使用 CMake 作為建構系統,配合 NDK 工具鏈編譯 C/C++ 程式碼為 .so 動態共享庫,透過 JNI 供 Java/Kotlin 呼叫。
project/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── cpp/ # C++ 原始碼
│ │ │ │ ├── native-lib.cpp
│ │ │ │ └── include/ # 標頭檔
│ │ │ └── java/... # Java/Kotlin 程式碼
│ │ └── CMakeLists.txt # CMake 建構腳本
│ └── build.gradle
cmake_minimum_required(VERSION 3.4.1)
# 設定 C++ 標準
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 專案名稱
project("my-native-lib")
# 匯入預編譯庫 (如有)
# add_library(imported-lib SHARED IMPORTED)
# set_target_properties(imported-lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libimported.so)
# 新增自有原始碼
add_library(
native-lib # 庫名稱 -> 編譯為 libnative-lib.so
SHARED # 動態庫
native-lib.cpp # 來源檔案
)
# 包含目錄
target_include_directories(native-lib PRIVATE include)
# 連結系統庫 (log, android, OpenGL ES 等)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib})
# 如需連結其他 .so
# target_link_libraries(native-lib imported-lib ${log-lib})
#include
#include
#include "my_cpp_class.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
MyCppClass obj;
std::string result = obj.processData("Hello from C++");
return env->NewStringUTF(result.c_str());
}
// 多參數範例
extern "C" JNIEXPORT jint JNICALL
Java_com_example_myapp_Calculator_add(
JNIEnv* env,
jobject,
jint a,
jint b) {
return a + b;
}
// Java
public class MainActivity {
static {
System.loadLibrary("native-lib"); // 對應 CMake 中的 native-lib
}
public native String stringFromJNI();
public native int add(int a, int b);
}
// Kotlin
class Calculator {
companion object {
init { System.loadLibrary("native-lib") }
}
external fun add(a: Int, b: Int): Int
}
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions -std=c++17"
arguments "-DANDROID_STL=c++_shared"
}
}
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a' // 指定架構,減少體積
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.18.1"
}
}
}
若需在 Windows 獨立編譯 (不使用 Android Studio):
# 設定 NDK 路徑
set NDK_ROOT=C:\Users\%USERNAME%\AppData\Local\Android\Sdk\ndk\25.1.8937393
# 使用 CMake 交叉編譯
cmake -B build -S . \
-DCMAKE_TOOLCHAIN_FILE=%NDK_ROOT%\build\cmake\android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-21 \
-DANDROID_STL=c++_shared \
-DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
| 問題 | 原因 | 解決 |
|---|---|---|
| UnsatisfiedLinkError: 找不到 .so | 架構不匹配、庫名錯誤、未載入依賴 | 檢查 abiFilters、System.loadLibrary 名稱、ldd 分析依賴 |
| JNI 簽名不符 | Java native 宣告與 C++ 函式簽名不一致 | 使用 javah 或 AS 自動生成標頭檔、核對參數型別 |
| C++ 標準庫衝突 | c++_static vs c++_shared 混用 | 統一使用 c++_shared,或所有模組同為 static |
| 編譯錯誤: 標頭檔找不到 | include 路徑未正確設定 | CMake target_include_directories、NDK sysroot 路徑 |