行業(yè)網(wǎng)站方案營(yíng)銷型企業(yè)網(wǎng)站
環(huán)境搭建
Android NDK開(kāi)發(fā)實(shí)戰(zhàn)之環(huán)境搭建篇(so庫(kù),Gemini ai)-CSDN博客
初始配置
前面已經(jīng)運(yùn)行了一個(gè)簡(jiǎn)單的初始程序,現(xiàn)在我們來(lái)往初始程序添加類和函數(shù),并成功運(yùn)行的實(shí)驗(yàn)。
一級(jí)配置
第一層配置主要是cmake文件環(huán)境和一些編譯選項(xiàng)。
build配置 可參考:?
#build配置externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt')version '3.22.1'//cpp 編譯選項(xiàng)cppFlags '-fexceptions -std=c++11'//設(shè)置c++stl為動(dòng)態(tài)庫(kù) 默認(rèn)是靜態(tài)庫(kù) arguments '-DANDROID_STL=c++_shared'}}
?
二級(jí)cmake配置
主要配置生成的動(dòng)態(tài)庫(kù)名稱,具體看注釋
為了測(cè)試 我們創(chuàng)建一個(gè)hello類
#include "iostream"
class hello {
public:std::string getVersion();
};
#include "hello.h"
std::string hello::getVersion(){return "v1.0 hello word";
}
#include <jni.h>
#include <string>#include "hello.h"
extern "C" JNIEXPORT jstring JNICALL
//stringFromJNI是c++function名稱
Java_com_example_first_1ndk_1cpp_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string helo = "Hello from first native C++ ";hello h;helo += h.getVersion();return env->NewStringUTF(helo.data());
}
?更改cmake,把cpp文件加入
#cmake最低版本
cmake_minimum_required(VERSION 3.22.1)#最終項(xiàng)目名稱 通過(guò)${CMAKE_PROJECT_NAME}獲得
project("first_ndk_cpp")add_library(#生成的動(dòng)態(tài)庫(kù)名稱${CMAKE_PROJECT_NAME}#生成庫(kù)類型:SHARED動(dòng)態(tài) 默認(rèn)靜態(tài)SHARED#相關(guān)cpp文件 假設(shè)有全局變量,交叉使用需要注意編譯順序。native-lib.cpphello.cpp)target_link_libraries(#最終生成目標(biāo)庫(kù)名稱${CMAKE_PROJECT_NAME}# 鏈接其他目標(biāo)庫(kù)androidlog)
MainActivity
MainActivity 通常被認(rèn)為是 Android 應(yīng)用程序的主要入口點(diǎn)。
public class MainActivity extends AppCompatActivity {// 靜態(tài)初始化塊, 程序啟動(dòng)時(shí)調(diào)用static {//加載名為 first_ndk_cpp 的動(dòng)態(tài)庫(kù)System.loadLibrary("first_ndk_cpp");}private ActivityMainBinding binding;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//視圖綁定binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());// Example of a call to a native methodTextView tv = binding.sampleText;tv.setText(stringFromJNI()); //java調(diào)用}/**這聲明了一個(gè)名為 stringFromJNI 的本地方法。該實(shí)現(xiàn)位于 first_ndk_cpp 庫(kù)中。*/public native String stringFromJNI();
}
運(yùn)行
最后運(yùn)行輸出
?小結(jié)
熟悉基本配置,知道增加類代碼如何重新編譯成動(dòng)態(tài)庫(kù)使用。
動(dòng)態(tài)庫(kù)實(shí)戰(zhàn)
場(chǎng)景:編譯兩份版本動(dòng)態(tài)庫(kù) 分別輸出v1和v2,然后切換運(yùn)行。
設(shè)置動(dòng)態(tài)庫(kù)導(dǎo)出路勁
前面操作,我們成功編譯出動(dòng)態(tài)庫(kù)。但是路勁很隱蔽,其次規(guī)范處理。
實(shí)現(xiàn)方法
CMakeLists.txt 設(shè)置導(dǎo)出so路勁:
CMAKE_ARCHIVE_OUTPUT_DIRECTORY :默認(rèn)存放靜態(tài)庫(kù)的?件夾位置; CMAKE_LIBRARY_OUTPUT_DIRECTORY :默認(rèn)存放動(dòng)態(tài)庫(kù)的?件夾位置;
# 第一種做法:單獨(dú)設(shè)置動(dòng)態(tài)庫(kù)的默認(rèn)輸出路徑
# 將動(dòng)態(tài)庫(kù)輸出到 `main/jniLibs/${ANDROID_ABI}` 目錄
# ${ANDROID_ABI} 是 Gradle 配置的 ABI 策略(如 armeabi-v7a, arm64-v8a 等)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY${CMAKE_CURRENT_SOURCE_DIR}/../libs/jniLibs/${ANDROID_ABI})# 第二種做法:設(shè)置動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的默認(rèn)輸出路徑
# 將動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)輸出到 `main/jniLibs/${ANDROID_ABI}` 目錄
# 注意:LIBRARY_OUTPUT_PATH 是舊版 CMake 的變量,
#推薦使用 CMAKE_LIBRARY_OUTPUT_DIRECTORY 和 CMAKE_ARCHIVE_OUTPUT_DIRECTORY
set(LIBRARY_OUTPUT_PATH${CMAKE_CURRENT_SOURCE_DIR}/../libs/jniLibs/${ANDROID_ABI})
?
?根據(jù)這個(gè)方法步驟編譯兩個(gè)版本
主要區(qū)別:
std::string hello::getVersion(){return "v2.0 hello word";
}
?
嘗試版本切換
//定義項(xiàng)目的源代碼和資源文件的目錄結(jié)構(gòu)sourceSets {main {//指定 JNI 庫(kù)文件(.so 文件)的存放目錄jniLibs.srcDirs = ['src/main/libs/jniLibs']}}
?小結(jié)
學(xué)習(xí)如何指定動(dòng)態(tài)庫(kù)導(dǎo)出路勁,并根據(jù)動(dòng)態(tài)庫(kù)切換,實(shí)現(xiàn)多種版本調(diào)用。
特定cpu架構(gòu)實(shí)戰(zhàn)
上述討論了如何導(dǎo)出不同的動(dòng)態(tài)庫(kù),現(xiàn)在如果只想根據(jù)x86架構(gòu)導(dǎo)出單個(gè)so庫(kù)如何實(shí)現(xiàn)?
先看看為什么需要指定cpu
?成指定cpu平臺(tái)對(duì)應(yīng)的so庫(kù)?件
應(yīng)??進(jìn)制接?(ABI),包含的內(nèi)容:
1、可執(zhí)??進(jìn)制?件的格式以及?持的內(nèi)容類型,?進(jìn)制?件如:程序、共享庫(kù)...
2、可使?的CPU指令集
3、運(yùn)?時(shí)內(nèi)存存儲(chǔ)和加載的字節(jié)順序
4、應(yīng)?和系統(tǒng)之間傳遞數(shù)據(jù)的規(guī)范,以及系統(tǒng)調(diào)?函數(shù)時(shí),如何使?堆棧、寄存器
5、如何重整C++名稱
abi與 指令集
Android 支持多種 CPU 架構(gòu),每種架構(gòu)對(duì)應(yīng)不同的 ABI。以下是常見(jiàn)的 CPU 架構(gòu)及其對(duì)應(yīng)的 ABI:
CPU 架構(gòu) | ABI | 說(shuō)明 |
---|---|---|
ARMv5 | armeabi | 32 位 ARM 架構(gòu),已過(guò)時(shí),Android NDK r17 已不再支持。 |
ARMv7 | armeabi-v7a | 32 位 ARM 架構(gòu),支持硬件浮點(diǎn)運(yùn)算和 NEON 指令集。 |
ARMv8 | arm64-v8a | 64 位 ARM 架構(gòu),支持 AArch64 指令集。 |
MIPS | mips | 32 位 MIPS 架構(gòu),已過(guò)時(shí),Android NDK r17 已不再支持。 |
MIPS64 | mips64 | 64 位 MIPS 架構(gòu),已過(guò)時(shí),Android NDK r17 已不再支持。 |
x86 | x86 | 32 位 Intel x86 架構(gòu),主要用于模擬器和部分低端設(shè)備。 |
x86_64 | x86_64 | 64 位 Intel x86 架構(gòu),主要用于模擬器和高性能設(shè)備。 |
ABI 兼容性是指應(yīng)用程序在不同 CPU 架構(gòu)上的運(yùn)行能力。以下是各 ABI 的兼容性說(shuō)明:
ABI | 兼容性說(shuō)明 |
---|---|
armeabi | 兼容 ARMv5 和 ARMv7,但不兼容 ARMv8(64 位)。 |
armeabi-v7a | 兼容 ARMv7,但不兼容 ARMv5 和 ARMv8(64 位)。 |
arm64-v8a | 兼容 ARMv8(64 位),但不兼容 ARMv5 和 ARMv7(32 位)。 |
mips | 僅兼容 MIPS 架構(gòu),已過(guò)時(shí)。 |
mips64 | 僅兼容 MIPS64 架構(gòu),已過(guò)時(shí)。 |
x86 | 兼容 x86 架構(gòu),同時(shí)兼容?armeabi ?和?armeabi-v7a (通過(guò)二進(jìn)制翻譯運(yùn)行)。 |
x86_64 | 兼容 x86_64 架構(gòu),同時(shí)兼容?arm64-v8a (通過(guò)二進(jìn)制翻譯運(yùn)行)。 |
x86 和 x86_64 的特殊性
x86:主要用于模擬器和部分低端設(shè)備。通過(guò)二進(jìn)制翻譯,可以運(yùn)行?armeabi
?和?armeabi-v7a
?的代碼,但性能較低。
x86_64:主要用于模擬器和高性能設(shè)備。通過(guò)二進(jìn)制翻譯,可以運(yùn)行?arm64-v8a
?的代碼。
ABI 配置
在 Android 項(xiàng)目中,可以通過(guò) Gradle 配置支持的 ABI。
android {defaultConfig {ndk {abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'}}
}
小結(jié)
ARM 架構(gòu):armeabi-v7a
?和?arm64-v8a
?是當(dāng)前主流的架構(gòu)。
x86 架構(gòu):主要用于模擬器,通過(guò)二進(jìn)制翻譯可以運(yùn)行 ARM 架構(gòu)的代碼。
ABI 配置:通過(guò) Gradle 的?abiFilters
?指定支持的 ABI。
問(wèn)題
當(dāng)遇到不能run,編譯沒(méi)錯(cuò)誤信息,則進(jìn)行sync now即可解決
??
學(xué)習(xí)資料分享
0voice · GitHub