移動應用開發中,各種開發框架和語言多種多樣,常用的有Java、Kotlin和Swift等。但有時候,我們需要使用C或C++語言編寫一些性能更高的原生代碼,以獲取更好的用戶體驗。Android Studio的NDK(Native Development Kit)提供了一種實現這種需求的方法。
一、什麼是NDK?
NDK是Android Studio提供的一個工具集,旨在幫助開發者編寫C/C++代碼來優化Android的應用程序,包括增加應用程序的性能,處理自定義任務和更多。目前,NDK支持的ABI主要包括 armeabi-v7a、arm64-v8a、x86、x86_64以及mips和mips64。
在沒有NDK時,開發者的代碼只能以Java和Kotlin等二進制代碼的方式運行。而有了NDK之後,可以將一些緊耦合的功能和代碼轉化為C/C++代碼,然後以庫的形式提供給Java和Kotlin等高級語言使用。這樣不僅可以提高性能,還可以在代碼共享方面實現更好的跨平台性。
二、如何在Android Studio中使用NDK?
Android Studio提供了NDK插件,讓開發者輕鬆地設置和配置NDK的開發環境。在使用NDK之前,需要完成以下步驟:
1、下載NDK:
在Android Studio中,點擊“Tools->SDK Manager->SDK Tools”選項卡,然後在右邊的主窗口區域找到和選中“NDK”即可下載。
2、配置Jni目錄
在Java工程的根目錄下構建JNI接口需要的目錄結構,例如:app/src/main/jni。然後在app下新建.buildozer文件(目的是為了讓gradle加載NDK配置)。
# app/.buildozer.gradle.kts android { defaultConfig { externalNativeBuild { cmake { cppFlags "-std=c++11" arguments "-DANDROID_STL=c++_shared" } } } }
3、創建.so庫文件
在jni目錄下創建一個C或C++源文件,然後使用編譯器創建.so文件,將其複製到應用程序的libs目錄中。在libs目錄下可以分別為每種CPU架構創建目錄,以job目錄為例:
app/libs/armeabi-v7a/ app/libs/arm64-v8a/ app/libs/x86/ app/libs/x86_64/
在完成上述步驟之後,你可以像其他庫一樣在Java代碼中使用自定義的C/C++庫文件。如下所示:
System.loadLibrary("natives-lib");
這裡的natives-lib就是.so文件的名稱,它需要和C/C++源文件中的名稱相同。
三、如何在NDK中使用靜態庫?
在C和C++中,靜態庫非常重要,它們被用作重複代碼和可重用代碼的共享。在Android NDK中,添加本機靜態庫和可執行文件也很簡單:
1、編寫C++源代碼
// test.cpp #include "test.h" int add(int a, int b) { return a + b; }
2、編寫C頭文件
// test.h #ifndef TEST_H #define TEST_H #ifdef __cplusplus extern "C"{ #endif int add(int a, int b); #ifdef __cplusplus } #endif #endif // TEST_H
3、編寫Android.mk文件
Android.mk文件用於配置如何構建NDK應用程序。它定義了源代碼文件、庫等,告訴編譯器如何處理這些文件,並包含使用這些文件創建動態庫的指令。Android.mk文件應在jni目錄下創建。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := test LOCAL_SRC_FILES := test.cpp include $(BUILD_STATIC_LIBRARY)
4、在.buildozer.gradle.kts文件中增加編譯選項
defaultConfig { externalNativeBuild { cmake { cppFlags "-std=c++11" arguments "-DANDROID_STL=c++_shared", "-DANDROID_TOOLCHAIN=clang" // 添加這一行 } } }
需要注意的是,要使用靜態庫時,需要使用clang作為工具鏈才能編譯通過。
5、在.buildozer.gradle.kts中導入靜態庫
android { sourceSets { main { jniLibs.srcDir 'libs' } } }
這個操作主要是告訴gradle在哪裡可以找到靜態庫,實現導入了so庫中。
6、在Java代碼中使用靜態庫
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("test"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); int result = Test.add(1, 2); //調用靜態庫函數 TextView textView = findViewById(R.id.tv_result); textView.setText("result = " + result); } }
以上就是使用靜態庫的完整步驟。在Jni目錄中,需要有Android.mk文件,它告訴編譯器如何構建靜態庫。編譯器會將靜態庫轉換為.so文件,並將其打包在APK應用包中。在Java代碼中可以通過System.loadLibrary方法加載本地庫,就像之前加載普通的so庫一樣。
四、NDK開發常見問題及解決方案
1、如何解決不同CPU架構的兼容性問題
Android系統支持多種CPU架構的設備,並且支持同時安裝多個.so庫的版本。這種格式通常是“/lib/libname.so”或“/lib/architecture/libname.so”。為了實現多架構支持,你需要在構建過程中生成多個庫版本。可以將結果位置指定到每個configure的ANDROID_ABI的不同子目錄中,如下所示:
app/ jni/ Android.mk Application.mk foo.c libs/ armeabi/ libfoo.so armeabi-v7a/ libfoo.so x86/ libfoo.so
2、如何解決debug版本無法正常工作的問題
默認情況下,NDK構建出的.so庫的標誌為release版本,而非debug版本,如果需要在NDK調試過程中使用debug版本,需要在Gradle中設置:
android { defaultConfig { externalNativeBuild { cmake { arguments "-DCMAKE_BUILD_TYPE=DEBUG" } } } }
3、如何解決NDK開發過程中出現的其他問題
可以將以下項目添加到build.gradle文件中查看調試級別。項目和gradle.properties文件中都有這些內容。
android { buildTypes{ debug { debuggable true jniDebuggable true } } }
4、如何解決NDK中遇到的鏈接錯誤
常見的原因包括C++代碼插入C語言源代碼、未定義的全球變量等,可以試着把鏈接器的日誌打開,檢查被外部問題導致的鏈接錯誤。
LOCAL_LDLIBS += -Wl,--trace-symbol=foo
五、總結
在移動應用開發中,NDK是為開發者提供高性能的編程接口的一種方法。它能幫助開發者編寫C/C++代碼,優化Android應用程序的性能,實現自定義任務等操作。本文介紹了如何使用NDK的詳細步驟和常見問題的解決方法,希望對你在移動應用開發中使用NDK起到一定的幫助。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/291021.html