Android Studio配置CMake開(kāi)發(fā)NDK

1.eclipse中的Jni開(kāi)發(fā)流程(一)
2.eclipse中的Jni開(kāi)發(fā)流程(二)
3.Android Studio配置CMake開(kāi)發(fā)NDK

1.在SDK Tools中勾選安裝CMake、LLDB、NDK

Paste_Image.png

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,沒(méi)有.cmd后綴
    Program:D:\adt\sdk\ndk-bundle\ndk-build.cmd
    Parameters:什么都不用填
    Working directory:$ModuleFileDir$\src\main
Paste_Image.png
Paste_Image.png

3.在工程的local.properties文件中配置NDK的目錄

sdk.dir=C\:\\Users\\yuxue\\AppData\\Local\\Android\\sdk
ndk.dir=C\:\\Users\\yuxue\\AppData\\Local\\Android\\sdk\\ndk-bundle
Paste_Image.png

也可以使用圖形界面,單擊模塊選擇Open Moude Setting,選擇好NDK的路徑

Paste_Image.png

4.編譯時(shí)如果檢查NDK過(guò)時(shí)了可以在gradle.properties文件中增加“android.useDeprecatedNdk=true”使它可以使用過(guò)時(shí)的NDK

android.useDeprecatedNdk=true

5.創(chuàng)建CMakeLists.txt文件并放在模塊的的根目錄

# 設(shè)置構(gòu)建本地庫(kù)所需的最小版本的cbuild。
cmake_minimum_required(VERSION 3.4.1)
# 創(chuàng)建并命名一個(gè)庫(kù),將其設(shè)置為靜態(tài)
#  或者共享,并提供其源代碼的相對(duì)路徑。
# 您可以定義多個(gè)庫(kù),而cbuild為您構(gòu)建它們。
#  Gradle自動(dòng)將共享庫(kù)與你的APK打包。
add_library( hello-lib  #設(shè)置庫(kù)的名稱(chēng)。即SO文件的名稱(chēng),生產(chǎn)的so文件為“l(fā)ibhello-lib.so”,在加載的時(shí)候“System.loadLibrary("hello-lib");”
                SHARED  # 將庫(kù)設(shè)置為共享庫(kù)。
                src/main/jni/hello.cpp    # 提供一個(gè)源文件的相對(duì)路徑
                src/main/jni/helloJni.cpp    # 提供同一個(gè)SO文件中的另一個(gè)源文件的相對(duì)路徑
              )
#搜索指定的預(yù)構(gòu)建庫(kù),并將該路徑存儲(chǔ)為一個(gè)變量。因?yàn)閏build默認(rèn)包含了搜索路徑中的系統(tǒng)庫(kù),所以您只需要指定您想要添加的公共NDK庫(kù)的名稱(chēng)。cbuild在完成構(gòu)建之前驗(yàn)證這個(gè)庫(kù)是否存在。
find_library(log-lib  # 設(shè)置path變量的名稱(chēng)。
              log   #  指定NDK庫(kù)的名稱(chēng) 你想讓CMake來(lái)定位。
               )
#指定庫(kù)的庫(kù)應(yīng)該鏈接到你的目標(biāo)庫(kù)。您可以鏈接多個(gè)庫(kù),比如在這個(gè)構(gòu)建腳本中定義的庫(kù)、預(yù)構(gòu)建的第三方庫(kù)或系統(tǒng)庫(kù)。
target_link_libraries( hello-lib     #指定目標(biāo)庫(kù)中。與 add_library的庫(kù)名稱(chēng)一定要相同
                       ${log-lib}    # 將目標(biāo)庫(kù)鏈接到日志庫(kù)包含在NDK。
                        )
#如果需要生產(chǎn)多個(gè)SO文件的話,寫(xiě)法如下
add_library( natave-lib  #設(shè)置庫(kù)的名稱(chēng)。另一個(gè)so文件的名稱(chēng)
                SHARED  # 將庫(kù)設(shè)置為共享庫(kù)。
                src/main/jni/nataveJni.cpp    # 提供一個(gè)源文件的相對(duì)路徑
              )
target_link_libraries( natave-lib     #指定目標(biāo)庫(kù)中。與 add_library的庫(kù)名稱(chēng)一定要相同
                       ${log-lib}    # 將目標(biāo)庫(kù)鏈接到日志庫(kù)包含在NDK。
                        )     

6.在模塊的build.gradle文件中添加

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.0"
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
Paste_Image.png

7.編寫(xiě)Java中的Native方法

    public native  String getStr();
    public native  String gethelloJniStr();

8.生成C的頭文件

Paste_Image.png

生成后

Paste_Image.png

9.編寫(xiě)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");
}
Paste_Image.png

至此,這個(gè)項(xiàng)目就可以運(yùn)行了

更多的學(xué)習(xí)

Paste_Image.png
(1) .externalNativeBuild文件夾:用于存放cmake編譯好的文件,包括支持的各種硬件等信息,有點(diǎn)類(lèi)似于build.gradle文件明確Gradle如何編譯APP;
(2) cpp文件夾:存放C/C++代碼文件,native-lib.cpp文件默認(rèn)生成的;
(3) CMakeLists.txt:cmake腳本配置文件,cmake會(huì)根據(jù)該腳本文件中的指令去編譯相關(guān)的C/C++源文件,并將編譯后產(chǎn)物生成共享庫(kù)或靜態(tài)塊,然后Gradle將其打包到APK中。

