jni

来源:互联网 发布:thinkphp网站源码下载 编辑:程序博客网 时间:2024/06/09 00:06

------------------------------------------------
jni中c文件要引入的路径:
project->properties->C/C++ General -> Paths and Symbols -> Includes ->
E:\Android\Tools\android-ndk-r9-windows-x86\android-ndk-r9\sources\cxx-stl\system\include
E:\Android\Tools\android-ndk-r9-windows-x86\android-ndk-r9\toolchains\arm-linux-androideabi-4.6\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.6\include
E:\Android\Tools\android-ndk-r9-windows-x86\android-ndk-r9\toolchains\arm-linux-androideabi-4.6\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.6\include-fixed
E:\Android\Tools\android-ndk-r9-windows-x86\android-ndk-r9\platforms\android-18\arch-arm\usr\include
 
------------------------------------------------
android工程删除jni
1、删除jni目录。
2、删除工程目录下.cproject文件
3、删除工程目录下的.project文件里的CDT相关项
4、把该工程从eclipse中删除:注意只是从工程中删除,不是从磁盘中删除。
5、把项目移到别的目录下,重新添加到eclipse工程中。


------------------------------------------------
1.在Java代码中声明本地方法必须有"native"标识符,native修饰的方法,在Java代码中只作为声明存在。
package com.example.s_jnidemo;
public class Example {
public native String jni_test(String str);
static {
System.loadLibrary("S_JniDemo");
}
}


2.在dos命令窗口中定位到工程所在的目录下,用javac编译该类:$javac HelloWorld.java


3.利用javah -jni产生头文件:$javah -jni HelloWorld

"-jni"为默认参数,可有可无.
  *4.2版本:在编译生成class文件后,要在本文件package包的上一级目录下,
执行命令:javah -classpath  . -jni packagename.classname。
包名之间用.分隔开


4.头文件中方法的参数
JNIEnv *:JNIEnv结构包括JNI函数表。
jobject:取决于该方法是静态还是实例方法(static or an instance method)。当本地方法作为一个实例方法时,第二个参数相当于对象本身,即this. 当本地方法作为一个静态方法时,指向所在类


5.调用GetStringUTFChars,把一个Unicode字串转成UTF-8格式字串
char *strt = (char *)env->GetStringUTFChars(prompt, NULL);
const jchar *jcstr = env->GetStringChars(prompt, 0);
上述声明中,有isCopy参数,当该值为JNI_TRUE,将返回str的一个拷贝;为
JNI_FALSE将直接指向str的内容。 注意:当isCopy为JNI_FALSE,不要修改返回值,不
然将改变java.lang.String的不可变语义。
一般会把isCopy设为NULL,不关心Java VM对返回的指针是否直接指向


有两个函数:GetStringLength/GetStringUTFLength,前者是Unicode编码长度,后者
是UTF编码长度。


GetStringUTFRegion很有用,因为你不能修改GetStringUTFChars返回值,所以需要另
外malloc/strcpy之后,再操作返回值,耗时费力,不如直接使用GetStringUTFRegion来
的简洁、高效。


6.调用ReleaseStringUTFChars释放GetStringUTFChars中分配的内存(Unicode -> UTF-8转换的原因)。
env->ReleaseStringChars(prompt, jcstr);
env->ReleaseStringUTFChars(prompt, strt);
记住在调用GetStringChars之后,要调用ReleaseStringChars做释放,不管在调用
GetStringChars时为isCopy赋值JNI_TRUE还是JNI_FALSE,因不同JavaVM实现的原因,
ReleaseStringChars可能释放内存,也可能释放一个内存占用标记(isCopy参数的作用,从
GetStringChars返回一个指针,该指针直接指向String的内容,为了避免该指针指向的内
容被GC,要对该内存做锁定标记)


7.把jni中的输出信息显示到Android的logcat窗口上
1)在mk文件的最后一行之前添加:LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
2)在.c/.cpp文件中添加:#include <android/log.h>
3)输出时调用:__android_log_print(ANDROID_LOG_INFO, "日志标签", "输出内容");

4)eg:__android_log_print(ANDROID_LOG_INFO, "MyJni", "%s, fun=%s, line=%d\n", "my print info", __FUNCTION__, __LINE__);



8.Java与JNI基本类型的映射关系表:

JavaNative(jni.h)booleanjbooleanbytejbytecharjcharshortjshortintjintlongjlongfloatjfloatdoublejdoubleObjectjobject


9.签名

1)基本签名:

Type SignatureJava TypeNative TypeZbooleanjbooleanBbytejbyteCcharjcharSshortjshortIintjintJlongjlongFfloatjfloatDdoublejdoubleL fully-qualified-class;fully-qualified-class [ typetype[] (arg-types) ret-typemethod type Vvoidvoid


2)数组则以"["开始,用两个字符表示

[IjintArrayint[][FjfloatArrayfloat[][BjbyteArraybyte[][CjcharArraychar[][SjshortArrayshort[][DjdoubleArraydouble[][JjlongArraylong[][ZjbooleanArrayboolean[]

 

3)类描述符:以“L”开头,以“;”结尾;中间用“/”隔开;其对应的C函数名的参数则为jobject。

eg:Ljava/net/Socket; Socket jobject

String是个例外:Ljava/lang/String; jstring String


如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。

例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"



10.从JNI调用实例方法命名规则: Call<Return Value Type>Method

"()V":表示void Func();

"(II)V":表示void Func(int, int);

"(Ljava/lang/String;Ljava/lang/String;)V"

eg:

jmethodID mId = (*env)->GetMethodID(env, jcls, "toLog", "()V");

"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();






------------------------------------------------
实例:在Native层返回一个int型二维数组(inta[ ][ ])
public class HelloJni {  
    ...  
    //参数代表几行几列数组 ,形式如:int a[dimon][dimon]  
    private native int[][] getTwoArray(int dimon) ;   
    ...  



Native层该方法实现为 :
//返回int二维数组JNIEXPORT jintArray JNICALL Java_com_sxy_JniTest_HelloWorld_getIntArray(JNIEnv *env, jobject obj, jint num){//得到类名//jclass jcls = (*env)->GetObjectClass(env, obj);//获得一维数组 的类引用,即jintArray类型jclass intArrCls = (*env)->FindClass(env, "[I");if(intArrCls == NULL){return NULL;}//构造一个指向jintArray类一维数组的对象数组,该对象数组初始大小为dimionjobjectArray result = (*env)->NewObjectArray(env, num, intArrCls, NULL);if(result == NULL){return NULL;}int i=0;//构建num个一维数组,并且将其引用赋值给obejctIntArray对象数组for(i=0; i<num; i++){//初始化一个容器,假设 num<256 ;jint temp[256];int j;//构建jint型一维数组jintArray iarr = (*env)->NewIntArray(env, num);if(iarr == NULL){return NULL;}for(j=0; j<num; j++){temp[j] = i+j;}//设置jint型一维数组的值(*env)->SetIntArrayRegion(env, iarr, 0, num, temp);//给object对象数组赋值,即保持对jint一维数组的引用(*env)->SetObjectArrayElement(env, result, i, iarr);//删除局部引用(*env)->DeleteLocalRef(env, iarr);}//返回该对象数组return result;}








获取类型变量名:
env->GetFieldID(cls, "name", "Ljava/lang/String;");//获取String型变量名ID
env->GetFieldID(cls, "nameid", "I");//获取int型变量名ID
env->GetFieldID(cls, "nameidy", "Z");//获取boolean型变量名ID
jclass intArrCls = env->FindClass("[I");//获取int数组











------------------------------------------------
Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名、引用的头文件目录、需要编译的.c/.cpp文件和.a静态库文件等。要掌握jni,就必须熟练掌握Android.mk的语法规范。 


一、Android.mk文件的用途 
一个android子项目中会存在一个或多个Android.mk文件 
1、单一的Android.mk文件 
直接参考NDK的sample目录下的hello-jni项目,在这个项目中只有一个Android.mk文件 
2、多个Android.mk文件 
如果需要编译的模块比较多,我们可能会将对应的模块放置在相应的目录中, 
这样,我们可以在每个目录中定义对应的Android.mk文件(类似于上面的写法), 
最后,在根目录放置一个Android.mk文件,内容如下: 
include $(call all-subdir-makefiles) 
只需要这一行就可以了,它的作用就是包含所有子目录中的Android.mk文件 
3、多个模块共用一个Android.mk 
这个文件允许你将源文件组织成模块,这个模块中含有: 
  -静态库(.a文件) 
  -动态库(.so文件) 
只有共享库才能被安装/复制到您的应用软件(APK)包中 
include $(BUILD_STATIC_LIBRARY),编译出的是静态库 
include $(BUILD_SHARED_LIBRARY),编译出的是动态库 









------------------------------------------------
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
0 0
原创粉丝点击