JNI和NDK程式設計知識點
總結歸納JNI和NDK相關的知識點。
JNI和NDK程式設計
版本:2018/3/18-1(11:36
JNI和NDK簡介
1、JNI是什麼?作用?
- Java Native Interface(java本地介面)
- 方便
Java
呼叫C、C++
等原生代碼所封裝的一層介面
2、為什麼需要JNI?
java
特點是跨平臺
,但是會導致本地互動能力
不夠強大,一些作業系統相關特性
Java是無法完成的-因此Java
提供JNI
專門用於和原生代碼互動,依次增強本地互動能力
- 可以使用現有的開源庫,現在很多優秀的開源庫都是用 C/C++ 編寫的。
- 程式碼的保護,Android apk 的 java 程式碼容易被反編譯,而 C/C++ 更難反編譯。
- 便於移植,用 C/C++ 寫的庫可以方便在其他嵌入式平臺使用。
3、NDK是什麼?
NDK
是Android所提供的工具集合
- 通過
NDK
可以在Android中更加方便地通過JNI
來訪問原生代碼,如C\C++
NDK
還提供交叉編譯器
,只需要簡單地修改mk檔案
就可以生成特定CPU平臺的動態庫
4、NDK的優點
- 提高程式碼的安全性—so庫反編譯比較困難
- 可以方便地使用目前已有的
C/C++開源庫
- 便於平臺間的移植—通過
C/C++
實現的動態庫可以很方便在其他平臺上使用- 提高程式在某些特定情況下的執行效率,但並不能明顯提升Android程式的效能。
5、AS3.0如何整合JNI功能
- AS3.0中下載NDK,CMake(高階的編譯配置工具),LLDB(高效的C/C++的偵錯程式)
- Java的native方法,通過javah生成對應的標頭檔案
- 編寫C/C++程式碼
- CMakeList檔案進行配置
6、cpp程式碼中JNIEXPORT
和JNICALL
關鍵字的作用?
- 這兩個關鍵字是兩個
巨集定義
- 用於說明該函式為
JNI函式
, Java虛擬機器載入的時候會連結對應的native方法
7、Java虛擬機器載入so庫時,如何找到Java層中對應的hative方法?(靜態註冊)
- 通過
JNI函式的函式名
去匹配:Java_PackageName_ClassName_NativeMethodName
- 可以在
app/build/intermediates/classes/debug
通過javah -d jni 包名.類名
在debug目錄下
生成jni目錄(-d jni引數指定)
,並在其中生成對應的H標頭檔案
8、自動生成的JNI函式中的引數jobject
是什麼?
- 當前和該JNI函式所連線的native方法所屬的類物件(等價於Java中的this)
9、JNI的動態註冊是什麼?
- 靜態註冊native方法的過程,是將
Java層的native方法
和JNI函式
一一對應- 動態註冊能讓
Java層的native方法
和任意JNI函式
連線起來。
10、JNI進行動態註冊的步驟
- Java中定義
native函式
- C/C++中定義對應的
JNI函式(名稱隨意不需要對應)
- C/C++中定義
JNINativeMethod的資料
—指明多組native函式和JNI函式對應關係
- C/C++中的
JNI_OnLoad()
中進行動態註冊
public class JniUtils2 {
static {
System.loadLibrary("native-lib");
}
public native String getStringFromC();
public native void dynamicFunction();
public native void dynamicFunction2();
}
#include "com_hao_jniapp_JniUtils2.h"
#include "android/log.h"
extern "C" {
JNIEXPORT jstring JNICALL Java_com_hao_jniapp_JniUtils2_getStringFromC
(JNIEnv *env, jobject jobject1) {
return env->NewStringUTF("我是來自JniUtils2的Native方法");
}
// 6. JNI函式(Java層的native方法的具體實現)
static void jniDynamicLog(JNIEnv *evn, jobject obj){
__android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: hello Java! Im from JNI");
}
static void jniTest(JNIEnv *evn, jobject obj){
__android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: hello Java! Im from JNI's Test");
}
/**==========================
* 7. JNINativeMethod結構體:記錄java的native方法和JNI函式的對應關係
*==========================*/
JNINativeMethod nativeMethod[] = { {"dynamicFunction", //1. Java層native方法的方法名
"()V", //2. Java層native方法的描述符
(void*)jniDynamicLog} //3. JNI函式的指標
,{"dynamicFunction2", "()V", (void*)jniTest} //4. 另一個繫結關係的native/jni
};
/**===========================================================
* 1. JNI_OnLoad會在Java中的`System.loadLibarary()`載入so庫的時候呼叫
* @param jvm *jvm為Java虛擬機器例項,JavaVM為一個結構體。
*==========================================================*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
JNIEnv *env;
//2. *jvm呼叫GetEnv()會獲得JNIEnv變數
if (jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
__android_log_print(ANDROID_LOG_INFO, "feather", "JNI's Log: JNI_OnLoad...");
//3. JNIEnv結構體指向一個函式表, 獲取到JniUtils物件
jclass clz = env->FindClass("com/hao/jniapp/JniUtils2");
//4. 將JniUtils物件和nativeMethod結構體所描述的Java層native方法和JNI函式 進行動態註冊
env->RegisterNatives(clz, nativeMethod, sizeof(nativeMethod)/sizeof(nativeMethod[0]));
//5. return 當前使用的JNI版本
return JNI_VERSION_1_4;
}
}
11、JNINativeMethod的作用
- 作為一個結構體,描述了native方法和JNI函式的繫結關係
typedef struct {
const char* name;//Java層native方法的名字
const char* signature;//Java層native方法的描述符
void* fnPtr;//對應JNI函式的指標
} JNINativeMethod;
12、JNIEnv結構體的作用
- 指向一個
函式表
,該函式表
指向一系列JNI函式
- 通過這些
JNI函式
就能夠實現呼叫Java層的程式碼
//1. 獲取到Java物件中某個變數的ID
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
//2. 根據變數的ID獲取到資料型別為boolean的變數
jboolean GetBooleanField(jobject obj, jfieldID fieldID)
//3. 獲取到Java物件中對應方法的ID
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
//4. 根據方法ID去呼叫對應物件中的方法,且該方法返回void
CallVoidMethod(jobject obj, jmethodID methodID, ...)
//5. 根據方法ID去呼叫對應物件中的方法,且該方法返回boolean
CallBooleanMethod(jobject obj, jmethodID methodID, ...)
13、JNI資料型別的作用
- Java層和C/C++的資料型別和物件不能直接相互引用和使用。
- C/C++的指標對於Java就是無法識別的。
- 綜上:JNI層定義了自己的資料型別以達到銜接的作用。
14、JNI中有哪幾種資料型別?
- JNI的資料型別分為兩種:基本型別和引用型別
15、JNI的原始資料型別
Java Type | Native Typ | Description |
---|---|---|
boolean | jboolean | unsigned 8 bits |
byte | jbyte | signed 8 bits |
char | jchar | unsigned 16 bits |
short | jshort | signed 16 bits |
int | jint | signed 32 bits |
long | jlong | signed 64 bits |
float | jfloat | 32 bits |
double | jdouble | 64 bits |
void | void | N/A |
16、JNI引用型別?
- JNI定義了一些引用型別來便於
JNI層
呼叫
jobject (all Java objects)
|
|-- jclass (java.lang.Class objects)
|-- jstring (java.lang.String objects)
|-- jarray (array)
| |--jobjectArray (object arrays)
| |--jbooleanArray (boolean arrays)
| |--jbyteArray (byte arrays)
| |--jcharArray (char arrays)
| |--jshortArray (short arrays)
| |--jintArray (int arrays)
| |--jlongArray (long arrays)
| |--jfloatArray (float arrays)
| |--jdoubleArray (double arrays)
|
|--jthrowable
17、JNI中的方法ID和變數ID的作用?
- 如果要在在JNI中去呼叫
Java層的某個方法
,首先需要獲取它的ID,再根據ID通過JNI函式去獲得該方法。
//變數ID
struct _jfieldID;
typedef struct _jfieldID *jfieldID;
//方法ID
struct _jmethodID;
typedef struct _jmethodID *jmethodID; /* method IDs */
18、JNI中類描述符的作用
- 用於去獲取Java的物件。
- 例如
com.hao.jniapp.JniUtils2
這是該類所屬於的包。需要更換為com/hao/jniapp/JniUtils2
-這就是類的描述符(FindClass("com/hao/jniapp/JniUtils2")
中常用)。
3.
19、方法描述符?
- 就是用於確定
native
方法的引數和返回值。- “()V”中“V”表示返回值為空
- “()V”中“()”標識為引數
Method Descriptor | Java Language Type |
---|---|
“()Ljava/lang/String;” | String f(); |
“(ILjava/lang/Class;)J” | long f(int i, Class c); |
“([B)V” | String(byte[] bytes); |
20、資料型別描述符
Field Desciptor | Java Language Type |
---|---|
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | floa |
D | double |
21、陣列描述符
- 一位陣列的描述符是“[+對應的型別描述符”
- 二維和三維陣列,以”[[“和“[[[”開頭,更多維陣列類似
Descriptor | Java Langauage Type |
---|---|
“[[I” | int[][] |
“[[[D” | double[][][] |
Field Desciptor | Java Language Type |
---|---|
“Ljava/lang/String;” | String |
“[Ljava/lang/Object;” | Object[] |
22、JNI函式中呼叫Java的靜態方法
- Java層的native方法所在類編寫一個一般方法
- C/C++的檔案中編寫函式,引數需要有(JNIEnv *env, jobject thiz),在內部去獲得Java層方法並呼叫。
- 在C/C++的JNI函式中去呼叫上者的方法。
//JniUtils2.Java
public class JniUtils2 {
static {
System.loadLibrary("native-lib");
}
...
//1. 靜態方法
public static void staticShowMsg(String msg){
Log.i("feather", "I'm Java Static method: get JNI's msg =" + msg);
}
}
//xxx.cpp
void callJavaMethod(JNIEnv *env, jobject thiz){
//1. 獲取到Java的class
jclass clazz = env->FindClass("com/hao/jniapp/JniUtils2");
if(clazz == NULL){
printf("find class JniUtils2 error!");
return;
}
//2. 獲取到方法ID
jmethodID id = env->GetStaticMethodID(clazz, "staticShowMsg", "(Ljava/lang/String;)V");
if(id == NULL){
printf("find method staticShowMsg error!");
}
//3. 呼叫該靜態方法並傳入引數
jstring msg = env->NewStringUTF("Hello Java! I'm JNI message");
env->CallStaticVoidMethod(clazz, id, msg);
}
23、JNI函式中呼叫Java的非靜態方法
重點是通過JNIEnv非靜態方法去呼叫,並且需要將對應的Java物件的this作為引數傳入。
//java
public class JniUtils2 {
static {
System.loadLibrary("native-lib");
}
...
public void showMsg(String msg){
Log.i("feather", "I'm Java method: get msg =" + msg + "from JNI");
}
}
void callAnothorJavaMethod(JNIEnv *env, jobject thiz){
jclass clazz = env->FindClass("com/hao/jniapp/JniUtils2");
if(clazz == NULL){
printf("find class JniUtils error!");
return;
}
//1. 獲取非靜態方法的ID
jmethodID id = env->GetMethodID(clazz, "showMsg", "(Ljava/lang/String;)V");
if(id == NULL){
printf("find method showMsg error!");
}
jstring msg = env->NewStringUTF("Hello Java! I'm JNI message");
//2. 重點是需要將代表JniUtils2物件的this指標(`jobject thiz`)
env->CallVoidMethod(thiz, id, msg);
}
參考書籍
相關推薦
JNI和NDK程式設計知識點
總結歸納JNI和NDK相關的知識點。 JNI和NDK程式設計 版本:2018/3/18-1(11:36 JNI和NDK簡介 1、JNI是什麼?作用? Java Native Interface(java本地介面) 方便
Android JNI和NDK學習(09)--JNI實例二 傳遞類對象
get state 回調 obj utf 說明 called [] code 1 應用層代碼 NdkParam.java是JNI函數的調用類,它的代碼如下: package com.skywang.ndk; import android.app.Activity;
JNI和NDK
roi 代碼 strong car net develop eve 場景 目的 摘:https://blog.csdn.net/carson_ho/article/details/73250163 JNI介紹定義:Java Native Interface,即 Java
淺學JNI和NDK
介紹 c++ google 什麽 為什麽 文章內容 特點 文件 view 作者:十歲的小男孩 QQ:929994365 心之安處即是吾鄉 前言 本文試圖通過解答以下三個問題來達到學習JNI和NDK的目的。是什麽?有什麽用?怎麽用?文章內容前三節來自下面第一個鏈接的博主共
JNI和NDK開發(1)_建立JNI程式
開始學習JNI開發技術,在網上看了很多文章,但講解的都是基礎或者過時的技術,沒有系統的關於JNI和NDK的學習教程,現在我寫《JNI和NDK開發》系列文章,主要是記錄自己從零開始學習遇到的一些問題和知識點,希望對大家也有些幫助。對於文章,本人也是邊學邊寫, 所以可能會更新的慢一點
JNI和NDK學習(1)--搭建開發環境
文章轉自我的Github Blog CommonQ's Blog NDK簡介 NDK的好處: 1. 程式碼的保護,由於apk的java層程式碼很容易被反編譯,而C/C++庫反匯難度較大。 2. 在NDK中呼叫第三方C/C++庫,因為大部分的開源庫都是用C/C++程式碼編
Android JNI和NDK學習(03)--動態方式實現JNI
前面總結了靜態實現JNI的方法,本文介紹如何動態實現JNI:JNI在載入時,會呼叫JNI_OnLoad,而解除安裝時會呼叫JNI_
【專案知識點彙總】二、JNI程式碼編譯方式camke 和 ndk 方式 -- Android Studio 操作
一、介紹 Android Studio 編譯JNI程式碼有兩種方式:cmake 和 ndk 方式 使用感受: 1、cmake方式會受到所用Android sdk版本的影響,主要是ndk的版本影響,沒有深入去探究原理 2、ndk方式可以跨Android sdk 版本執行
Android之SDK、NDK、JNI和so檔案
1. SDK Android SDK(AndroidSoftware Development Kit),即Android軟體開發工具包,Android的SDK基於Java實現,這意味著基於Android
Android NDK程式設計: JNI技巧
前言: 這篇文章是android官方文件(https://developer.android.com/training/articles/perf-jni), 講的非常贊. 有很多最佳實踐, 比如儲存classid/methodid, 管理執行緒, cpp和java執行緒互動, 異常UTF編碼, 最
java工作筆記:web 程式設計中關於jni和jna兩種工具操作和效能對比測試
第一次發部落格有點緊張哈。 最近剛剛公司轉崗從底層C語言的編寫到做Java的web restful架構。其中需要呼叫底層C++程式碼庫。所以對於選擇哪種方法從Java呼叫C的程式碼做了簡單地學習和對比測試。在這裡把他們貼出了。希望能有大神出來指點
在android studio下配置gradle用ndk-build和ndk-gbd編譯除錯JNI
因為要在舊版android在做一些工作。所以做用到了它。目標平臺是:android api 10和armv6. 開發環境是:AS
關於echarts、layer.js和jqGrid的知識點
spa params h+ item getdate 正則 math grid 參數 使用echarts和layer.js直接去官方文檔,能解決大部分問題。 但是有些問題,解釋不夠清楚,在這裏記錄一下。 1、echarts的使用 第一點:關於echarts的lab
android studio使用CMake和NDK,實現應用自身被卸載時打開某一網址
licensed 項目 右鍵 ava 開發工具 not per 2.0 idt 實現應用自身被卸載時打開某一網址的c代碼 MyActivity: public class MyActivity extends Activity { /** * Calle
用隊列和棧的知識點解決迷宮問題
margin 是否 port 迷宮 中一 post 左右 als info 迷宮問題 這裏有一個迷宮如圖所示,求走出迷宮的路徑 這裏我們建一個二維列表,表示迷宮(0表示通道,1表示圍墻)。 maze = [ [1,1,1,1,1,1,1,1,1,1],
Linux常用命令和Shell程式設計基礎
目錄相關 cd - .與.. 分別表示當前目錄和父目錄 - ~與$HOME 都是指當前使用者的主目錄 - cd – 切換到上一次所在的目錄(不一定是父目錄) pwd - pwd 顯示當前目錄 - $PWD與$OLDPWD 兩個變量表示當前目錄和上一次所在的目錄 ls - ls -rtl 檢視
網路程式設計知識點剖析
網路程式設計知識點剖析 一. C/S 架構: Client / Server 客戶端 / 服務端 B/S 架構: Browser / Server 前端 / 服務端 二.網路程式設計通訊流程. 網絡卡 mac地址 IP地址 子網掩碼
正則表示式和re模組知識點彙總
"\^":匹配字元的開始"\$":匹配字元的結尾"[]":字元組"[^a]":如果在字元組中以^開頭,就是除了a不匹配,其他的都匹配"a|b":匹配字元a或b 注意:使用或關係的時候,要把長規則放在短規則的前面"()"分組,需要對一個整體匹配規則量詞約束的,就對整體匹配規則加一個括號字串最前面加上r 就是不
C和指標--程式設計題9.14第10小題--判斷迴文函式
題目: 編寫函式 int palindrom( char *string); 如果引數字串是個迴文,函式就返回真,否則就返回假。迴文就是指一個字串從左向右讀和從右向左讀是一樣的。函式應忽略所有的非字母字元,而且在進行字元比較時不用區分大小寫。 前提是空白字元、標點符號和大小寫狀態被忽略,當Adam
快樂程式設計大本營【java語言訓練班】 6課:用java的物件和類程式設計
快樂程式設計大本營【java語言訓練班】 6課:用java的物件和類程式設計 第1節. 什麼是物件和類 第2節. 物件的屬性和方法 第3節. 類的繼承 第4節. 使用舉例:建立類,定義方法,定義屬性 第5節. 使用舉例:建立物件,屬性賦值與使用,方法呼叫; 第6節. 使用舉例:類繼承及物件使用 地址如下