1-安卓底层-基础

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
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 实现方式有何不一样
  1. 第二种有入口函数 可以对jni 做一些初始化工作

  2. 第二种方式是通过 jninativemethod 这个结构体来匹配的

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

实现接口文件

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 

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;
}

签名类型

1-安卓底层-基础_第1张图片

两者之间的数据类型

1-安卓底层-基础_第2张图片


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

“`

include

你可能感兴趣的:(安卓底层)