这两天一直在学习ndk,学习如何利用jni调用c代码。从环境安装配置到弹出helloworld这个过程中碰到不少问题,我这里就把这些问题记录下来,希望对大家有帮助。
1、安装NDK
这个没啥好说的,下载直接解压就是了。下载地址为http://developer.android.com/sdk/ndk/index.html
2、安装Cygwin
下载Cygwin。cygwin是一个在windows平台上运行的unix模拟环境,我们可以用它来编译jni程序。下载地址为http://www.softpedia.com/get/System/OS-Enhancements/Cygwin.shtml。Cygwin的安装与配置可以参考http://www.mcclean-cooper.com/valentino/cygwin_install/。
注意:http://www.mcclean-cooper.com/valentino/cygwin_install/中在Cygwin安装的第9个步骤作者也特别指出在安装的过程中可能会弹出一个"Download Incomplete.Tray again?"提示框,点击确定后就会回到步骤8,选择另外一个服务器继续安装就可以了。
3、将NDK与Cygwin关联起来
打开<Cygwin安装目录>\home\Administrator\.bash_profile文件,在文件中加入如下两段代码
NDK_ROOT=/cygdrive/e/android/android-ndk-r7b/
export NDK_ROOT
PATH+=:$NDK_ROOT
export PATH
注意:
1、我的ndk安装在E:\android\android-ndk-r7b,如果你是安装在F:\ndk\android-ndk-r7b目录那么NDK_ROOT就要改为/cygdrive/f/ndk/android-ndk-r7b/
2、另外我第一次进入<Cygwin安装目录>\home\Administrator目录时目录下并没有.bash_profile文件,如果Cygwin不是默认装在C盘就有可能出现这个问题,解决方法就是退出Cygwin然后把这个Administrator文件夹删掉,再重新打开Cygwin后就会自动生成Administrator目录以及.bash_profile文件。
3、另外必须强调的是.bash_profile文件不能用记事本或者写字板软件打开进行编译,否则重启Cygwin后会报错,如下图:
google,百度了一番才知道原来是用写字板或记事本编辑后.bash_profile文件的格式被转为DOC(默认该文件为unix格式),回车符多了一个'\r',所以cygwin会报“-bash: $'\r': command not found”。这里大家可以去下个UE,然后把Administrator文件夹删了重新生成,用UE软件编辑.bash_profile就可以了。
4、在NDK安装目录下新建文件夹apps,在apps下新建目录htf(这个名字可以自己任意取),在htf下需要新建jni文件夹及Application.mk文件。
Application.mk的内容如下:
APP_PROJECT_PATH:=${call my-dir}
APP_MODULES:=jni
jni文件夹下有两个文件,Android.mk及ftmjni.c。ftmjni.c就是我要编译的代码,Android.mk用于配置需要编译的内容等。
Android.mk内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ftmjni
LOCAL_SRC_FILES := ftmjni.c
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES表示你要编译的代码,多个代码可以用空格隔开。
LOCAL_MODULE表示生成的so库的名称。
ftmjni.c内容如下
#include <string.h>
#include <jni.h>
jstring Java_mobile_jni_MyJniActivity_sayHelloWorld( JNIEnv* env,jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello World");
}
注意:Java_mobile_jni_MyJniActivity_sayHelloWorld这个命名是遵循规律的,必须以Java开头mobile_jni实际上就是包路径,MyJniActivity就是类名,而sayHelloWorld就是方法名。这个名字要是错了就无法被调用到。
我的java代码如下:
package mobile.jni;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MyJniActivity extends Activity {
static {
//我编译生成的库叫“libftmjni.so”,我们要根据"ftmjni"取加载库而不是"libftmjni"
System.loadLibrary("ftmjni");
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
/**
* 按钮点击事件
* @param view
*/
public void onBtnClicked(View view){
String str=sayHelloWorld();
Toast.makeText(this, str, Toast.LENGTH_LONG).show();
}
public native String sayHelloWorld();
}
5、ok,环境代码准备就绪。现在可以开始编译了。
1、打开cygwin输入"cd $NDK_ROOT"就可以直接进入ndk安装目录。
2、cd到htf目录然后直接输入"ndk-build"后回车,如下图。我们可以看到在 htf/libs/armeabi/目录下成功生成了libftmjni.so文件。
注意:htf所存放的路劲最好不要有空格,如不要把"apps"名为为"apps htf",否可能导致编译失败。
6、编译成功后直接将libs文件夹拷贝到工程目录下(与src同级)。然后运行项目。点击上面的buton可以看到弹出了"Hello World"
JNI代码及工程我都已经上传到http://download.csdn.net/detail/goleftgoright/4167190了,有需要的同学可以去下。这只是个小例子,要深入就靠自己了。