CMakeLists.txt文件解析如下:

# 指定cmke版本  
cmake_minimum_required(VERSION3.4.1)  
# add_library()命令用于向CMake添加依賴(lài)源文件或庫(kù)  
# 指令需傳入三個(gè)參數(shù)(函數(shù)庫(kù)名稱(chēng)、庫(kù)類(lèi)型、依賴(lài)源文件相對(duì)路徑)  
add_library(  # 生成函數(shù)庫(kù)的名稱(chēng),即libnative-lib.so或libnative-lib.a(lib和.so/.a默認(rèn)缺省)  
             native-lib  
             # 生成庫(kù)類(lèi)型:動(dòng)態(tài)庫(kù)為SHARED,靜態(tài)庫(kù)為STATIC  
             SHARED  
             # 依賴(lài)的c/cpp文件(相對(duì)路徑)  
             src/main/cpp/native-lib.cpp )  
# find_library()命令用于定位NDK中的庫(kù)  
# 需傳入兩個(gè)參數(shù)(path變量、ndk庫(kù)名稱(chēng))  
find_library(  # 設(shè)置path變量的名稱(chēng),這里為NDK中的日志庫(kù)  
              log-lib  
                            #指定cmake查詢(xún)庫(kù)的名稱(chēng)  
                            #即在ndk開(kāi)發(fā)包中查詢(xún)liblog.so函數(shù)庫(kù),將其路徑賦值給log-lib  
              log )  
#target_link_libraries()命令用于指定要關(guān)聯(lián)到的原生庫(kù)的庫(kù)  
target_link_libraries(# 指定目標(biāo)庫(kù),與上面指定的函數(shù)庫(kù)名一致  
                  native-lib  
                  # 鏈接的庫(kù),根據(jù)log-lib變量對(duì)應(yīng)liblog.so函數(shù)庫(kù)  
                  ${log-lib} )  
通過(guò)查看native-lib.cpp方法,stringFromJNI目的是向Java層返回一個(gè)字符串。如果要在native-lib.cpp文件中添加新的方法,必須添加在extern"C" { } 中,或者在每個(gè)方法前加extern"C", 否則會(huì)報(bào)找不到方法。如果源文件為C,則須將extern“C”部分去掉,因?yàn)閑xtern "C"的作用就是告訴編譯器以C方式編譯。

JNI開(kāi)發(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);
Paste_Image.png

Android系統(tǒng)目前支持的CPU架構(gòu)

ARMv5,ARMv7 (從2010年起)
x86 (從2011年起)
MIPS (從2012年起)
ARMv8,MIPS64和x86_64 (從2014年起)
每一個(gè)CPU架構(gòu)對(duì)應(yīng)一個(gè)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)選項(xiàng),將創(chuàng)建以基于ARM* v5TE 的設(shè)備為目標(biāo)的庫(kù)。 具有這種目標(biāo)
的浮點(diǎn)運(yùn)算使用軟件浮點(diǎn)運(yùn)算。 使用此ABI(二進(jìn)制接口)創(chuàng)建的二進(jìn)制代碼將可以
在所有 ARM*設(shè)備上運(yùn)行。所以armeabi通用性很強(qiáng)。但是速度慢
armeabi-v7a:創(chuàng)建支持基于ARM* v7 的設(shè)備的庫(kù),并將使用硬件FPU指令。
armeabi-v7a是針對(duì)有浮點(diǎn)運(yùn)算或高級(jí)擴(kuò)展功能的arm v7 cpu。
mips:MIPS是世界上很流行的一種RISC處理器。MIPS的意思是“無(wú)內(nèi)部互鎖流水級(jí)
的微處理器”(Microprocessor without interlocked piped stages),其機(jī)
制是盡量利用軟件辦法避免流水線中的數(shù)據(jù)相關(guān)問(wèn)題。
x86:支持基于硬件的浮點(diǎn)運(yùn)算的IA-32 指令集。x86是可以兼容armeabi平臺(tái)運(yùn)行
的,無(wú)論是armeabi-v7a還是armeabi,同時(shí)帶來(lái)的也是性能上的損耗,另外需要
指出的是,打包出的x86的so,總會(huì)比armeabi平臺(tái)的體積更小。
總結(jié)
如果項(xiàng)目只包含了 armeabi,那么在所有Android設(shè)備都可以運(yùn)行;
如果項(xiàng)目只包含了 armeabi-v7a,除armeabi架構(gòu)的設(shè)備外都可以運(yùn)行; 
如果項(xiàng)目只包含了 x86,那么armeabi架構(gòu)和armeabi-v7a的Android設(shè)備是無(wú)法
運(yùn)行的;
如果同時(shí)包含了 armeabi,armeabi-v7a和x86,所有設(shè)備都可以運(yùn)行,程序在運(yùn)
行的時(shí)候去加載不同平臺(tái)對(duì)應(yīng)的so,這是較為完美的一種解決方案,同時(shí)也會(huì)導(dǎo)致
包變大。

我的CSDN博客地址:http://blog.csdn.net/wo_ha/article/details/78131635

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容