JNI開發與NDK開發的基本流程

上一篇文章主要講解有關JNI和NDK開發過程中需要理解的基本的知識,想要了解的,請移步https://blog.csdn.net/qq_36451275/article/details/95347000

開發:

一、JNI原生開發流程(Eclipse)

   (1)基本流程

       1.在java類中定義native方法

       2.生成包含對應JNI函數聲明的頭文件

       3.實現生成的JNI的函數

       4.藉助NDK編譯生成動態鏈接庫文件(.so)

       5. 在Java類中加載動態連接庫並調用native的方法

       6. 運行安裝到ARM模擬器上

(2)詳細流程

1. 在Java類中定義native方法

在Activity類中聲明: public native String helloJNI();

2. 生成包含對應JNI函數聲明的頭文件

1). 在命令行窗口中執行: javah Activity全類名(在src下執行)

說明有的電腦可能會提示GBK的不可映射字符: 添加 -encoding utf-8

2). 在src下會生成一個頭文件: com_atguigu_hellojni_MainActivity.h

3). 頭文件中包含一個native方法對應的JNI函數聲明(需要後面實現):

JNIEXPORT jstring JNICALL Java_com_atguigu_hellojni_MainActivity_helloJNI(JNIEnv *, jobject)

3. 實現生成的JNI函數

1). 在應用下創建一個文件夾: jni

2). 將剛纔生成的頭文件複製到此文件夾下

3). 創建一個c文件來實現生成的JNI函數聲明: test.c

#include "com_atguigu_hellojni_MainActivity.h"

JNIEXPORT jstring JNICALL Java_com_atguigu_hellojni_MainActivity_helloJNI

(JNIEnv * env, jobject jobj) {

 

return (*env)->NewStringUTF(env, "Hello from C");

}

4. 藉助NDK編譯生成動態鏈接庫文件(.so)

1). 解壓NDK包, 配置NDK文件夾到path(不能包含空格)

2). 藉助NDK下的文檔(ANDROID-MK.html)編寫用於編譯的文件(jni/Android.mk)

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := hello-jni #指定生成的so文件的唯一標識

LOCAL_SRC_FILES := test.c #指定包含JNI函數的c文件名

include $(BUILD_SHARED_LIBRARY)

3). 在命令行窗口中進入應用根目錄, 執行ndk-build命令, 生成so動態鏈接庫文件

so文件路徑: /libs/armeabi/libhello-jni.so

5. 在Java類中加載動態連接庫並調用native的方法

1). 在靜態代碼塊中加載so文件:

static {

System.loadLibrary("hello-jni");

}

2). 調用native方法:

String result = helloJNI();

6. 運行安裝到ARM模擬器上

(3)補充說明

JNIEXPORT :

在Jni編程中所有本地語言實現Jni接口的方法前面都有一個"JNIEXPORT",這個可以看做是Jni的一個標誌,至今爲止沒發現它有什麼特殊的用處。

JNICALL :

這個可以理解爲Jni 和Call兩個部分,和起來的意思就是 Jni調用XXX(後面的XXX就是JAVA的方法名)。

二、NDK集成開發流程(Eclipse)

  (1)基本流程

   1. 安裝配置NDK

   2. 將NDK關聯到eclipse

   3. 爲當前應用自動生成c文件和mk文件

   4. 定義naitve方法

   5. 實現native方法對應的JNI函數

   6. 一錘編譯生成so文件

   7. 加載動態庫, 並調用native方法

   8. 運行應用安裝到ARM模擬器上

(2)詳細流程

1. 安裝配置NDK

1). 解壓NDK的zip包到非中文目錄

2). 配置path : 解壓後NDK的根目錄----->ndk-build

2. 將NDK關聯到eclipse

Window-->Preferences-->Android-->NDK-->配置NDK的根目錄

3. 爲當前應用自動生成c文件和mk文件

1). 選中當前應用右鍵-->Android Tools-->Add Native Support

2). 將生成的.cpp文件改爲.c文件

3). 修改mk文件: 將.cpp改爲.c

4. 配置關聯jni.h (見"配置關聯jni.h文件"截圖)

1). 選中當前應用右鍵-->Properties-->C/C++ General-->Paths and Symbols

2). 選擇add-->選擇File System-->選擇文件夾android-ndk-r9\platforms\android-18\arch-arm\usr\include

3). 點擊ok-->點擊apply

5. 定義naitve方法

public native String helloNDK();

