现在的位置: 首页 > 综合 > 正文

通过jni让java和cpp互相调用(包括编译脚本)

2014年09月18日 ⁄ 综合 ⁄ 共 4825字 ⁄ 字号 评论关闭

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}

抱歉!评论已关闭.