记录JNI编程有关知识点

注册JNI函数有两种方法:静态注册和动态注册
1.静态注册:比较常见也比较麻烦
- 先创建 Java 类,声明Native方法,编译成.class文件。 
- 使用Javah命令生成C/C++的头文件,例如:javah -jni com.devilwwj.jnidemo.TestJNI,则会生成一个以.h为后缀的文件
- 创建.h对应的源文件.c/.cpp,然后实现对应的native方法
2.动态注册:实现动态注册就必须实现 JNI_OnLoad 方法,这个是JNI的一个入口函数,我们在Java层通过System.loadLibrary加载完动态库后,紧接着就会去查找一个叫JNI_OnLoad的方法。如果有,就会调用它,而动态注册的工作就是在这里完成的。在这里我们会去拿到JNI中一个很重要的 结构体JNIEnv ,env指向的就是这个结构体,通过env指针可以找到指定类名的类,并且调用JNIEnv的RegisterNatives方法来完成注册native方法和JNI函数的对应关系。
Java  Native函数和JNI函数时一一对应的,JNI中就有一个叫JNINativeMethod的结构体来保存这个对应关系,实现动态注册方就需要用到这个结构体。JNINativeMethod可以存放所有要实现的Native方法。结构体如下:
typedef struct { const char* name; //Java层的函数名 const char* signature; void* fnPtr; //Native层的函数指针} JNINativeMethod;
signature 字段的取值,实际上这些字符与函数的参数类型/返回类型一一对应,其中"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void func(),"(II)V" 表示 void func(int, int),具体的每一个字符的对应关系如下:
字符     Java类型     C/C++类型
V           void          void
Z         jboolean      boolean
I            jint            int
J           jlong          long
D         jdouble       double
F          jfloat          float
B          jbyte          byte
C          jchar           char
S          jshort         short
 
数组则以"["开始,用两个字符表示:
字符     java类型          c/c++类型
[Z     jbooleanArray      boolean[]
[I        jintArray            int[]
[F       jfloatArray         float[]
[B      jbyteArray          byte[]
[C      jcharArray          char[]
[S      jshortArray         short[]
[D     jdoubleArray       double[]
[J        jlongArray          long[]
上面的都是基本类型,如果参数是Java类,则以"L"开头,以";"结尾,中间是用"/"隔开包及类名,而其对应的C函数的参数则为jobject,一个例外是String类,它对应C类型jstring,例如:Ljava/lang /String; 、Ljava/net/Socket; 等,如果JAVA函数位于一个嵌入类(也被称为内部类),则用$作为类名间的分隔符,例如:"Landroid/os/FileUtils$FileStatus;"。

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = NULL;
jint result = JNI_ERR;
int mySize;
char func[] = "JNI_OnLoad";
int fd=0;
if (vm == NULL) {
return JNI_ERR;
}

if (vm->GetEnv((void **)&env, JNI_VERSION_1_4))
return JNI_ERR;
iac_init();
jclass myClass = env->FindClass("com/xxx/xxx/xxx/xxx");

if (myClass != NULL) {

mySize = sizeof(gUpgradeFunction) / sizeof(gUpgradeFunction[0]);

result =
env->RegisterNatives((jclass) myClass, gUpgradeFunction,
mySize);

if (result < 0) {
LOGD("%s, %s, Register fuction failed, result = %d\n",
JACModule4, func, result);
}
else
LOGD("Register function done");

}
LOGD("JNI_OnLoad Done.");
return JNI_VERSION_1_4;
}

打印log
#include <android/log.h>

#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

android.mk
LOCAL_PATH := $(call my-dir) //返回当前目录的路径
include $(CLEAR_VARS) //清除一些变量的值,但是LOCAL_PATH除外。
LOCAL_LDLIBS :=-llog //必须放在include $(CLEAR_VARS) 后面
LOCAL_MODULE := TestNdk //指定当前待编译模块的名称
LOCAL_SRC_FILES := com_example_testndk_JniClient.c //编译的源文件
include $(BUILD_SHARED_LIBRARY)

其他:
LOCAL_CFLAGS := 主要是引用外部的C头文件, -I 是头文件的存放路径,如果该头文件和我们自己的源文件放在同一级目录,则不需要配置;
LOCAL_LDLIBS := 是引用外部库文件,-L是指定该lib文件的存放路径
LOCAL_C_INCLUDES:额外的C/C++编译头文件路径,用LOCAL_PATH表示本文件所在目录,像gcc的-I参数。如:LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_CC:另外指定c编译器,不使用默认的。
L OCAL_LDFLAGS:这个编译变量传递给链接器一个一些额外的参数,比如想传递而外的库和库路径给ld,或者传递给ld linker的一些链接参数,-On,-EL{B}(大小端字节序),那么就要加到这个上面,如:
LOCAL_LDFLAGS += -L$(LOCAL_PATH)/lib/ -lHWrecog –EB{EL} –O{n} …
或者直接加上绝对路径库的全名:
LOCAL_LDFLAGS += $(LOCAL_PATH)/lib/libHWrecog.a –EB{EL} –O{n}  
注:如果是非系统的第三方库,貌似只能用LOCAL_LDFLAGS方式,LOCAL_LDLIBS方式不行。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TestNdk
LOCAL_SRC_FILES := jniInterface.cpp
LOCAL_CFLAGS := -fdata-sections -ffunction-sections -D_JBP_DEBUG_ANDROID
LOCAL_LDFLAGS += -Wl,--gc-sections,--version-script,linker
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ac $(LOCAL_PATH)
LOCAL_LDLIBS := -L. -ljbp -Llib -lac_shim -lac -llog -lz
include $(BUILD_SHARED_LIBRARY)

 nm libgdfont.a 来看里面的目标文件和导出函数(带 T 标记)
 nm libgdfont.so 来看里面导出的函数(带 T 标记)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值