文章目錄
我是在 Linux 上編譯的方式
配置觀景變量
- 下載好 NDK 我這裏學習採用的是 R17版本 gcc 方式編譯 後面的版本採用 cLang編譯
配置環境變量。我直接添加到了 .bash_profile 結尾
export NDK_ARM_GCC="/root/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc"
export PATH=$PATH:$NDK_ARM_GCC
export NDK_ARM_CFIG="--sysroot=/root/ndk/android-ndk-r17c/platforms/android-23/arch-arm -isystem /root/ndk/android-ndk-r17c/sysroot/usr/include -isystem /root/ndk/android-ndk-r17c/sysroot/usr/include/arm-linux-androideabi"
export PATH=$PATH:$NDK_ARM_CFIG
export NDK_ARM_AR="/root/ndk/android-ndk-r17c/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc-ar"
export PATH+$PATH:$NDK_ARM_AR
新建.h .c 文件並交叉編譯出靜態庫和動態庫
- 新建一個 hello.h 如下:
#include<stdio.h>
int getNum();
- 新建 hello.c 方便測試直接返回了一個數字
#include"hello.h"
int getNum(){
return 12345;
}
- 通過NDK的 gcc 交叉編譯.c文件 輸出 hello.o文件
$NDK_ARM_GCC $NDK_ARM_CFIG -fPIC -c hello.c -o hello.o
運行完成以後如下,生成了 hello.o 文件
- 編譯靜態庫
$NDK_ARM_AR rcs -o libhello.a hello.o
生成 libhello.a 文件
- 編譯動態庫
$NDK_ARM_GCC $NDK_ARM_CFIG -fPIC -shared hello.c -o libhello.so
生成 libhello.so 文件
- 導出 libhello.a 和 libhello.so 文件 我使用的 sz 導出
sz libhello.a
sz libhello.so
AS加載使用靜態庫和動態庫
Android Studio mk方式加載靜態庫
- 這裏只是記錄copy一下其他人總結的 mk 使用語法,重點還是在於後面的 cmake 編譯
# 這裏面能夠決定編譯 Login.c
# 1.源文件在的位置。宏函數 my-dir 返回當前目錄(包含 Android.mk 文件本身的目錄)的路徑。
# LOCAL_PATH 其實就是Android.mk文件本身的目錄的路徑
LOCAL_PATH := $(call my-dir)
$(info "LOCAL_PATH:======== ${LOCAL_PATH}")
# 2.清理
include $(CLEAR_VARS)
# TODO 預編譯庫的引入 == 提前編譯好的庫
LOCAL_MODULE := get
# LOCAL_SRC_FILES := libget.so
LOCAL_SRC_FILES := libget.a
# 預編譯共享庫的Makeifle腳本
# include $(PREBUILT_SHARED_LIBRARY)
include $(PREBUILT_STATIC_LIBRARY)
#引入其他makefile文件。CLEAR_VARS 變量指向特殊 GNU Makefile,可爲您清除許多 LOCAL_XXX 變量
#不會清理 LOCAL_PATH 變量
include $(CLEAR_VARS)
# TODO end
# 3.指定庫名字
#存儲您要構建的模塊的名稱 每個模塊名稱必須唯一,且不含任何空格
#如果模塊名稱的開頭已是 lib,則構建系統不會附加額外的前綴 lib;而是按原樣採用模塊名稱,並添加 .so 擴展名。
LOCAL_MODULE := MyLoginJar
#包含要構建到模塊中的 C 和/或 C++ 源文件列表 以空格分開
LOCAL_SRC_FILES := Login.c \
Test.c
# TODO 開始鏈接進來
# 靜態庫的鏈接
LOCAL_STATIC_LIBRARIES := get
# 動態庫鏈接
#LOCAL_SHARED_LIBRARIES := get
# 導入 log
#LOCAL_LDLIBS := -llog
LOCAL_LDLIBS := -lm -llog
# 4.動態庫
#構建動態庫BUILD_SHARED_LIBRARY 最後要動態庫
include $(BUILD_SHARED_LIBRARY)
Android Studio 通過 CMake加載靜態庫和動態庫
- 加載靜態庫
編譯期:編譯期的時候,把靜態庫完整全部Copy一份去執行的。如果修改了靜態庫,需要重新編譯。如果內部使用的庫,不會給外部提供,採用靜態庫
app的gradle配置如下:
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.lu.ndk03"
minSdkVersion 23
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
// cppFlags ""
// abiFilters 'armeabi-v7a'
}
ndk {
// 打包生成的 APK 文件指揮包含 ARM 指令集的動態庫 不加這個我那個手機導入靜態庫就崩潰
abiFilters "armeabi-v7a" /*, "arm64-v8a", "x86", "x86_64"*/
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
- 靜態庫添加到了cpp文件夾下 libhello.a
- CMake 靜態庫配置如下:
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
native-lib.cpp
libhello.a
)
# 導入靜態庫 STATIC:靜態 IMPORTED:導入
add_library(hello STATIC IMPORTED)
# 開始真正的導入
set_target_properties(hello PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libhello.a)
find_library(
log-lib
log)
target_link_libraries(
native-lib
${log-lib}
# 鏈接 hello 庫
hello
)
- 調用 hello.c 之前寫的 getNum() 方法 返回 12345
#include <jni.h>
#include <string>
#include <android/log.h>
// 用 C 編譯的 getNum 所以需要執行需要 C 環境
extern "C" {
// 自己定義的方法 會返回 12345
int getNum();
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_lu_ndk03_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
// 這裏只是打印了一下 log 查看 getNum是否調用成功
jint result = getNum();
// 成功打印出 12345
__android_log_print(ANDROID_LOG_DEBUG, "lu", "hello的結果=%d", result);
return env->NewStringUTF(hello.c_str());
}
- 加載動態庫
運行的時候,纔會去加載,而且只加載一次(System.loadLIbary(xxxx.so)),當加載一次之後,在內存中存在副本,所有使用的地方都是公用的。比如地圖的.so庫等。
- 跟靜態庫加載需要修改 CMake 的配置如下:
cmake_minimum_required(VERSION 3.4.1)
add_library(
native-lib
SHARED
native-lib.cpp
# libhello.a
)
# 導入靜態庫
#add_library(hello STATIC IMPORTED)
# 開始真正的導入
#set_target_properties(hello PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libhello.a)
# CMAKE_ANDROID_ARCH_ABI 代表 armeabi-v7a src/main
# add 添加自己的動態庫
add_library(hello SHARED IMPORTED)
#${PROJECT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libhello.so
set_target_properties(hello PROPERTIES IMPORTED_LOCATION so存儲路徑/libhello.so)
# find 只能找系統的
find_library(
log-lib
log)
target_link_libraries(
native-lib
${log-lib}
# 鏈接 hello 庫
hello
)
MainActivity中
static {
// 要寫在 總庫 之前
System.loadLibrary("hello");
System.loadLibrary("native-lib");
}