一.什么是JNI
JNI java本地开发接口
JNI 是一个协议
这个协议用来沟通java代码和外部的本地代码(c/c++).
通过这个协议,java代码就可以调用外部的c/c++代码
外部的c/c++代码也可以调用java代码
二.JNI在Android中的应用
1.创建一个android工程
2.JAVA代码中写声明native 方法 public native String helloFromJNI();
3. 创建jni目录,编写c代码,方法名字要对应 (在目下D:\Android-code\androidJNI\bin\classes 执行 javah com.example.androidjni.MainActivity 会自动把native方法的签名)
#include<stdio.h>
#include<jni.h>
jstring Java_com_example_androidjni_MainActivity_hellofronc( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "你好,中国 !");
}
JNIEnv 类型代表了java环境 通过JNIEnv* 指针,就可以对java端的代码进行操作.
创建java类的对象,调用java对象的方法
获取java对象的属性 等等.
jobject是个什么
jobject obj 就是当前方法所在的类代表的对象.
添加参数的jni中函数形式:
public native String hellofronc(int k,String m);
JNIEXPORT jstring JNICALL Java_com_example_androidjni_MainActivity_hellofronc
(JNIEnv *, jobject, jint, jstring);
4.编写Android.mk文件(交叉编译器在编译c或c++依赖的配置文件,是linux下makefile的子集)
LOCAL_PATH := $(call my-dir)//指明Android.mk文件所在的目录
include $(CLEAR_VARS)//重新变量的初始化,不会LOCAL_PATH的初始化
LOCAL_MODULE := hello//就是你要生成的库的名字,名字要是唯一的这个.不能有空格.
LOCAL_SRC_FILES := hello.c
include $(BUILD_SHARED_LIBRARY)//编译后生成的库的类型
解释mk文件:
Android.mk 的含义
LOCAL_PATH:=$(call my-dir)
LOCAL_PATH是定义源文件在哪个目录用的.
my-dir 是个定义的宏方法, $(call my-dir)就是调用这个叫 my-dir的宏方法,这个方法返回值就是
Android.mk文件所在的目录
include $(CLEAR_VARS)
CLEAR_BARS 变量是build system里面的一个变量
这个变量指向了所有的类似 LOCAL_XXX的变量,
执行完这一句话, 这个编译系统就把 所有的类似
LOCAL_MODULE,_SRC_FILELOCALS,LOCAL_STATIC_LIBRARIES,...这样的变量都清除掉
但是不会清除掉 LOCAL_PATH
LOCAL_MODULE 就是你要生成的库的名字,名字要是唯一的这个.不能有空格.
编译后系统会自动在前面加上lib的头, 比如说我们的Hello 就编译成了libHello.so
还有个特点就是如果你起名叫libHello 编译后ndk就不会给你的module名字前加上lib了
但是你最后调用的时候 还是调用Hello这个库
LOCAL_SRC_FILES = :Hello.c
这个是指定你要编译哪些文件
不需要指定头文件 ,引用哪些依赖, 因为编译器会自动找到这些依赖 自动编译
include $(BUILD_SHARED_LIBRARY) BUILD_STATIC_LIBRARY
.so
编译后生成的库的类型,如果是静态库.a 配置include $(BUILD_STATIC_LIBRARY)
别的参数
LOCAL_CPP_EXTENSION := cc //指定c++文件的扩展名
LOCAL_MODULE := ndkfoo
LOCAL_SRC_FILES := ndkfoo.cc
LOCAL_LDLIBS += -llog -lvmsagent -lmpnet -lmpxml -lH264Android
//指定需要加载一些别的什么库.
5.Ndk编译生成动态库
可以看到,生成的so文件是根据mk文件中的LOCAL_MODULE变量来的
在命令行界面下进入项目中,然后,把ndk-build。Cmd拖进去即
当然,本步骤也可以用cygwin,进入到当前项目,跳入ndk-build 即可自动编译
6.Java代码load 动态库.调用native代码
static {
System.loadLibrary("hello");
}
三。C语言代码调用java中的代码
JNIEXPORT void JNICALL Java_cn_itcast_ndkcallback_DataProvider_callmethod1
(JNIEnv * env, jobject obj){
//在c代码里面调用java代码里面的方法
// java 反射
//1 . 找到java代码的 class文件
// jclass (*FindClass)(JNIEnv*, const char*);
jclass dpclazz = (*env)->FindClass(env,"cn/itcast/ndkcallback/DataProvider");
if(dpclazz==0){
LOGI("find class error");
return;
}
LOGI("find class ");
//2 寻找class里面的方法
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID method1 = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");//此时,需要参数 用到javap
if(method1==0){
LOGI("find method1 error");
return;
}
LOGI("find method1 ");
//3 .调用这个方法
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,obj,method1);
}
最后,推荐两本好书给大家哈,下面是地址,先领券,后购买,会便宜奥!https://uland.taobao.com/coupon/edetail?e=uT89QV1g7g
ya2P%2BN2ppgB5cGJKb3z7oyZ
JjmQv1Olyz2%2BDoRKonRyxpBwAz9u2FrKDPRlXjRi6f
s1DLi40cq9wPbfjxGQb3QoUC34ijeiBuSkJ3%2F5GrL5G
jok%2BNtmjPde0i8zdmiYU6Uxnri0Lv2FLICkDE4TS6i
&pid=mm_53591275_19054502_66630155&af=1
https://uland.taobao.com/coupon/edetail?e=sYglM1DSXfCa2P%2
BN2ppgB5cGJKb3z7oyZJjmQv1Olyz2%2BDoRKonRyxpBwAz9u2Frg5Ll3kyilbL
NMCZJtgR2owPbfjxGQb3QoUC34ijeiBuSkJ3%2F5GrL5Gjok%2BNtm
jPde0i8zdmiYU6Uxnri0Lv2FLICkDE4TS6i
&pid=mm_53591275_19054502_66630155&af=1
https://uland.taobao.com/coupon/edetail?e=Y94CbAJDtEma2P%2BN2ppgB5cGJKb
3z7oyZJjmQv1Olyz2%2BDoRKonRyxpBwAz9u2Fr0Qg%2F3FJJw
tEpbmtMowugZwPbfjxGQb3QoUC34ijeiBuSkJ3%2F5G
rL5Gjok%2BNtmjPde0i8zdmiYU6Uxnri0Lv2FLI
CkDE4TS6i&pid=mm_53591275_19054502_66630155&af=1
https://uland.taobao.com/coupon/edetail?e=4nLtqN68D2ma2P%2B
N2ppgB5cGJKb3z7oyZJjmQv1Olyz2%2BDoRKonRyxpBwAz9u2FrbNbG1
6cAURcGQK8mHc179QPbfjxGQb3QoUC34ijeiBuSkJ3%2F5GrL5Gjok%2
BNtmjPde0i8zdmiYU6Uxnri0Lv2FLICkDE4TS6i
&pid=mm_53591275_19054502_66630155&af=1