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
learnjni.cpp,上面头文件的实现
#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}