JNI在Android Studio2.2中基本配置和使用

  • what?

    1. JNI
      Java Native Interface 它允許Java代碼和其他語言寫的代碼進行交互。JNI 是本地編程接口,它使得在 Java 虛擬機 (VM) 內部運行的 Java 代碼能夠與用其它編程語言(如 C、C++ 和匯編語言)編寫的應用程序和庫進行交互操作。
      由于Android的應用層的類都是以Java寫的,這些Java類編譯為Dex型式的Bytecode之后,必須靠Dalvik虛擬機(VM: Virtual Machine)來執行。

    2. NDK
      Native Develop Kit(本地開發工具包),類似于JDK;只是一套工具,它可以幫助開發者在android開發中,它使用的是JNI機制.

    3. 兩者的區別
      JNI Java Native Interface java調用本地接口 的技術名詞
      NDK Native Developer Kit 谷歌給開發人員的工具包

  • 使用ndkBuilder進行項目的構建

  • 下載ndk(已裝,略過)

ndk下載.png

 

進入項目設置界面

20160531123154969.png

沒有安裝的話,直接Download即可,PS.在最終安裝的時候會卡很長時間,耐心等待安裝完成

  1. 配置app,build.gradle文件

    1. 在app的build.gradle中,也就是要運行的項目中的build.gradle文件中的defaultConfig節點中增加
      ndk {
           moduleName "NdkJniDemo"   //生成的so名字
           ldLibs "log", "z", "m"    //添加依賴庫文件,因為有log打印等//非必填加項
           abiFilters "armeabi", "armeabi-v7a", "x86" //輸出指定三種abi體系結構下的so庫,目前可有可無。//不填寫則生成所有
       }
    </li> </ol>
    1. 創建本地需要創建調用C的代碼,這里使用一個獲取字符串的方法為例

    2. 新建一個工具類JniUtils,使用C獲取一個字符串,然后展示到一個

      public class JniUtils {
        public static native String getStringFormC();
        ...可以有很多的native代碼
      }
      使用native關鍵字,表示調用本地的方法,該方法可以使用C/C++語言來實現
    1. 生成.h,C/C++的頭文件(熟悉C的知道,可以沒有頭文件,頭文件只是定義類中所有方法(C中沒有類的概念))

      1. build或rebuild或clear一下程序之后,會在build/intermediates/classes/debug目錄中生成項目中的所有的class文件,

      </li> </ol>

      class文件路徑.png

      2. 命令行進入debug目錄cd <路徑>

      1. 編譯指令</code></pre>
        javah -jni com.wobiancao.ndkjnidemo.ndk.JniUtils

        注意 這里javah -jni后面跟的是JniUtils類的全路徑,如果javah報不存在之 類的,是你的java環境沒有配置好。

        1. 編譯過后會在debug目錄下生成一個.h的文件,它的命名方式會很長,基本 是全路徑的命名方式
          jonathanhsia_com_ndktest_utils_JniUtils.h

        2. 拷貝文件到項目中的main/jni目錄下,如果沒有直接創建即可

        1. 編寫C的方法實現

          1. 在jni目錄下新建C/C++文件,引用頭文件,復寫其中的java要調用的C/C++方法,返回一個字符串,

          </li>
        2. 在JniUtils中靜態導入C/C++所生成的so包

          static {
            System.loadLibrary("NdkJniDemo");//之前在build.gradle里面設置的so名字,必須一致
          }

          此時run之后java代碼即可以調用到用C/C++實現的代碼了

        3. </ol>

          "PS. 在run之后,會在build/intermediates/ndk/debug/lib目錄下會出現在build.gradle中配置的三中cpu架構的so包,此時刪除jni目錄中的源碼,將這些so包直接的拷入到項目中就可以直接的使用了"

          遇到的坑

          1. C/C++不能格式化代碼,否則會出現,編譯通過(可能編譯出錯,但是沒有阻止運行),運行不了,報出找不到so包的異常
          2. 首次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.
            這樣的錯誤,按照里面的提示在gradle.properties文件中增加android.useDeprecatedNdk=true字段即可
          3. 不支持intant run
          4. 兩個c同時實現h中的方法,會報錯,不允許,邏輯上也是不允許;
          5. JniUtils的位置不能夠隨便已經,因為和C/C++文件中是一一對應的引用關系

          使用cmake進行項目的構建

          * **1.cmake編輯功能是android studio 2.2才支持的新功能;目的是簡化jni的開發過程,使用studio2.2新建項目的話,會有相應的讓你勾選使用cmake**

          1474439172560.png

          1474439229866.png

          • 1.當勾選了include C++ Support時,在創建項目的時候,會多出如上界面,選擇C/C++的標準,此處的設置在app的build.gradle中的defaultConfig會增加設置

            externalNativeBuild {
            
               cmake {
                   cppFlags "-frtti -fexceptions"http://這個標記是第一個選項,如果使用C++11的標準,則使用
                   //cppFlags "-std=c++11"
               }
            
            }</code></pre> </li> </ul>
            • 2.在build.gradle中的android節點下面會增加配置,指定生成so文件配置文件的路徑

              externalNativeBuild {
                 cmake {
              
                 path "CMakeLists.txt"
              
              } }</code></pre> </li> </ul>
              • 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>

        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 屬性
            </li> </ul>

             

             

            來自:http://www.jianshu.com/p/3cc045829bb6

             

 本文由用戶 MackGoforth 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!