1-安卓底層–基礎
先看看代碼: java 調用 C/C++ 代碼
1.TestJni.java
public class TestJni{
static{
System.loadLibrary("xxx"); //加載 libxxx.so 庫文件
}
public native void hello(); //本地方法,在so文件裏實現
public static void main (String [] args){
TestJni d = new TestJni();
d.hello(); //調用庫文件裏面的hello方法
}
}
2.編譯java程序 javac TestJni.java
生成 TestJni.class
3.通過javah生成jni接口 javah TestJni
生成 TestJni.h
4.新建xxx.c 文件 然後實現接口
#include<jni.h>
JNIEXPORT void JNICALL Java_TestJni_hello(JNIEnv * env, jobject obj){
printf("hello world\n");
}
5.編譯成so庫文件 ( linux 動態庫命名規則 lib + 庫名 + .so window 庫名+.dll )
gcc -shared -fPIC xxx.c -o libxxx.so -I /usr/lib/jvm/java-7-openjdk-amd64/include/
* -I 指定頭文件的路徑 -L 指定庫的路徑 -l更上名字 -lm -lsqlite3
6.指定動態庫的路徑 export LD_LIBRARY_PATH=:
7.運行java TestJni
* jni.h 在編譯android源碼時要安裝jdk 5.0之前 直接下載甲骨文的jdk 5.0之後 要安裝openjdk (sudo apt-get install openjdk+版本
)注意 android 和jdk的版本有對應關係(android 官網)
* Java_TestJni_hello 接口的名字 命名規則 Java_+類名_+本地方法名 接口的返回值和方法的返回值一致
* JNIEnv jni總管 他是一個函數指針數組的首地址 成員爲函數指針 jobject java對象
第二種
第二種方式的jni實現
vi /usr/lib/jvm/java-7-openjdk-amd64/include/linux/jni.h
1. 完成入口函數
1944 JNIEXPORT jint JNICALL
1945 JNI_OnLoad(JavaVM *vm, void *reserved);
2. 在入口函數裏面實現 一下三步
2.1 獲得java虛擬機環境
jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
2.2 找到先關的類
jclass (JNICALL *FindClass)
226 (JNIEnv *env, const char *name);
* (*env)->FindClass(env, "java/lang/String")
2.3 註冊
720 jint (JNICALL *RegisterNatives)
721 (JNIEnv *env, jclass clazz, const JNINativeMethod *methods,jint nMethods);
完成 JNINativeMethod 這個結構體 作用是本地方法和本地函數的映射關係
180 typedef struct {
181 char *name; //本地方法的名字
182 char *signature; // 本地方法的簽名
183 void *fnPtr; // 相對應的本地函數
184 } JNINativeMethod;
函數簽名通常是以下結構:
- 返回值 fun(參數1,參數2,參數3);
- 其對應的Jni方法簽名格式爲:(參數1參數2參數3) 返回值
- 注意:
- 函數名,在Jni中沒有體現出來
- 參數列表相挨着,中間沒有逗號,沒有空格
- 返回值出現在()後面
- 如果參數是引用類型,那麼參數應該爲:L類型;
第一種jni 和第二種jni 實現方式有何不一樣
第二種有入口函數 可以對jni 做一些初始化工作
第二種方式是通過 jninativemethod 這個結構體來匹配的
第一種是靠名字匹配的
實現接口文件
1 實現JNI_OnLoad 函數
2 是在入口函數裏面獲得jvm 環境變量 通過 GetEnv 這個函數
3 找類 findclass();
4 註冊 RegisterNatives method 這個結構體
5 實現 method 這個結構體 讓java的本地方法 和 jni的本地函數綁定在一起
寫法
TestJni.java
public class TestJni{
static {
System.loadLibrary("native");
}
public native int hello(int i,char j);
public static void main (String [] args){
TestJni d = new TestJni();
d.hello(12,'r');
}
}
native.c
#include <jni.h>
jint Jhello(JNIEnv *env,jobject obj,jint i,jchar j){
printf("%d\t%c\n",i,j);
}
//函數數組 ,
//參數1 java 裏寫的本地方法名
//參數2 簽名(看下面的圖)頭文件裏自動生成
//參數3 調用的函數的指針
JNINativeMethod method[] = {
"hello","(IC)I",(void *)Jhello,
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env;
jclass cls;
if((*vm) -> GetEnv(vm,(void **)&env,JNI_VERSION_1_4))
return JNI_ERR;
cls = (*env) ->FindClass(env,"TestJni");
if(cls == NULL) return JNI_ERR;
//註冊函數
(*env) -> RegisterNatives(env,cls,method,sizeof(method)/sizeof(JNINativeMethod));
return JNI_VERSION_1_4;
}
簽名類型
兩者之間的數據類型
java傳數組
TestJni.java
public class TestJni{
static {
System.loadLibrary("native");
}
public native int hello(int []arr,int len);
public static void main (String [] args){
int []ibo = {12,13,14,15};
TestJni d = new TestJni();
System.out.println(d.hello(ibo,ibo.length));
}
}
native.c
“`