死活链接不到std::string之流的符号的时候,需要增加一个Application.mk文件,至少有以下这一行内容:

APP_STL := gnustl_static

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

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

ndkgdb虽然可以做调试,但是还是麻烦,所以直接打印日志最方便,如下几步:
1. 首先需要包含android/log.h文件
2. 然后定义

#define print_log(fmt, args...) __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, fmt, ##args)

3. 自己定义好APPNAME,另外,在print_log宏中的ANDROID_LOG_VERBOSE参数是可以定义的,在android/log.h文件中有定义,如下

typedef enum android_LogPriority {                                                                                                                                                       
     ANDROID_LOG_UNKNOWN = 0,
     ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
     ANDROID_LOG_VERBOSE,
     ANDROID_LOG_DEBUG,
     ANDROID_LOG_INFO,
     ANDROID_LOG_WARN,
     ANDROID_LOG_ERROR,
     ANDROID_LOG_FATAL,
     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 } android_LogPriority;

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();
}

今天HTC G7拿到家,迫不急待的要升级到2.2的系统,打开GOOGLE胡乱搜索一通,基本上总结出来要以下三步:

1、先刷ROOT
A. 刷ROOT关键是要刷对应版本的破解ROM,现在市面上流行三种不同版本的手机ROM,0.80或者以下、0.83以及0.93。其实我原来的机器是0.83的,回家上了WIFI后居然自动升级成0.93的了。想要看自己的机器的ROM的版本,首先关机,然后按住“返回”键,然后不要松手再按一下电源键开机。这时机器会打开,然后在启动的屏幕上可以看到ROM的版本。像我的手机上有HBOOT-0.93.0001的字样,说明我的手机应该要刷0.93的ROM。
B. 下载对应的ROM文件reflash_package0.92_0.93.rar,这个文件可以在这里下载,0.83版本的文件名称应该是reflash_packagefor0.83.zip,下载好后解压缩到一个目录下,然后运行reflash.exe,运行好后使用USB线连接手机(注:最好使用电脑机箱后方的USB口,因为前方的口可能供电不足会导致UNKNOWN DEVICE问题)
C. 手机会自动重启几次,最后停留在一个绿色的文字黑色底的界面就说明成功了。

2、准备一张手机SD卡,把它刷成金卡(因为会使用这张卡来升级新的镜像,但是有时候却可能因为地区不同而会导致更新系统失败,如果刷成了金卡,则会自动跳过地区检查,大概是这个用途,我还没有碰到过该问题,也许是因为我已经刷成金卡的缘故)
A. 刷金卡的关键是要在手机上安装一个终端软件,可以在电子商场里找到很多类似的软件,直接点击下载一个,然后在所有程序中找到该终端程序运行。
B. 输入以下的命令取得该卡的号码cat /sys/class/mmc_host/mmc*/mmc*:*/cid,按下回车按钮后会得到一串数字,该数字就是SD卡的号码。这时可以把该数字记下来,我则是直接使用GMAIL来同步,我首先把终端里的文字拷贝下来,然后打开GMAIL建立一个新邮件,把剪切板的内容粘贴到新邮件里,然后保存草稿同步一下就可以用电脑来直接复制该SD卡卡号
C. 复制卡号到电脑的剪切板之后,在电脑上打开网站:http://hexrev.soaa.me/,然后使用CTRL+V把卡号粘贴到输入框中,按下Submit按钮,不一会儿,则取得了使用该卡号码算出来的另一个号码,把该号码复制到剪切板
D. 使用浏览器打开网站:http://psas.revskills.de/?q=goldcard,然后填写email地址以及粘贴新算出来的号码(CID)至对应的输入框中,然后输入验证码后按下“Generate goldcard”,不一会儿,生成好的映像文件将会发送至邮箱中
E. 关掉手机,把SD卡取出来,插到电脑上
F. 下载HxDSetupEn然后安装至电脑中,使用Open Disk打开SD卡(注意要把Read Only那个钩去掉),再使用Open Disk Image打开邮箱中的img文件,然后把img文件中的0-170行都复制到剪切板中,然后选择打开的SD卡中的0-170行再使用CTRL+V粘贴img文件中的所有内容至卡中,最后保存退出。这里有一点要注意的是,在Open Disk中应该选择Removable disk 1设备而不是带有卷标和盘符的设备。
关于制作金卡的更详细的教程,可以参考:http://hi.baidu.com/sdhlkx/blog/item/fbf80e118ee8d50d213f2e55.html

3、最后刷网上下载好的镜像ROM文件

A. 把在网上下载好的镜像ZIP文件保存到SD卡的根目录,然后更名为update.zip,把SD卡装至手机中
B. 按下音量-号键不要松手,再按下电源键打开手机,在第一个白底的菜单中使用音量调节键选择RECOVERT菜单,按下电源键确定
C. 进入到黑底绿字的界面,分别选择第3第4项,把data/factory reset和cache partition删除干净(做这步前要备份好手机上的数据),然后使用第2项apply sdcard:update.zip
D. 等待手机安装镜像和更新系统,手机会自动重启多次,最后进入到第一次设置的界面中,这时系统已经刷好了指定的镜像文件的系统了。
PS:能不使用电脑前置的USB口就不要使用电脑前置的USB口,不然会出很多奇怪的问题。