Android NDK开发入门指引(有源码)

Android NDK 开发入门指引

 

前言:

       Android NDK 是一套工具,允许 Android 应用开发者嵌入从 C C++ 源代码文件编译来的本地机器代码到各自的应用软件包中 , 并通过 JNI 进行访问。 Android 1.5 开始支持 NDK.

 

环境搭建:

       NDK 开发需要安装以下物体 :

1.cygwin ( 需要 1.7 以上版本,下载地址: http://www.cygwin.com 官方明确表示 MSys or Cygwin 1.5 is not supported), 这个我用的是在线安装方法(并且是全安装,非常大,很耗时)

安装好后启动 cygwin, 运行 :

Make –v

看到如下所示就 ok ( 注意 :GNU Make 3.81 以上版本 )



2.NDK (android-ndk-r4b) ,此文档只针对 r4b 版进行说明 , ndk 可以到官方网 http://developer.android.com 上进行下载, 但这个网站已被 zf 和协,我是在这里下载: http://d131.d.iask.com/fs/800/1/c1631bdc5eaf7b8309db9cb23311693035788482/zip/android-ndk-r4b-windows.zip 如下载不了,直接向我要吧 .

Ndk 下载下来随意解压到一个目录即可 ( 路径中不能有空格 )

: D:/android/android-ndk-r4b

 

然后为 cygwin 配好我们的 ndk PATH 环境

cygwin 用户路径 C:/cygwin/home/huangdingwu ( 请替换相应用户名 )

打开 .bash_profile

在文件末尾加上:

 

ANDROID_NDK_ROOT=/cygdrive/d/android/android-ndk-r4b

export ANDROID_NDK_ROOT

PATH=${ANDROID_NDK_ROOT}:${PATH}

配好后重新打开 cygwin

输入:

Ndk-build

 

如出现如下提示表示路径已配好:

 


3.eclipse + android sdk   ( 这个 大家应该都已经安装好了 )

4.windows Jdk 安装配置    

第一步:下载 JDK
   JDK Java Developement Kit 的缩写,包括 Java 编译器和运行时环境 j2re   可以从 SUN Java 站点下载
http://java.sun.com/javase/downloads/index.jsp
http://www6.software.ibm.com/dl/idpe/idpe-p?S_TACT=104AHW02 
或它的前一面: http://www-106.ibm.com/developerworks/java/jdk/eclipse/


第二步:安装 JDK
  直接运行 JDK 的安装程序,选择一个安装目录,按照安装向导即可轻松完成 JDK 的安装。如需了解安装细节,请参考 Java 2 SDK  Installation Notes for Microsoft Windows

第三步:设置环境变量

    JAVA_HOME=<JDK
安装目录 >
    Path=<
Path>;%JAVA_HOME%/bin;%JAVA_HOME%/jre/bin
   
(注意其实没有等号)
    
本人使用的是 jdk-6-windows-i586.exe 默认安装路径   C:/Program Files/Java/jdk1.6.0 JAVA_HOME=C:/Program Files/Java/jdk1.6.0

第四步:编译一个 Java 程序
  请用任何文本编辑器输入以下内容并保存为 Hello.java 文件(只能保存为 Hello.java ,不能使用别的文件名),请严格注意大小写:
public class Hello 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello, world."); 
    } 
}  
  然后打开控制台,切换到存放 Hello.java 的目录下,输入: javac Hello.java
  如果编译通过,屏幕上没有任何显示。否则,屏幕上会输出出错信息,请仔细检查源代码。

第五步:运行一个 Java 程序
  打开控制台,切换到存放 Hello.class 的目录下,然后输入: java Hello ( 注意大小写啊 !)
  稍等几秒钟,屏幕输出: Hello, world.
  说明运行成功!
   
如果不成功可能环境变量不正确

 

简单的 NDK Demo 程序

       好了,环境已搭建好, 现在我们开始建立一个简单的 ndk 程序来体验下整个 ndk 开发流程 :

第一步:首先我们在eclipse 中新建一个工程,工程名这里是NdkPassNormalData   在工程   中新建一个java:CallNativeDemo.java

内容如下:

package com.jiubang.Demo.Ndk.PassNormalData;

 

public class CallNativeDemo {

 

    static {

       System.loadLibrary ( "NdkPassDataDemo" );

// 注意库文件名,对于 NdkPassDataDemo 系统会在该类初始化时加载 //libNdkPassDataDemo.so , 切记勿画蛇添足加上前面的 lib .so 扩展名

    }

   

    public native int Sum( int a , int b); // 加上 native 表示该方法由 .so 实现

    public native String StrCat(String str1 , String str2);

}

编写好该 java 文件后,先编译,然后用 javah 生成 ndk 中我们需要的 c 头文件 :

进入到工程的 bin 目录下输入:

javah  -jni com.jiubang.Demo.Ndk.PassNormalData.CallNativeDemo

然后会在当前目录下生成com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo.h 文件

内容大概如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo */

 

#ifndef _Included_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo

#define _Included_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo

#ifdef __cplusplus