6. 實現native方法對應的JNI函數

1). 使用javah命令, 生成JNI頭文件, 將其複製到jni文件下

2). 在c文件中實現h文件中的函數聲明

3). 利用* 的NewStringUTF()函數, 返回字符串

7. 一錘編譯生成so文件

1). 使用工具欄中的"Build"工具點擊錘子按鈕生成

2). 文件路徑: /libs/armeabi/libNDKTest.so

8. 加載動態庫, 並調用native方法

static {

System.loadLibrary("NDKTest");

}

String result = helloNDK();

9. 運行應用安裝到ARM模擬器上

(3)補充說明

   1.修改C函數, 不需要再單獨編譯生成so文件, 可直接運行安裝

   2.APK只是將so打包了, 本質並不需要jni文件夾下的相關文件

   3.多平臺交叉編譯:arm、intel、mips

1>. 參照NDK文檔: APPLICATION-MK.html

2>. 在jni文件夾下創建: Application.mk

APP_ABI := all

3>. 編譯時會生成多個so文件來支持不同類型的CPU

4>. 不同CPU的說明

armeabi: 是指的該so庫用於ARM的通用CPU,armeabi通用性強,但速度

armeabi-v7a: CPU支持硬件浮點運算, 能充分發揮v7a CPU的能力,

x86: 用於Intel的CPU

mips : 另一種CPU, 用得特別少

   4.Android.mk詳細介紹

#必須定義好LOCAL_PATH變量。它用於在開發樹中查找源文件

#宏函數’my-dir’,由編譯系統提供,用於返回當前路徑(包含c/c++文件)

LOCAL_PATH := $(call my-dir)

#清除除LOCAL_PATH之外的LOCAL_XXX變量

#CLEAR_VARS由編譯系統提供

include $(CLEAR_VARS)

#以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的

#編譯會產生的鏈接庫文件(lib+名稱+.so): libtest2-jni.so

LOCAL_MODULE := test2-jni

#指定將要編譯打包進模塊中的C或C++源代碼文件

#如果有多個, 以空格隔開

LOCAL_SRC_FILES := test2.c

#編譯生成動態庫(也就是.so文件)

include $(BUILD_SHARED_LIBRARY)

#編譯生成靜態庫(也就是.a文件)

#include $(BUILD_STATIC_LIBRARY)

(4)重要配置

   1.編寫Android.mk

   2.配置關聯jni.h文件

 

 

 

 

 

 

   3.編寫Application.mk

三、NDK集成開發流程(Android Studio)

1. 安裝配置NDK

1). 解壓NDK的zip包到非中文目錄

2). 配置path : 解壓後NDK的根目錄----->ndk-build

 

2. 給AS配置關聯NDK

1). local.properties中添加配置

ndk.dir=G\:\\android-ndk-r10

2). gradle.properties中添加配置

android.useDeprecatedNdk=true

 

3. 編寫native方法:

public class JNIS {

public native String helloJNI();

}

 

4. 定義對應的JNI

1). 在main下創建jni文件夾

2). 生成native方法對應的JNI函數聲明頭文件: 命令窗口中, 進入java文件夾

執行命令: javah com.atguigu.jnitests2.JNIS

生成頭文件: com_atguigu_jnitests2_JNIS.h

函數聲明: JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI(JNIEnv *, jobject);

3). 將生成的頭文件轉移到jni文件夾下

4). 在jni下定義對應的函數文件: test.c

#include "com_atguigu_jnitests2_JNIS.h"

JNIEXPORT jstring JNICALL Java_com_atguigu_jnitests2_JNIS_helloJNI

(JNIEnv * env, jobject jobj) {

return (*env)->NewStringUTF(env, "Hello from C");

}

5). 在jni文件夾下創建一個空的C文件: empty.c

說明: 這是AS的bug, 必須至少2個C文件才能通過編譯

 

5. 指定編譯的不同CPU

defaultConfig {

ndk{

moduleName "HelloJni" //so文件: lib+moduleName+.so

abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的類型

}

}

6. 編譯生成不同平臺下的動態鏈接文件

1). 執行rebuild, 生成so文件

2). so文件目錄: build\intermediates\ndk\debug\lib\.....

7. 調用native方法:

1). 在native方法所在的類中加載so文件

static {

System.loadLibrary("HelloJni");

}

2). 在Activity中調用native方法:

String result = new JNIS().helloJNI();

Log.e("TAG", "result="+result);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章