0%

Android NDK(JNI)开发入门

NDK这东西如果是第一次用有点麻烦,我花了一天时间参考网上的文章,总算写出了Hello World.网上的文章都直接拷代码,没几篇写得具体点的。说明一下,对于C语言,我属于新手,怎么个新法?就是花了一两天时间,看了几节视频教程的那种。所以下面我的观点有什么错误,请见谅。本来想录个视频教程,但想想还是算了,我得把配置好的环境全删了再装,太麻烦,和我一样新或者比我还新的新手朋友如果看不懂,留言吧,我尽心帮忙。 第一步,下载安装NDK和Cygwin,Cygwin这东西其实就类似于一个Linux的模拟器,你要是用Linux开发,就不用装这东西了。 NDK:http://developer.android.com/sdk/ndk/index.html 貌似今天不用翻墙,网页上已经是r6版,我用的是r5 Cygwin:http://www.cygwin.com/setup.exe 是一个在线安装的文件,下载了打开 Cygwin安装时会提示选两个路径,第一个是安装路径,第二个是安装文件下载后存放路径,注意区别。下载站点选mirrors.163.com,贼快。Select Packages时勾选devel里的make、gcc、gcc-core、gcc-g++这个不是很确定,反正我是把所有描述为C compiler,C++ complier的都选了。 我的安装路径: NDK(解压就好):D:\ndk\android-ndk-r5c Cygwin:D:\ndk\cygwin 安装好后在开始菜单可以找到Cygwin Bash Shell,当然,你安装的时候要是没选就没有,那么就打开安装目录的Cygwin.bat文件。试一下分别输入gcc -v, g++ -v, make -v这几个命令,看看是不是都返回了正确的版本号。 上个图先: 再配置一下环境变量,编译的时候方便。打开D:\ndk\cygwin\home\FHP\.bash_profile(我电脑登录用户名为FHP),在文件最后添加: NDK="/cygdrive/d/ndk/android-ndk-r5c" export NDK Cygwin会把所有的硬盘分区映射到/cygdrive/目录下,所以,其实这里设置的就是上面的NDK路径 接下来,Eclipse需要安装CDT,在线安装http://www.eclipse.org/cdt/downloads.php ,根据你的版本选一个安装地址,与安装语言包类似,不明白请参考http://www.pocketdigi.com/20110204/165.html  装完后,新建一个Android项目,我这里为NDKTest,包为com.ndk,类为Main。我的项目路径:D:\ndk\NDKTest 建好项目后,在项目上点右键,新建一个名为jni的文件夹,所有的c或c++文件必须放这里。 下面配置一下Eclipse,让它自动编译我们的c或者c++源代码。在项目上点右键-属性,选择构建器,点右边的新建-程序,看图: 位置跟工作目录就不解释了,自变量解释一下,这个就是编译时执行的命令,/cygdrive/d/ndk/NDKTest是Android项目的路径,$NDK/ndk-build,就是D:\ndk\android-ndk-r5c\ndk-build 因为我们刚才设置了环境变量。 所以这个自变量的意思就是进入项目所在目录,执行ndk-build编译。 刷新选项卡要勾选“完成时刷新资源” 构建选项卡: 点击“指定资源”,勾选项目NDKTest的jni目录,这样,只要是jni下面的文件改变了,就会自动重新编译。 最后,保存,把刚才建的构建器移动最顶端(必须先编译c文件才能编译apk). 然后是代码部分,在jni目录下建一个ndkc.c文件,把c语言的代码都写这里:

#include 
#include 

jstring Java_com_ndk_Main_StringBack(JNIEnv* env, jobject obj){
     return (*env)->NewStringUTF(env, "TESTsfsfdaas标杆s!");
     //(*env)->NewStringUTF方法是把c语言的字符串转换成jstring(Java语言的字符串)
     //
}
//函数名有限制,必须为Java_调用它的类名_调用方法,JNIEnv* env, jobject obj,这两个参数是必须加的
jint Java_com_ndk_Main_Add(JNIEnv * env, jobject obj, jint a, jint b){
    return a+b;
    //好像基本数据类型不用转
    //jint就是int
}

在jni目录下建一个Android.mk文件,这个差不多就是编译的参数: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ndkc LOCAL_SRC_FILES := ndkc.c #LOCAL_MODULE 指的是编译后的库名,java文件中直接就调用这个名字 #LOCAL_SRC_FILES c语言源文件名 include $(BUILD_SHARED_LIBRARY) 接下来就是Java里面的调用,Main.java:

package com.ndk;

import android.app.Activity;
import android.os.Bundle;

public class Main extends Activity {
    /** Called when the activity is first created. */
    static {
        System.loadLibrary("ndkc");
        //调用编译C语言生成的库
    }
    public native String StringBack();
    //定义一下来自C的方法
    public native int Add(int a,int b);
    //同上,返回类型为int,参数是两个int
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        System.out.println(StringBack());
        System.out.println(Add(5,6));
      //输出返回值
    }
}

最后是运行,可以在logcat看到结果 网上很多文章都说编译C文件之前要用javah 生成h头文件,但我好像都没用到,我感觉那一步唯一的作用就是可以参考生成的h头文件来写c程序,因为h头文件里包括了所有被java调用的方法包括及参数,返回类型这类的东西。如果要生成h头文件,注意一下,先编译,然后切换到项目的bin目录(不是src)下,再javah -包名.类名,在bin目录下就会生成一个h头文件