更新了Android Studio版本之后挂捻,在按照之前的方式搭建JNI的開發(fā)環(huán)境吃挑,發(fā)現(xiàn)不斷的報錯,通過查看日志發(fā)現(xiàn)羊初,android.useDeprecatedNdk不再支持了讓滨溉,使用CMake or ndk-build。本文介紹了在低版本和高版本上分別怎么實現(xiàn)长赞,以及總結(jié)在搭建過程中遇到的錯誤和解決辦法晦攒。
Android Studio 2.2版本以下
1.首先通過SDKManager-SDK Tools下載NDK插件
2.在local.properties文件里面配置NDK路徑:
一種方式是在該文件中直接填寫NDK的路徑
另一種方式是在SDK Location里面配置:在項目上右鍵->選擇open Moulde Settings
3.在在gradle.properties文件中追加下面代碼:
android.useDeprecatedNdk=true
4.使用native關(guān)鍵字編寫JNI接口
public class JNIUtils {
public static native String getStringFromC();
}
編寫之后,make project得哆,在工程目build\intermediates\classes\debug\自己的包名下就可以看到編譯后的class文件JNIUtils.class如下圖所示:
5.使用javah命令生成.h頭文件
5.1 打開Terminal脯颜,然后在命令行中先進入到工程的build\intermediates\classes\debug目錄下(cd 直接拖拽debug目錄即可)
5.2 輸入命令:javah 包名.類名
javah com.bysj.myapplication.JNIUtils
在debug目錄下就會生成對應(yīng)的頭文件(.h文件)
6. 實現(xiàn)上述頭文件里面的方法
6.1 在main目錄下新建jni文件夾
6.2 將上述的頭文件復(fù)制進來,文件名可以隨意該贩据,但是內(nèi)容不能改栋操。
6.3 新建一個c或者c++源文件實現(xiàn)頭文件中的方法,并在源文件中引入頭文件(此處我自己建立的是C++的文件)
#include "com_bysj_jniapplication_JNIUtils.h" //頭文件的名字要對應(yīng)
JNIEXPORT jstring JNICALL Java_com_bysj_jniapplication_JNIUtils_getStringFromC
(JNIEnv *env, jclass) {
return env -> NewStringUTF("Hello from C++");
}
7. 添加NDK配置
7.1 開發(fā)app內(nèi)build.gradle乐设,在android/defaultConfig下面添加ndk配置
android {
讼庇。。近尚。蠕啄。。戈锻。
defaultConfig {
歼跟。。格遭。哈街。。拒迅。
ndk {
moduleName "JNISample" //生成so庫的名字
}
}
buildTypes {
骚秦。她倘。。作箍。硬梁。。
}
}
7.2 加載so庫胞得,在JNIUtils類中添加以下的代碼:
public class JNIUtils {
static {
System.loadLibrary("JNISample");//名字要與build.gradle中配置的一致
}
public native static String getStringFromC();
}
最后編譯運行荧止,可以看到結(jié)果:
以上是在AS2.2版本以下這樣做會成功,但是在2.2以后在編譯的時候會報以下的錯誤:
我們仔細看下Log阶剑,大概意思就是說:
- android.useDeprecatedNdk不再支持了
- 讓使用CMake or ndk-build
- 然后還有鏈接
考慮使用CMake或ndk構(gòu)建集成跃巡。要了解更多信息,請訪問:
https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile
首先牧愁,您可以使用Android的ndk構(gòu)建腳本示例插件為您生成:
/Users/apple/Desktop/AndroidJNITest/app/build/intermediates/ndk/debug/Android.mk
或者素邪,你可以使用實驗插件:
https://developer.android.com/r/tools/experimental-plugin.html
繼續(xù)使用已棄用的NDK編譯60天,設(shè)置在gradle.properties
android.deprecatedNdkCompileLease = 1523416167903(這個測試不起作用)
經(jīng)過各種查資料递宅,發(fā)現(xiàn)原來在gradle3.0以上以前這種方法不再支持
所以在AS2.2版本以后進行NDK開發(fā)要使用CMake娘香,下面演示以下具體的實現(xiàn)方法(你會發(fā)現(xiàn)很簡單,省去類很多的事)
Android Studio 2.2版本以上
1. 先通過SDKManager下載:CMake和LLDB
2.在新建項目的時候勾選 Include C++ Support
接下來的步驟跟創(chuàng)建普通項目一樣办龄。
2.1 配置C++支持功能(Customize C++ Support)在Customize C++ Support界面默認即可烘绽。
-
C++ Standard
指定編譯庫的環(huán)境,其中Toolchain Default使用的是默認的CMake環(huán)境俐填;C++ 11也就是C++環(huán)境安接。兩種環(huán)境都可以編庫,至于區(qū)別英融,后續(xù)會跟進盏檐,當前博文使用的是CMake環(huán)境。
-
Exceptions Support
如果選中復(fù)選框驶悟,則表示當前項目支持C++異常處理胡野,如果支持,在項目Module級別的build.gradle文件中會增加一個標識 -fexceptions到cppFlags屬性中痕鳍,并且在so庫構(gòu)建時硫豆,gradle會把該屬性值傳遞給CMake進行構(gòu)建。
-
Runtime Type Information Support
同理笼呆,選中復(fù)選框熊响,項目支持RTTI,屬性cppFlags增加標識-frtti
點擊完成诗赌,Android Studio會自動把JIN開發(fā)的環(huán)境搭建好汗茄,可以直接運行,比起低版本的是不是省很多事懊簟洪碳!
勾選了 Include C++ Support以后递览,會自動在build.gradle中添加以下配置
android {
compileSdkVersion 27
defaultConfig {
。偶宫。非迹。环鲤。纯趋。。冷离。吵冒。
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt" //該文件用于配置JNI項目屬性
}
}
}
3.CMakeLists.txt文件說明
CMakeLists.txt文件用于配置JNI項目屬性,主要用于聲明CMake使用版本西剥、so庫名稱痹栖、C/CPP文件路徑等信息,下面是該文件內(nèi)容:
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
# 設(shè)置so文件名稱
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# 設(shè)置這個so文件為共享.
# file are automatically included.
src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
-
cmake_minimum_required(VERSION 3.4.1)
CMake最小版本使用的是3.4.1瞭空。add_library()
配置so庫信息(為當前當前腳本文件添加庫)native-lib
這個是聲明引用so庫的名稱揪阿,在項目中,如果需要使用這個so文件咆畏,引用的名稱就是這個南捂。值得注意的是,實際上生成的so文件名稱是libnative-lib旧找。當Run項目或者build項目是溺健,在Module級別的build文件下的intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main
下會生成相應(yīng)的so庫文件。* SHARED
這個參數(shù)表示共享so庫文件钮蛛,也就是在Run項目或者build項目時會在目錄intermediates\transforms\mergeJniLibs\debug\folders\2000\1f\main
下生成so庫文鞭缭。此外,so庫文件都會在打包到.apk里面魏颓,可以通過選擇菜單欄的Build->Analyze Apk...*查看apk中是否存在so庫文件岭辣,一般它會存放在lib目錄下。src/main/cpp/native-lib.cpp
構(gòu)建so庫的源文件甸饱。
STATIC:靜態(tài)庫沦童,是目標文件的歸檔文件,在鏈接其它目標的時候使用柜候。
SHARED:動態(tài)庫搞动,會被動態(tài)鏈接,在運行時被加載渣刷。
MODULE:模塊庫鹦肿,是不會被鏈接到其它目標中的插件,但是可能會在運行時使用dlopen-系列的函數(shù)動態(tài)鏈接辅柴。
更詳細的解釋請參考這篇文章:C++靜態(tài)庫與動態(tài)庫
-
頭文件
也可以配置頭文件路徑箩溃,方法是(注意這里指定的是目錄而非文件):
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
下面的配置實際上與自定義的JNI項目(自定義的so庫)沒有太大關(guān)系瞭吃。
find_library()
這個方法與我們要創(chuàng)建的so庫無關(guān)而是使用NDK的Apis或者庫,默認情況下Android平臺集成了很多NDK庫文件涣旨,所以這些文件是沒有必要打包到apk里面去的歪架。直接聲明想要使用的庫名稱即可(猜測:貌似是在Sytem/libs目錄下)。在這里不需要指定庫的路徑霹陡,因為這個路徑已經(jīng)是CMake路徑搜索的一部分和蚪。如示例中使用的是log相關(guān)的so庫。log-lib
這個指定的是在NDK庫中每個類型的庫會存放一個特定的位置烹棉,而log庫存放在log-lib中log
指定使用log庫target_link_libraries()
如果你本地的庫(native-lib)想要調(diào)用log庫的方法攒霹,那么就需要配置這個屬性,意思是把NDK庫關(guān)聯(lián)到本地庫浆洗。native-lib
要被關(guān)聯(lián)的庫名稱${log-lib}
要關(guān)聯(lián)的庫名稱催束,要用大括號包裹,前面還要有$符號去引用伏社。
實際上抠刺,我們可以自己創(chuàng)建CMakeLists.txt文件,而且路徑不受限制摘昌,只要在build.gradle中配置externalNativeBuild.cmake.path來指定該文件路徑即可速妖。
說明
AS2.2版本以后不會再創(chuàng)建jin文件夾,而創(chuàng)建的是cpp文件夾
總結(jié)
Android Studio2.2以上版本進行JNI開發(fā)第焰,只需要在新建項目的時候勾選 Include C++ Support選項买优,AS會自動幫我們搭建好JNI開發(fā)環(huán)境,我們只需要改成我們需要的文件名即可挺举。相比低版本的各種配置杀赢,是簡單方便了很多。