extern "C" {

#endif

/*

  * Class:     com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo

  * Method:    Sum

  * Signature: (II)I

  */

JNIEXPORT jint JNICALL Java_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo_Sum

  (JNIEnv *, jobject, jint, jint);

 

/*

  * Class:     com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo

  * Method:    StrCat

  * Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

  */

JNIEXPORT jstring JNICALL Java_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo_StrCat

  (JNIEnv *, jobject, jstring, jstring);

 

#ifdef __cplusplus

}

#endif

#endif

 

第二步:在我们新的工程中加一个名为:jni 的文件夹。这个文件夹就是放原生态c/c++ 的源码的地方,我们make 的时候cygwin 就是编译这个文件夹的。

第三步:在jni 文件夹里新建一个Android.mk 文件。注意,后缀为.mk , 且文件夹一定要小写

            Android.mk 的内容为:

                 LOCAL_PATH := $(call my-dir) <--------- 默认的,不需要更改

                 include $(CLEAR_VARS)           <-------- 默认的,不需要更改

                 LOCAL_MODULE    := native  <-------- java 类引用时的名称

                 LOCAL_SRC_FILES := myNative.c <------ jni 文件夹下的 c/c++ 的名称

                 include $(BUILD_SHARED_LIBRARY) <-- 默认的,不需要更改

 

LOCAL_PATH := $(call my-dir) <--------- 返回当前路径

include $(CLEAR_VARS)      <-------- 清除先前定义的环境变量

LOCAL_MODULE := NdkPassDataDemo <-------- java 类引用时的名称

LOCAL_CPP_EXTENSION := cpp

LOCAL_SRC_FILES := Fun.cpp <------ 需要编译的源文件

LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib –llog <-- log 要用到的库,这里暂时不大明白为什么库名是这样

include $(BUILD_SHARED_LIBRARY) <-- 这里指的是动态库

第四步:在jni 文件夹里新建一个 Fun.cpp 的文件。这个文件就是c/c++ 文件。

             Fun.cpp 的内容为:

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <android/log.h>

#include "com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo.h"

 

// 对应 public native int Sum( int a , int b) 的实现

jint JNICALL Java_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo_Sum(JNIEnv* aEnv, jobject aThis, jint aParamA, jint aParamB)

{

 

    int sum = 0;

    __android_log_print(ANDROID_LOG_INFO , "Ndk_PassNormalData" , "CallNativeDemo_Sum Coming");

    sum = aParamA + aParamB;

 

    FILE* file = fopen("/sdcard/hello.txt","w+");

 

    if (file != NULL)

    {

       fputs("HELLO WORLD!/n", file);

       fflush(file);

       fclose(file);

    }

 

 

    __android_log_print(ANDROID_LOG_INFO , "Ndk_PassNormalData" , "CallNativeDemo_Sum Leaving");

    return sum;

}

 

 

// 对应 public native String StrCat(String str1 , String str2) 实现

jstring JNICALL Java_com_jiubang_Demo_Ndk_PassNormalData_CallNativeDemo_StrCat(JNIEnv *aEnv, jobject aThis, jstring aStr1, jstring aStr2)

{

 

    __android_log_print(ANDROID_LOG_INFO , "Ndk_PassNormalData" , "CallNativeDemo_StrCat Coming");

 

    const char* str1 = aEnv->GetStringUTFChars(aStr1 , 0);

    const char* str2 = aEnv->GetStringUTFChars(aStr2 , 0);

 

    //char* str1 = (char*)(*aEnv)->GetStringUTFChars(aEnv ,aStr1 , 0);

    //char* str2 = (char*)(*aEnv)->GetStringUTFChars(aEnv ,aStr2 , 0);

 

    int str1_len = strlen(str1);

    int str2_len = strlen(str2);

 

    // char* pszRet = malloc(str1_len + str2_len + 1);

    char* pszRet = new char[str1_len + str2_len + 1];

    strcpy(pszRet, str1);

    strcat(pszRet, str2);

 

    //jstring jstrRet = (*aEnv)->NewStringUTF(aEnv, pszRet);

    jstring jstrRet = aEnv->NewStringUTF(pszRet);

    // free(pszRet);

    delete pszRet;

 

    __android_log_print(ANDROID_LOG_INFO , "Ndk_PassNormalData" , "CallNativeDemo_StrCat Leaving");

    return jstrRet;

}

 

然后就可以开始编译了 :

 

打开 cygwin, 进入到工程的 jni 目录,然后执行 ndk-build


 

有看到 Install OK

然后会发现工程目录下会多了一个 lib obj 的目录

 

最后在 android 工程里加上调用这些 ndk 本地方法的代码:

 

       

运行,得到结果:


 

更多的 jni 数据传递处理相关资料参见:

http://andilyliao.javaeye.com/blog/494255

http://blog.csdn.net/sunyujia/archive/2008/05/03/2371557.aspx

NDK 示例开发参考:

http://blog.csdn.net/GEOLO/archive/2010/10/20/5953941.aspx

 

本教程工程下载:

http://download.csdn.net/source/3224679

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值