1-安卓底層--基礎(chǔ)

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)方式有何不一樣
  1. 第二種有入口函數(shù) 可以對jni 做一些初始化工作

  2. 第二種方式是通過 jninativemethod 這個結(jié)構(gòu)體來匹配的

  3. 第一種是靠名字匹配的

實現(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;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄 第一章 介紹第二章 設(shè)計機(jī)制第三章 JNI類型和數(shù)據(jù)結(jié)構(gòu)第四章 JNI函數(shù)(1)第四章 JNI函數(shù)(2)第四...
    駱駝騎士閱讀 3,733評論 1 9
  • 目錄 第一章 介紹第二章 設(shè)計機(jī)制第三章 JNI類型和數(shù)據(jù)結(jié)構(gòu)第四章 JNI函數(shù)(1)第四章 JNI函數(shù)(2)第四...
    駱駝騎士閱讀 3,743評論 0 4
  • 前言 人生苦多,快來 Kotlin ,快速學(xué)習(xí)Kotlin! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,686評論 9 118
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,641評論 18 399
  • 2017/06/06(五月十二日)夜,晴 據(jù)電視上介紹,今年全國有940萬名考生大戰(zhàn)明天的高考。數(shù)字驚人,隊...
    木貞ma閱讀 272評論 3 1

友情鏈接更多精彩內(nèi)容