JNI在Android Studio2.2中基本配置和使用
-
what?
-
JNI
Java Native Interface 它允許Java代碼和其他語言寫的代碼進行交互。JNI 是本地編程接口,它使得在 Java 虛擬機 (VM) 內部運行的 Java 代碼能夠與用其它編程語言(如 C、C++ 和匯編語言)編寫的應用程序和庫進行交互操作。
由于Android的應用層的類都是以Java寫的,這些Java類編譯為Dex型式的Bytecode之后,必須靠Dalvik虛擬機(VM: Virtual Machine)來執行。 -
NDK
Native Develop Kit(本地開發工具包),類似于JDK;只是一套工具,它可以幫助開發者在android開發中,它使用的是JNI機制. -
兩者的區別
JNI Java Native Interface java調用本地接口 的技術名詞
NDK Native Developer Kit 谷歌給開發人員的工具包
-
-
使用ndkBuilder進行項目的構建
-
下載ndk(已裝,略過)
ndk下載.png
進入項目設置界面
20160531123154969.png
沒有安裝的話,直接Download即可,PS.在最終安裝的時候會卡很長時間,耐心等待安裝完成
-
配置app,build.gradle文件
- 在app的build.gradle中,也就是要運行的項目中的build.gradle文件中的defaultConfig節點中增加
ndk { moduleName "NdkJniDemo" //生成的so名字 ldLibs "log", "z", "m" //添加依賴庫文件,因為有log打印等//非必填加項 abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結構下的so庫,目前可有可無。//不填寫則生成所有 }
-
創建本地需要創建調用C的代碼,這里使用一個獲取字符串的方法為例
-
新建一個工具類JniUtils,使用C獲取一個字符串,然后展示到一個
public class JniUtils { public static native String getStringFormC(); ...可以有很多的native代碼 }
-
生成.h,C/C++的頭文件(熟悉C的知道,可以沒有頭文件,頭文件只是定義類中所有方法(C中沒有類的概念))
-
build或rebuild或clear一下程序之后,會在build/intermediates/classes/debug目錄中生成項目中的所有的class文件,
class文件路徑.png
2. 命令行進入debug目錄cd <路徑>
- 編譯指令</code></pre>
javah -jni com.wobiancao.ndkjnidemo.ndk.JniUtils
注意 這里javah -jni后面跟的是JniUtils類的全路徑,如果javah報不存在之 類的,是你的java環境沒有配置好。
-
編譯過后會在debug目錄下生成一個.h的文件,它的命名方式會很長,基本 是全路徑的命名方式
jonathanhsia_com_ndktest_utils_JniUtils.h -
拷貝文件到項目中的main/jni目錄下,如果沒有直接創建即可
-
編寫C的方法實現
-
在jni目錄下新建C/C++文件,引用頭文件,復寫其中的java要調用的C/C++方法,返回一個字符串,
-
-
在JniUtils中靜態導入C/C++所生成的so包
static { System.loadLibrary("NdkJniDemo");//之前在build.gradle里面設置的so名字,必須一致 }
此時run之后java代碼即可以調用到用C/C++實現的代碼了
</ol>
- C/C++不能格式化代碼,否則會出現,編譯通過(可能編譯出錯,但是沒有阻止運行),運行不了,報出找不到so包的異常
- 首次run的時候可能報出
Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
- 不支持intant run
- 兩個c同時實現h中的方法,會報錯,不允許,邏輯上也是不允許;
- JniUtils的位置不能夠隨便已經,因為和C/C++文件中是一一對應的引用關系
-
1.當勾選了include C++ Support時,在創建項目的時候,會多出如上界面,選擇C/C++的標準,此處的設置在app的build.gradle中的defaultConfig會增加設置
externalNativeBuild {
}</code></pre> </li> </ul>cmake { cppFlags "-frtti -fexceptions"http://這個標記是第一個選項,如果使用C++11的標準,則使用 //cppFlags "-std=c++11" }
-
2.在build.gradle中的android節點下面會增加配置,指定生成so文件配置文件的路徑
externalNativeBuild { cmake {
} }</code></pre> </li> </ul>path "CMakeLists.txt"
-
3.創建需要調用C/C++代碼的java代碼,和ndkBuilder相同
public class JniUtils { public static native String getStrFromC2(); }
- 4.在項目中src/main/中創建cpp目錄,里面可以直接的創建cpp源代碼,和ndkBuild一樣,用C/C++所寫的源代碼中的方法名稱必須是全路徑的方法名,然后以Java開頭,分割使用下劃線.
#include <jni.h> #include <string>
-
-
"PS. 在run之后,會在build/intermediates/ndk/debug/lib目錄下會出現在build.gradle中配置的三中cpu架構的so包,此時刪除jni目錄中的源碼,將這些so包直接的拷入到項目中就可以直接的使用了"
遇到的坑
使用cmake進行項目的構建
* **1.cmake編輯功能是android studio 2.2才支持的新功能;目的是簡化jni的開發過程,使用studio2.2新建項目的話,會有相應的讓你勾選使用cmake**
1474439172560.png
1474439229866.png
extern "C" jstring Java_com_ndkcmaketestapp_utils_JniUtils_getStrFromC2(JNIEnv *env, jobject thiz) { std::string hello = "Hello from C++ Two!"; return env->NewStringUTF(hello.c_str()); }</code></pre>
-
5.CMakeLists.txt文件中的具體配置
cmake_minimum_required(VERSION 3.4.1) #指定cmake版本 add_library(form SHARED src/main/cpp/form.cpp) #hello是生成的so文件的名稱,要和cpp文件的名稱相同 target_link_libraries(hello log android) # 此處增加了,日志的鏈接庫
-
6.在java代碼中增加引用so庫的代碼,使代碼生效
public class JniUtils {
// Used to load the 'native-lib' library on application startup. static { System.loadLibrary("form");//此處的form庫的名稱需要和CMakeLists.txt中配置的相同 } public static native String getStrFromC2(); }</code></pre> </li> </ul>
-
7.在run成功之后,會在build目錄的上方增加.externalNativeBuild目錄,其中.externalNativeBuild/cmake/debug/obj包含所有生成的so包,同樣的拷貝到項目中的jniLibs就可以直接的使用
CMake的優勢
- 1.可以直接的在C/C++代碼中加入斷點,進行調試
- 2.java引用的C/C++中的方法,可以直接 ctrl+左鍵 進入
- 3.對于include的頭文件,或者庫,也可以直接的進入
- 4.不需要配置命令行操作,手動的生成頭文件,不需要配置 android.useDeprecatedNdk=true 屬性
來自:http://www.jianshu.com/p/3cc045829bb6
-
-
-
- 在app的build.gradle中,也就是要運行的項目中的build.gradle文件中的defaultConfig節點中增加