JNI的开发流程
基于Android studio 2.0 的JNI开发流程
HelloJni
- 需求:点击一个按钮,Toast从c代码中打印出来的”HelloJni”字符串.
布局就不作赘述了,下面开始具体实现步骤:
关键字native声明一个本地方法,具体内容交给c来实现.
public native String helloFromC(); public void click(View view){ Toast.makeText(this, helloFromC(), Toast.LENGTH_SHORT).show(); }
在module的 build.gradle 中 defaultConfig 内添加ndk.
ndk{ moduleName "hello" //指定最终生成库名,但是最终生成的动态链接库的文件名是libhello.so }
同步之后如果出现报错,点击setXXX, as会在gradle.properties自动添加android.useDeprecatedNdk=true.
在调用本地方法的类中通过静态代码块加载动态库,指定库名
static { System.loadLibrary("hello");//指定库名加载动态库 }
缺少生成库的源码, 需要在模块中new一个jni Folder文件夹,默认在main目录下. 在jni文件夹下新建hello.c源文件,并且创建它的hello.h头文件
在hello.c源文件中按要求实现本地方法相应函数
#include "hello.h" //“ ”双引号包含的头文件系统会优先在当前目录下查找 //如果没找到,再去系统头文件目录找 #include <jni.h> //提供java和c的基本类型及引用类型的对应关系,声明数据转换方法 /** * 本地方法相应的函数名:Java_包名_类名_本地方法名 * 本地方法虽然没有参数, 但是对应到本地方法的函数至少需要两个参数 * 参数1 JNIEnv *env jni环境,调用转换数据方法 * 参数2 jobject obj 调用本地方法类的对象 */ // String helloFromC();写作以下形式 jstring Java_com_example_jnidemo_MainActivity_helloFromC(JNIEnv *env, jobject obj){ char buf[] = "hello from c!"; //还记得上一篇中提到的 //JNIEnv : struct JNINativeInterface* //env : JNIEnv * <=> struct JNINativeInterface* * return (*env)->NewStringUTF(env, buf); //jstring (*NewStringUTF)(JNIEnv*, const char*); }
- gradle同步, make module, 完成. 总体来说以上步骤跟eclipse开发不一样,不需要配置 Android.mk文件.
javah自动生成本地方法相应的函数声明
- 以上Demo是手动生成本地方法相应的函数名, 如果本地方法过多或者命名过于复杂,手写容易出错.
打开Terminal窗口, 在main/java文件夹和com的同层目录中执行
\main\java>javah -classpath . -d ../jni com.example.jnidemo.MainActivity