java 代码
package com.ashqal.test; /** * Created by ashqal on 14-3-22. */ public class LearnJNI { static { //System.loadLibrary("ljni"); System.load("/files/maccode/idea/JNIProject/jni/liblearnjni.so"); } public native void displayHelloWorld(); public native int getInt(); public native String getString(); public void callFromJNI1() { System.out.println("callFromJNI1"); } public void callFromJNI2(int k) { System.out.println("callFromJNI2:" + k); } public String callFromJNI3(int k,String text,byte[] bytes) { System.out.println("callFromJNI3:" + k + ",text:" + text); return "get it!"; } public LearnJNI() { displayHelloWorld(); System.out.println("getInt:" + getInt()); System.out.println("getString:" + getString()); } }
com_ashqal_test_LearnJNI.h,由javah生成不要去改变它!
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_ashqal_test_LearnJNI */ #ifndef _Included_com_ashqal_test_LearnJNI #define _Included_com_ashqal_test_LearnJNI #ifdef __cplusplus extern "C" { #endif /* * Class: com_ashqal_test_LearnJNI * Method: displayHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_com_ashqal_test_LearnJNI_displayHelloWorld (JNIEnv *, jobject); /* * Class: com_ashqal_test_LearnJNI * Method: getInt * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_ashqal_test_LearnJNI_getInt (JNIEnv *, jobject); /* * Class: com_ashqal_test_LearnJNI * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ashqal_test_LearnJNI_getString (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include "com_ashqal_test_LearnJNI.h" #include <iostream> /* 类型 相应的签名 boolean Z byte B char C short S int I long L float F double D void V object L用/分隔包的完整类名: Ljava/lang/String; Array [签名 [I [Ljava/lang/Object; Method (参数1类型签名 参数2类型签名···)返回值类型签名 */ /* Java类型 别名 本地类型 字节(bit) boolean jboolean unsigned char 8, unsigned byte jbyte signed char 8 char jchar unsigned short 16, unsigned short jshort short 16 int jint long 32 long jlong __int64 64 float jfloat float 32 double jdouble double 64 void void n/a Object _jobject *jobject */ /* * Class: com_ashqal_test_LearnJNI * Method: displayHelloWorld * Signature: ()V */ JNIEXPORT void JNICALL Java_com_ashqal_test_LearnJNI_displayHelloWorld (JNIEnv *env, jobject obj) { std::cout<<"from jni"<<std::endl; jclass clz = env->GetObjectClass(obj); // public void callFromJNI1() // "()V" jmethodID methodID1 = env->GetMethodID(clz,"callFromJNI1","()V"); env->CallVoidMethod(obj,methodID1); // public void callFromJNI1() // "()V" jmethodID methodID2 = env->GetMethodID(clz,"callFromJNI2","(I)V"); env->CallVoidMethod(obj,methodID2,12); jvalue * args2 = new jvalue[2];//存储参数的数组 args2[0].i = 10; args2[1].i = 10; //args2[1].d=3.44; env->CallVoidMethodA(obj,methodID2,args2); delete [] args2; //外部类型都得加L,结尾处得加分号,如Ljava/lang/String; //有返回值的可以调CallVoidMethod char param[]="中文你好,i want to call callFromJNI3."; jmethodID methodID3 = env->GetMethodID(clz,"callFromJNI3","(ILjava/lang/String;[B)Ljava/lang/String;"); jobject result = env->CallObjectMethod(obj,methodID3,12,(env)->NewStringUTF(param),NULL); jboolean iscopy = true; const char* str = env->GetStringUTFChars((jstring)result,&iscopy); std::cout<<"return from java:"<<str<<std::endl; env->ReleaseStringUTFChars((jstring)result,str); } /* * Class: com_ashqal_test_LearnJNI * Method: getInt * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_ashqal_test_LearnJNI_getInt (JNIEnv *, jobject) { return -9; } /* * Class: com_ashqal_test_LearnJNI * Method: getString * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_ashqal_test_LearnJNI_getString (JNIEnv *env, jobject) { char result[]="abc"; return (env)->NewStringUTF(result); }
autojavah.sh
.java文件生成.h文件的脚本
#!/bin/sh export ProjectPath=$(cd ../../"$(dirname "$2")"; pwd) export TargetClassName="com.ashqal.test.LearnJNI" #// 表示所有 #. 表示. #/ 表示替换成 #\/ 表示替换为/ export SourceFile="${ProjectPath}/src/"${TargetClassName//./\/} export TargetPath="${ProjectPath}/jni" export TempPath="${TargetPath}/tmp" mkdir "${TempPath}" javac -d ${TempPath} "${SourceFile}.java" cd "${TempPath}" javah -d ${TargetPath} "${TargetClassName}" rm -rf "${TempPath}" #echo javac "${SourcePath}/${SourceName}.java -d ${TargetPath}" #javah ${CLASS_NAME} #echo "[Succeed]jni interface created!"
项目结构,因为autojavah.sh是在 项目目录/jni/shell下的,所以上面运行.sh的时候做了../../,这样就到了项目的根目录
liblearnjni.so文件编译脚本build.sh
-I /System/Library/Frameworks/JavaVM.framework/Headers表示jni.h和jni_md.h所在的位置,如果两个分开的,就得分别找出来
-shared就是生成.so文件参数
#!/bin/sh g++ learnjni.cpp -o liblearnjni.so -shared -I /System/Library/Frameworks/JavaVM.framework/Headers echo "build complete."
本文cpp是在sublime2里实现的,增加了sublime2的build-system
就是指向当前.cpp文件夹下的shell文件夹内的build.sh,这样在sublime内使用command+b快捷键就可以自动编译了
{ "cmd": ["${file_path}/shell/build.sh"], "shell":true, "variants": [ { "name": "Run", "cmd": ["${file_path}/shell/build.sh && ${file_path}/shell/run.sh"] } ] }
当然上述方法除了编译生成.so文件步骤不同,需要调用ndk的编译器编译,其他都相同
所以分类到android开发啦~~
3月23日更新
原来javah命令只要在src文件夹下运行就可以了,不需要编译出来的.class文件
#!/bin/sh export ProjectPath=$(cd ../../"$(dirname "$2")"; pwd) export TargetClassName="com.ashqal.test.LearnJNI" export SourceFile="${ProjectPath}/src/" export TargetPath="${ProjectPath}/jni" cd "${SourceFile}" javah -d ${TargetPath} ${TargetClassName}