1.eclipse中的Jni開發(fā)流程(一)
2.eclipse中的Jni開發(fā)流程(二)
3.Android Studio配置CMake開發(fā)NDK
1.在SDK Tools中勾選安裝CMake掂碱、LLDB透揣、NDK
2.配置一些快捷方式
參數(shù)講解
javah 用于生成頭文件
Program:$JDKPath$/bin/javah
Parameters:-d ../jni -jni $FileClass$
Working directory:$SourcepathEntry$\..\java
ndk-build 用于構(gòu)建so包
注意:MAC/Linux用ndk-build胧瓜,沒有.cmd后綴
Program:D:\adt\sdk\ndk-bundle\ndk-build.cmd
Parameters:什么都不用填
Working directory:$ModuleFileDir$\src\main
3.在工程的local.properties文件中配置NDK的目錄
sdk.dir=C\:\\Users\\yuxue\\AppData\\Local\\Android\\sdk
ndk.dir=C\:\\Users\\yuxue\\AppData\\Local\\Android\\sdk\\ndk-bundle
也可以使用圖形界面危纫,單擊模塊選擇Open Moude Setting吧趣,選擇好NDK的路徑
4.編譯時如果檢查NDK過時了可以在gradle.properties文件中增加“android.useDeprecatedNdk=true”使它可以使用過時的NDK
android.useDeprecatedNdk=true
5.創(chuàng)建CMakeLists.txt文件并放在模塊的的根目錄
# 設(shè)置構(gòu)建本地庫所需的最小版本的cbuild榴捡。
cmake_minimum_required(VERSION 3.4.1)
# 創(chuàng)建并命名一個庫,將其設(shè)置為靜態(tài)
# 或者共享验游,并提供其源代碼的相對路徑幢炸。
# 您可以定義多個庫泄隔,而cbuild為您構(gòu)建它們拒贱。
# Gradle自動將共享庫與你的APK打包宛徊。
add_library( hello-lib #設(shè)置庫的名稱。即SO文件的名稱逻澳,生產(chǎn)的so文件為“l(fā)ibhello-lib.so”,在加載的時候“System.loadLibrary("hello-lib");”
SHARED # 將庫設(shè)置為共享庫闸天。
src/main/jni/hello.cpp # 提供一個源文件的相對路徑
src/main/jni/helloJni.cpp # 提供同一個SO文件中的另一個源文件的相對路徑
)
#搜索指定的預(yù)構(gòu)建庫,并將該路徑存儲為一個變量斜做。因為cbuild默認(rèn)包含了搜索路徑中的系統(tǒng)庫苞氮,所以您只需要指定您想要添加的公共NDK庫的名稱。cbuild在完成構(gòu)建之前驗證這個庫是否存在瓤逼。
find_library(log-lib # 設(shè)置path變量的名稱笼吟。
log # 指定NDK庫的名稱 你想讓CMake來定位。
)
#指定庫的庫應(yīng)該鏈接到你的目標(biāo)庫霸旗。您可以鏈接多個庫贷帮,比如在這個構(gòu)建腳本中定義的庫、預(yù)構(gòu)建的第三方庫或系統(tǒng)庫诱告。
target_link_libraries( hello-lib #指定目標(biāo)庫中撵枢。與 add_library的庫名稱一定要相同
${log-lib} # 將目標(biāo)庫鏈接到日志庫包含在NDK。
)
#如果需要生產(chǎn)多個SO文件的話精居,寫法如下
add_library( natave-lib #設(shè)置庫的名稱锄禽。另一個so文件的名稱
SHARED # 將庫設(shè)置為共享庫。
src/main/jni/nataveJni.cpp # 提供一個源文件的相對路徑
)
target_link_libraries( natave-lib #指定目標(biāo)庫中靴姿。與 add_library的庫名稱一定要相同
${log-lib} # 將目標(biāo)庫鏈接到日志庫包含在NDK沃但。
)
6.在模塊的build.gradle文件中添加
android {
compileSdkVersion 26
buildToolsVersion "26.0.0"
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
7.編寫Java中的Native方法
public native String getStr();
public native String gethelloJniStr();
8.生成C的頭文件
生成后
9.編寫C函數(shù)
#include "stdio.h"
#include "jni.h"
#include "string"
extern "C"
JNIEXPORT jstring JNICALL Java_com_ljp_learnandroidadvanced_MainActivity_getStr
(JNIEnv *env,
jobject jobject1){
return env->NewStringUTF("hello world from cpp");
}
至此,這個項目就可以運行了
更多的學(xué)習(xí)
(1) .externalNativeBuild文件夾:用于存放cmake編譯好的文件佛吓,包括支持的各種硬件等信息绽慈,有點類似于build.gradle文件明確Gradle如何編譯APP;
(2) cpp文件夾:存放C/C++代碼文件辈毯,native-lib.cpp文件默認(rèn)生成的坝疼;
(3) CMakeLists.txt:cmake腳本配置文件,cmake會根據(jù)該腳本文件中的指令去編譯相關(guān)的C/C++源文件谆沃,并將編譯后產(chǎn)物生成共享庫或靜態(tài)塊钝凶,然后Gradle將其打包到APK中。
CMakeLists.txt文件解析如下:
# 指定cmke版本
cmake_minimum_required(VERSION3.4.1)
# add_library()命令用于向CMake添加依賴源文件或庫
# 指令需傳入三個參數(shù)(函數(shù)庫名稱、庫類型耕陷、依賴源文件相對路徑)
add_library( # 生成函數(shù)庫的名稱掂名,即libnative-lib.so或libnative-lib.a(lib和.so/.a默認(rèn)缺省)
native-lib
# 生成庫類型:動態(tài)庫為SHARED,靜態(tài)庫為STATIC
SHARED
# 依賴的c/cpp文件(相對路徑)
src/main/cpp/native-lib.cpp )
# find_library()命令用于定位NDK中的庫
# 需傳入兩個參數(shù)(path變量哟沫、ndk庫名稱)
find_library( # 設(shè)置path變量的名稱饺蔑,這里為NDK中的日志庫
log-lib
#指定cmake查詢庫的名稱
#即在ndk開發(fā)包中查詢liblog.so函數(shù)庫,將其路徑賦值給log-lib
log )
#target_link_libraries()命令用于指定要關(guān)聯(lián)到的原生庫的庫
target_link_libraries(# 指定目標(biāo)庫嗜诀,與上面指定的函數(shù)庫名一致
native-lib
# 鏈接的庫猾警,根據(jù)log-lib變量對應(yīng)liblog.so函數(shù)庫
${log-lib} )
通過查看native-lib.cpp方法,stringFromJNI目的是向Java層返回一個字符串隆敢。如果要在native-lib.cpp文件中添加新的方法发皿,必須添加在extern"C" { } 中,或者在每個方法前加extern"C", 否則會報找不到方法拂蝎。如果源文件為C穴墅,則須將extern“C”部分去掉,因為extern "C"的作用就是告訴編譯器以C方式編譯温自。
JNI開發(fā)打印日志
#include <android/log.h>
#define LOG_TAG "System.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
LOG的使用
LOGD("TAGD,a=%d,b=%d",a,b);
LOGI("TAGI,a=%d,b=%d",a,b);
LOGW("TAGW,a=%d,b=%d",a,b);
LOGE("TAGE,a=%d,b=%d",a,b);
Android系統(tǒng)目前支持的CPU架構(gòu)
ARMv5玄货,ARMv7 (從2010年起)
x86 (從2011年起)
MIPS (從2012年起)
ARMv8,MIPS64和x86_64 (從2014年起)
每一個CPU架構(gòu)對應(yīng)一個ABI
CPU架構(gòu) ABI
ARMv5 ---> armeabi
ARMv7 ---> armeabi-v7a
x86 ---> x86
MIPS ---> mips
ARMv8 ---> arm64-v8a
MIPS64 ---> mips64
x86_64 ---> x86_64
armeabi:默認(rèn)選項悼泌,將創(chuàng)建以基于ARM* v5TE 的設(shè)備為目標(biāo)的庫松捉。 具有這種目標(biāo)
的浮點運算使用軟件浮點運算。 使用此ABI(二進(jìn)制接口)創(chuàng)建的二進(jìn)制代碼將可以
在所有 ARM*設(shè)備上運行券躁。所以armeabi通用性很強(qiáng)惩坑。但是速度慢
armeabi-v7a:創(chuàng)建支持基于ARM* v7 的設(shè)備的庫,并將使用硬件FPU指令也拜。
armeabi-v7a是針對有浮點運算或高級擴(kuò)展功能的arm v7 cpu以舒。
mips:MIPS是世界上很流行的一種RISC處理器。MIPS的意思是“無內(nèi)部互鎖流水級
的微處理器”(Microprocessor without interlocked piped stages)慢哈,其機(jī)
制是盡量利用軟件辦法避免流水線中的數(shù)據(jù)相關(guān)問題蔓钟。
x86:支持基于硬件的浮點運算的IA-32 指令集。x86是可以兼容armeabi平臺運行
的卵贱,無論是armeabi-v7a還是armeabi滥沫,同時帶來的也是性能上的損耗,另外需要
指出的是键俱,打包出的x86的so兰绣,總會比armeabi平臺的體積更小。
總結(jié)
如果項目只包含了 armeabi编振,那么在所有Android設(shè)備都可以運行缀辩;
如果項目只包含了 armeabi-v7a,除armeabi架構(gòu)的設(shè)備外都可以運行;
如果項目只包含了 x86臀玄,那么armeabi架構(gòu)和armeabi-v7a的Android設(shè)備是無法
運行的瓢阴;
如果同時包含了 armeabi,armeabi-v7a和x86健无,所有設(shè)備都可以運行荣恐,程序在運
行的時候去加載不同平臺對應(yīng)的so,這是較為完美的一種解決方案累贤,同時也會導(dǎo)致
包變大叠穆。
我的CSDN博客地址:http://blog.csdn.net/wo_ha/article/details/78131635