1-安卓底層--基礎(chǔ)
先看看代碼: java 調(diào)用 C/C++ 代碼
1.TestJni.java
public class TestJni{
static{
System.loadLibrary("xxx"); //加載 libxxx.so 庫文件
}
public native void hello(); //本地方法,在so文件里實現(xiàn)
public static void main (String [] args){
TestJni d = new TestJni();
d.hello(); //調(diào)用庫文件里面的hello方法
}
}
2.編譯java程序 javac TestJni.java 生成 TestJni.class
3.通過javah生成jni接口 javah TestJni 生成 TestJni.h
4.新建xxx.c 文件 然后實現(xiàn)接口
#include<jni.h>
JNIEXPORT void JNICALL Java_TestJni_hello(JNIEnv * env, jobject obj){
printf("hello world\n");
}
5.編譯成so庫文件 ( linux 動態(tài)庫命名規(guī)則 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.指定動態(tài)庫的路徑 export LD_LIBRARY_PATH=:
7.運(yùn)行java TestJni
* jni.h 在編譯android源碼時要安裝jdk 5.0之前 直接下載甲骨文的jdk 5.0之后 要安裝openjdk (sudo apt-get install openjdk+版本)注意 android 和jdk的版本有對應(yīng)關(guān)系(android 官網(wǎng))
* Java_TestJni_hello 接口的名字 命名規(guī)則 Java_+類名_+本地方法名 接口的返回值和方法的返回值一致
* JNIEnv jni總管 他是一個函數(shù)指針數(shù)組的首地址 成員為函數(shù)指針 jobject java對象
第二種
第二種方式的jni實現(xiàn)
vi /usr/lib/jvm/java-7-openjdk-amd64/include/linux/jni.h
1. 完成入口函數(shù)
1944 JNIEXPORT jint JNICALL
1945 JNI_OnLoad(JavaVM *vm, void *reserved);
2. 在入口函數(shù)里面實現(xiàn) 一下三步
2.1 獲得java虛擬機(jī)環(huán)境
jint (JNICALL *GetEnv)(JavaVM *vm, void **penv, jint version);
2.2 找到先關(guān)的類
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 這個結(jié)構(gòu)體 作用是本地方法和本地函數(shù)的映射關(guān)系
180 typedef struct {
181 char *name; //本地方法的名字
182 char *signature; // 本地方法的簽名
183 void *fnPtr; // 相對應(yīng)的本地函數(shù)
184 } JNINativeMethod;
函數(shù)簽名通常是以下結(jié)構(gòu):
- 返回值 fun(參數(shù)1,參數(shù)2,參數(shù)3);
- 其對應(yīng)的Jni方法簽名格式為:(參數(shù)1參數(shù)2參數(shù)3) 返回值
- 注意:
- 函數(shù)名,在Jni中沒有體現(xiàn)出來
- 參數(shù)列表相挨著,中間沒有逗號,沒有空格
- 返回值出現(xiàn)在()后面
- 如果參數(shù)是引用類型,那么參數(shù)應(yīng)該為:L類型;
第一種jni 和第二種jni 實現(xiàn)方式有何不一樣
第二種有入口函數(shù) 可以對jni 做一些初始化工作
第二種方式是通過 jninativemethod 這個結(jié)構(gòu)體來匹配的
第一種是靠名字匹配的
實現(xiàn)接口文件
1 實現(xiàn)JNI_OnLoad 函數(shù)
2 是在入口函數(shù)里面獲得jvm 環(huán)境變量 通過 GetEnv 這個函數(shù)
3 找類 findclass();
4 注冊 RegisterNatives method 這個結(jié)構(gòu)體
5 實現(xiàn) method 這個結(jié)構(gòu)體 讓java的本地方法 和 jni的本地函數(shù)綁定在一起
寫法
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);
}
//函數(shù)數(shù)組 ,
//參數(shù)1 java 里寫的本地方法名
//參數(shù)2 簽名(看下面的圖)頭文件里自動生成
//參數(shù)3 調(diào)用的函數(shù)的指針
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;
//注冊函數(shù)
(*env) -> RegisterNatives(env,cls,method,sizeof(method)/sizeof(JNINativeMethod));
return JNI_VERSION_1_4;
}
簽名類型
簽名類型.PNG
兩者之間的數(shù)據(jù)類型
兩者之間的數(shù)據(jù)類型.PNG
java傳數(shù)組
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
#include <jni.h>
jint Jhello(JNIEnv *env,jobject obj,jintArray arr,jint num){
jint *carr;
jint i, sum = 0;
carr = (*env)->GetIntArrayElements(env, arr, NULL);
if (carr == NULL)return 0;
for (i=0; i<num; i++) sum += carr[i];
(*env)->ReleaseIntArrayElements(env, arr, carr, 0);
return sum;
}
JNINativeMethod method[] = {
(char *)"hello",(char *)"([II)I",(void *)Jhello,
};
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved){
JNIEnv *env;
jclass cls;
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2)) {
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_2;
}