|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
最初被命名为Oak,目标设定在家用电器等小型系统的编程语言,来解决诸如电视机、电话、闹钟、烤面包机等家用电器的控制和通讯问题。JNI就是JavaNativeInterface,也能够了解为一样平常剧本言语的CAPI,一样平常情形下这类API的进修都是一种疾苦的精神,历来云云,没有太多手艺含量,就是一堆流畅难以了解的编程模子,编程接口,充溢着各类从以后言语到C言语的范例转换.基础的寄义就是用C言语的头脑往暗示以后的言语,这个成绩在Lua言语中抵达了极致.不论是何等为了效力,一个纯仓库操纵的编程接口都像汇编言语一样难以利用.
由于比来又入手下手做Android游戏了,用的是cocos2d-x,JNI是难以免了,之前的利用都是照猫画虎似的写几个函数挪用接口,总感到有成绩,明天好好的进修进修吧.
与一样平常关于JNI文章略微有些纷歧样的是,本文会更多的存眷于Android相干的成绩.
本文利用的情况是:
MacOSX10.8.3
javaversion"1.6.0_43"
Java(TM)SERuntimeEnvironment(build1.6.0_43-b01-447-11M4203)
JavaHotSpot(TM)64-BitServerVM(build20.14-b01-447,mixedmode)
gccversion4.2.1(BasedonAppleInc.build5658)(LLVMbuild2336.11.00)
AndroidSDKAPI17
Androidndkr8d
从Java中挪用C/C++库
从Java中挪用C/C++库的典范利用场景就是在Android中Load本人写的游戏库,然后运转.固然有cocos2d-x引擎的时分你几近不必体贴这个.
HelloWorld
从R&D入手下手,HelloWorld就成了一入手下手必用的例子了,进修JNI也从这个入手下手吧.
起首构建一个最复杂的Javaclass:- //HelloWorld.javaimportjava.lang.System.*;publicclassHelloWorld{publicnativevoidSayHelloWorld();publicstaticvoidmain(String[]args){System.loadLibrary("helloworld");HelloWorldhelloworld=newHelloWorld();helloworld.SayHelloWorld();}}
复制代码 native关头字暗示的接口就是必要用C/C++来完成的接口,System.loadLibrary挪用的就是将会完成的jni库.
然后用javac将文件编译成字节码:天生HelloWorld.class,java中最人道的一点就是把binding的天生间接作为尺度了,这一点比Python和lua要强多了,也使得JNI的利用是我打仗过的言语中,相似CAPI最便利的一个.间接天生C/C++binding头文件的体例是用javah命令:从下面的HelloWorld类天生的头文件以下:- /*DONOTEDITTHISFILE-itismachinegenerated*/#include<jni.h>/*HeaderforclassHelloWorld*/#ifndef_Included_HelloWorld#define_Included_HelloWorld#ifdef__cplusplusextern"C"{#endif/**Class:HelloWorld*Method:SayHelloWorld*Signature:()V*/JNIEXPORTvoidJNICALLJava_HelloWorld_SayHelloWorld(JNIEnv*,jobject);#ifdef__cplusplus}#endif#endif
复制代码 这其实是相称人道化了,我们只必要包括HelloWorld.h头文件,然后完成依照头文件给的署名完成Java_HelloWorld_SayHelloWorld函数就好了,而不必本人往记着这么庞大的函数名和参数.完成的HelloWorld.cc文件以下:- //HelloWorld.cc#include"HelloWorld.h"#include<cstdio>JNIEXPORTvoidJNICALLJava_HelloWorld_SayHelloWorld(JNIEnv*,jobject){printf("HelloWorld.n");}
复制代码 编译C++代码的时分在MacOS下和在Linux,Windows有所分歧,不是编译成.so大概dll,而是MacOS本人的jnilib.而且jni.h的目次也对照特别,是/System/Library/Frameworks/JavaVM.framework/Headers/,这个必要略微注重一下,详细的命令以下:- g++-dynamiclib-olibhelloworld.jnilibHelloWorld.cc-frameworkJavaVM-I/System/Library/Frameworks/JavaVM.framework/Headers
复制代码 此时统统停当:- >javaHelloWorldHelloWorld.
复制代码 带参数的函数
两个言语之间的往返挪用,在没有任何参数的情形下还好,有了参数今后,由于扳连到两个言语对范例的分歧暗示体例,必要举行范例转换,是最贫苦的中央,好比在Lua,Python中,利用CAPI时,你就必要记着Lua和Python的各类范例分离对应C言语中的哪一个范例,JAVA中在挪用C/C++函数时,在Java中经由过程javah部分减缓了这个成绩,可让我们间接晓得对应的范例是哪个,不外详细每一个用C言语暗示的JAVA范例该怎样用,仍是查文档吧,好比上面这个例子:- //ArugmentTest.javaimportjava.lang.System.*;publicclassArgumentTest{publicnativeintintMethod(intn);publicnativebooleanbooleanMethod(booleanbool);publicnativeStringstringMethod(Stringtext);publicnativeintintArrayMethod(int[]intArray);publicstaticvoidmain(String[]args){System.loadLibrary("argumenttest");ArgumentTestobj=newArgumentTest();System.out.println("intMethod:"+obj.intMethod(5));System.out.println("booleanMethod:"+obj.booleanMethod(true));System.out.println("stringMethod:"+obj.stringMethod("JAVA"));System.out.println("intArrayMethod:"+obj.intArrayMethod(newint[]{1,2,3,4,5}));}}
复制代码 编译后,用javah天生的头文件以下:- /*DONOTEDITTHISFILE-itismachinegenerated*/#include<jni.h>/*HeaderforclassArgumentTest*/#ifndef_Included_ArgumentTest#define_Included_ArgumentTest#ifdef__cplusplusextern"C"{#endif/**Class:ArgumentTest*Method:intMethod*Signature:(I)I*/JNIEXPORTjintJNICALLJava_ArgumentTest_intMethod(JNIEnv*,jobject,jint);/**Class:ArgumentTest*Method:booleanMethod*Signature:(Z)Z*/JNIEXPORTjbooleanJNICALLJava_ArgumentTest_booleanMethod(JNIEnv*,jobject,jboolean);/**Class:ArgumentTest*Method:stringMethod*Signature:(Ljava/lang/String;)Ljava/lang/String;*/JNIEXPORTjstringJNICALLJava_ArgumentTest_stringMethod(JNIEnv*,jobject,jstring);/**Class:ArgumentTest*Method:intArrayMethod*Signature:([I)I*/JNIEXPORTjintJNICALLJava_ArgumentTest_intArrayMethod(JNIEnv*,jobject,jintArray);#ifdef__cplusplus}#endif#endif
复制代码 这里我们能够看到,也许的范例对应干系:
Object=>jobject
int=>jint
boolean=>jboolean
String=>jstring
int[]=>jintArray
可是,jobject,jstring,jintArray详细怎样利用,总回得再进修一遍.可是javah的存在仍是十分成心义的,最少我们不必记哪一个范例该查甚么文档了.
完成的C++文件以下:- //ArgumentTest.cc#include"ArgumentTest.h"#include<cstring>usingnamespacestd;JNIEXPORTjintJNICALLJava_ArgumentTest_intMethod(JNIEnv*env,jobjectobj,jintnum){returnnum*num;}JNIEXPORTjbooleanJNICALLJava_ArgumentTest_booleanMethod(JNIEnv*env,jobjectobj,jbooleanboolean){return!boolean;}JNIEXPORTjstringJNICALLJava_ArgumentTest_stringMethod(JNIEnv*env,jobjectobj,jstringstr){constchar*cstr=env->GetStringUTFChars(str,0);charcap[128]="language:";strcat(cap,cstr);env->ReleaseStringUTFChars(str,cstr);returnenv->NewStringUTF(cap);}JNIEXPORTjintJNICALLJava_ArgumentTest_intArrayMethod(JNIEnv*env,jobjectobj,jintArrayarray){jsizelen=env->GetArrayLength(array);jint*body=env->GetIntArrayElements(array,0);intsum=0;for(inti=0;i<len;++i){sum+=body[i];}env->ReleaseIntArrayElements(array,body,0);returnsum;}
复制代码 这里能够看到几个特别的函数,GetStringUTFChars,GetArrayLength,GetIntArrayElements,ReleaseIntArrayElements等,还好都不算太庞大.一旦用了JNI,必要注重的就是,你资本的分派开释,就得和C/C++中一样了,得本人手动来.
别的,还值得一提的是,由于C++对类的间接撑持,以是C++中能够用比C言语更简便的语法,也许的区分看了上面的示例:
C代码:(*env)->GetStringUTFChars(env,string,0);
C++代码:env->GetStringUTFChars(string,0);
Android中的情形
实在完成和利用体例都相似,只是编译时,必要利用分歧的命令,实在由于Android实在就是一种特别的Linux,以是关于Android来讲,天生体例和Linux相似,而且都是天生Unix/Linux通用的.so静态库文件.
别的,另有一些典范的Android的成绩,好比在Android中往完成后面的ArugmentTest:必要注重的是,Android中就不要利用System.out这类尺度JAVA的库输入了,用的是android.util.Log这个再LogCat输入的类.然后,作为Android的工程,一个Activity是必需的,这里就把ArgumentTest做成了Activity了.
编译的时分必要注重,一方面在Android中,我们一定必要指定一个本人的package,不克不及像后面何处随便了,这里的pakcage我用的是com.jtianling.ArgumentTest,别的,还必要指定一下android的classpath:一样的,pacakge在用javah的时分也必不成少,否则就算天生了.so,实在package对不上也是找不到的.起首进进jni目次,然后用上面的命令,指定好package.此时天生的头文件是带package信息的,也许是上面如许子:
com_jtianling_ArgumentTest_ArgumentTest.h
文件的函数名也是相似,也附带了package的信息:一样的,依照署名和函数名完成便可,在一个典范的Android工程中,jni相干的C/C++代码都是放在工程的jni目次下,我们还需在此目次设置Android.mk文件,也许以下:我们利用ndk-build来编译android的jni静态库.编译的输出以下:
java比较简单,没有C++的烦琐,但学习时最好有C++为基础.与JSP和SQL起应用,功能强大. |
|