1. 运行javah命令要在项目目录的src/目录下
2. 要指定完全的包及类的名称,例如:com.ai.chess.Board
3. 指定classpath的位置到项目的bin/classes目录
4. 完整示例:

javah -jni -classpath ../bin/classes com.ai.chess.Board

1. 对于Java的数据类型,基本类型是可以与c++的数据类型混用的
2. 如果要使用字符串类型,可以参考下面的例子

// 建立新的字符串对象
char const* some_string = "sample";
jstring username = env->NewStringUTF(some_string);
// 取得字符串对象的C语言字符串指针
char const* some_string_from = env->GetStringUTFChars(username, 0);
// 别忘记释放
env->ReleaseStringUTFChars(username, some_string_from);

3. 回调java的函数,需要先取得java虚拟机对象的指针,使用env->GetJavaVM(&vm)可以取得,vm的类型为:JavaVM*,然后要使用该对象的AttackCurrentThread附着于对应的javaVM的线程,在java回调完成后,需要使用DetachCurrentThread来离开
4. 回调java的函数,先取出对象(jobject)的类(jclass),使用jclass cls = env->GetObjectClass(obj);可以取得
5. 然后使用jmethodID mid = env->GetMethodID(cls, 方法名称, 方法型);来取得方法的ID;其中,方法型字符串代入可以参考
6. 取得了methodID后可以使用env->CallVoidMethod(obj, mid, …);函数来调用java的方法了,在本例中的CallVoidMethod是无返回值的,若要调用有返回值的函数,可以具体google相关的调用方法

对于C++程序来说,需要用到的一个功能,废话不多说,直接来步骤:

  • 先下载NDK最新的版本,可以直接到官网上下载:http://developer.android.com,但是其实官网的版本对stl支持并不好,考虑使用CrystaX.NET上经过修改过的NDK,下载:http://www.crystax.net/zh/android/ndk
  • 若是在Windows下,那么下载Cygwin然后安装make, gcc, g++等编译相关的工具
  • 若是在Mac下,推荐下载MacPorts.org,然后安装make, gcc, g++,当然可以使用XCode来下载command-line tools,同样也会有c++的命令行编译器
  • 将自己的c/c++程序放到Android工程的./jni目录下
  • 在Android的工程中建立导出的Java类,方法类似public native void some_call();然后使用javah -jni 来生成.h文件。要注意的是,javah -jni后面所带的文件名称为包的详细名称+类名称,例如:javah -jni com.ai.connectfour.Board,并且当前的目录应该为工程目录下的src目录内
  • 生成好了.h文件后,拷贝该文件至jni目录中,然后自行补完.c/.cpp文件,关于JNIEnv对象如何使用,查询java.com上的文档
  • 参考NDK/docs目录下的ANDROID-MK.HTML,并自行建立Android.mk文件,放到jni目录里
  • 设置好NDK的目录,使用export NDK=(ndk root)命令
  • 调用NDK命令编译:$NDK/ndk-build
  • 编译好之后,so文件将会存在于工程目录下的lib目录中,java类应该可以直接使用

附,Android.mk样例:

   LOCAL_PATH := $(call my-dir)
   include $(CLEAR_VARS)
   LOCAL_MODULE    := hello-jni
   LOCAL_SRC_FILES := hello-jni.c
   include $(BUILD_SHARED_LIBRARY)

附,Java导出类样例:

package com.ai.connectfour;
 
public class Board {
	static {
		System.loadLibrary("ai_connectfour");
	}
	public native void setDifficulty(int difficulty);
	public native int[] getBoard();
	public native void setHumanFirst();
	public native void setComputerFirst();
	public native int isComputerWin();
	public native int isHumanWin();
	public native int isComputerTurn();
	public native int takeHumanTurn(int pos);
	public native int takeComputerTurn();
	public native int takeBackMove();
	public native int getBestMove();
	public native void move(int pos);
	public native int isGameOver();
	public native byte[] getData();
	public native void setData(byte[] data);
	public native void init();
	public native void deinit();
}