首页
社区
课程
招聘
[分享]Android NDK入门
2010-12-9 11:16 16448

[分享]Android NDK入门

2010-12-9 11:16
16448
这是来自国外某论坛的文章,当时学习NDK的时候碰巧搜到,可以作为入门的好材料
地址: http://marakana.com/forums/android/examples/49.html

Updated for NDK 1.6

While Android SDK is great for application development, every once in a while you may need access to native code. This code is usually done in C. While you were able to access native code via Java Native Interface (JNI) all along, the process was rather hard. You would've typically had to compile everything on your host computer for the target architecture, requiring you to have the entire toolchain on your development machine.

Android NDK (Native Development Kit) simplifies working with native code. It includes the entire toolchain needed to build for your target platform (ARM). It is designed to help you create that shared library.

Note that native code accessible via JNI still runs inside the Dalvik VM, and as such is subject to the same life-cycle rules that any Android application lives by. The advantage of writing parts of your app code in native language is presumably speed in certain cases.

Note: I'm using <NDKHOME> to refer to the root directory in which you installed your NDK. For me that's /Users/marko/WorkArea/android-ndk-1.6_r1. I'm assuming all other directories and files are relative to your Eclipse project root, in my case /Users/marko/Workspace/Android/NDKDemo.

Overview
这里是图片,抱歉这里没有显示,

We are roughly going to do this:

1. Create the Java class representing the native code
2. Create the native code header file
3. Implement the native code by writing your C code
4. Compile everything and build you Shared Library
5. Use your native code inside Android activity

Create Native Library

This is just a Java file that lives in standard src directory in your Eclipse project. It serves as the glue to the native code that we'll write later.

/src/com.marakana/NativeLib.java

package com.marakana;

public class NativeLib {

  static {
    System.loadLibrary("ndk_demo");
  }
  
  /** 
   * Adds two integers, returning their sum
   */
  public native int add( int v1, int v2 );
  
  /**
   * Returns Hello World string
   */
  public native String hello();
}


Create C Header File
In your project bin directory (in my case, <EclipseWorkspace>/NDKDemo/bin), run javah tool to create the JNI header file.

Next, create a jni directory in your project directory (in my case, <EclipseWorkspace>/NDKDemo/jni).

Next, copy the JNI header from <EclipseWorkspace>/NDKDemo/bin to <EclipseWorkspace>/NDKDemo/jni

Here's my command line:

NDKDemo/bin$ javah -jni com.marakana.NativeLib
NDKDemo/bin$ mv com_marakana_NativeLib.h ../jni/


Write the C Code

In your <EclipseWorkspace>/NDKDemo/jni/ folder, create ndk_demo.c file. This is where we'll implement the native code. To start, copy the function signatures from the header file, and provide the implementation for those functions. In this example, the header file looks like this:

<EclipseWorkspace>/NDKDemo/jni/com_marakana_NativeLib.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_marakana_NativeLib */

#ifndef _Included_com_marakana_NativeLib
#define _Included_com_marakana_NativeLib
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_marakana_NativeLib
 * Method:    add
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_marakana_NativeLib_add
  (JNIEnv *, jobject, jint, jint);

/*
 * Class:     com_marakana_NativeLib
 * Method:    hello
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_marakana_NativeLib_hello
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


And the corresponding implementation looks like this:

<EclipseWorkspace>/NDKDemo/jni/ndk_demo.c
#include "com_marakana_NativeLib.h"

JNIEXPORT jstring JNICALL Java_com_marakana_NativeLib_hello
  (JNIEnv * env, jobject obj) {
    return (*env)->NewStringUTF(env, "Hello World!");
}

JNIEXPORT jint JNICALL Java_com_marakana_NativeLib_add
  (JNIEnv * env, jobject obj, jint value1, jint value2) {
    return (value1 + value2);
}



Build The Library


To build the library, first we need to create a makefile for how to compile the C code:

<EclipseWorkspace>/NDKDemo/jni/Android.mk


LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := ndk_demo
LOCAL_SRC_FILES := ndk_demo.c

include $(BUILD_SHARED_LIBRARY)


Next, we need to tell NDK how to build the shared library and put it in the correct place inside the Eclipse project. To do this, create a folder <NDKHOME>/apps/ndk_demo/ and inside this folder create the Application file:

<NDKHOME>/apps/ndk_demo/Application
APP_PROJECT_PATH := $(call my-dir)/project
APP_MODULES      := ndk_demo


Next, create a symbolic link <NDKHOME>/apps/ndk_demo/project to your Eclipse project:

ln -s ~/Workspace/Android/NDKDemo <NDKHOME>/apps/ndk_demo/project

If you are on Windows, or another OS that doesn't support symbolic links, you may have to copy entire Eclipse project into <NDKHOME>/apps/ndk_demo/project directory, then copy back to Eclipse. I'm running all this on Mac OS X 10.6 and I assume Linux-type shell.

You can now to to your <NDKHOME> and run make APP=ndk_demo

The output should look lie this:
android-ndk-1.5_r1$ make APP=ndk_demo
Android NDK: Building for application 'ndk_demo'    
Compile thumb  : ndk_demo <= sources/ndk_demo/ndk_demo.c
SharedLibrary  : libndk_demo.so
Install        : libndk_demo.so => apps/ndk_demo/project/libs/armeabi


You can now refresh your Eclipse project and you should /lib/ directory containing your libndk_demo.so file.

Calling Native Code from Java

So now that we have the native C library implemented, compiled, and placed in the right place, let's see how we can call it from our Activity. It's actually rather simple - you just have to instantiate the instance of your NativeLib class and from there on, it's just a regular Java object.

/src/com.marakana/NDKDemo.java
package com.marakana;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class NDKDemo extends Activity {
  NativeLib nativeLib;

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    nativeLib = new NativeLib();
    String helloText = nativeLib.hello();

    // Update the UI
    TextView outText = (TextView) findViewById(R.id.textOut);
    outText.setText(helloText);

    // Setup the UI
    Button buttonCalc = (Button) findViewById(R.id.buttonCalc);

    buttonCalc.setOnClickListener(new OnClickListener() {
      TextView result = (TextView) findViewById(R.id.result);
      EditText value1 = (EditText) findViewById(R.id.value1);
      EditText value2 = (EditText) findViewById(R.id.value2);

      public void onClick(View v) {
        int v1, v2, res = -1;
        v1 = Integer.parseInt(value1.getText().toString());
        v2 = Integer.parseInt(value2.getText().toString());

        res = nativeLib.add(v1, v2);
        result.setText(new Integer(res).toString());
      }
    });
  }
}


The UI for this example is not that significant, but I'm going to include it here for the sake of completeness. 

/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView android:layout_width="fill_parent"
    android:layout_height="wrap_content" android:text="NDK Demo"
    android:textSize="22sp" />
  <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:id="@+id/textOut"
    android:text="output"></TextView>
  <EditText android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:id="@+id/value1"
    android:hint="Value 1"></EditText>
  <TextView android:id="@+id/TextView01" android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:text="+"
    android:textSize="36sp"></TextView>
  <EditText android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:id="@+id/value2"
    android:hint="Value 2"></EditText>
  <Button android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:id="@+id/buttonCalc"
    android:text="="></Button>
  <TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content" android:text="result"
    android:textSize="36sp" android:id="@+id/result"></TextView>
</LinearLayout>


Output
模拟器截图,不好传,可以自己实现

阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

收藏
点赞6
打赏
分享
最新回复 (9)
雪    币: 208
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
memory零九 2010-12-9 11:24
2
0
这里是源代码
上传的附件:
雪    币: 114
活跃值: (81)
能力值: (RANK:60 )
在线值:
发帖
回帖
粉丝
沙加L 1 2011-3-14 15:25
3
0
谢谢楼主的分享,我最近做的一个实验系统中,也需要用到NDK的开发,这个对我的帮助很大的。同时,楼主也可以看一下我分享的一个pdf文件,它是中文的,是【eoe特刊】第七期:NDK。这个pdf文件也是很不错,可以看一下
雪    币: 233
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
myicefox 2011-3-14 15:34
4
0
这个NDK太老了。。。还是r1,现在都是r5b了,
新的NDK从r5开始支持纯C++代码了,不再需要java里面的JNI调用了,这点对一些应用开发很有帮助,不过可惜的是,这个特性要求的最低Andorid平台为2.3 。。。
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
bushimajia 2011-3-14 15:37
5
0
来凑个热闹,字数太少.....
雪    币: 114
活跃值: (81)
能力值: (RANK:60 )
在线值:
发帖
回帖
粉丝
沙加L 1 2011-3-14 18:11
6
0
myicefox,你有一些关于NDK的资料吗?可以共享一下吗?
雪    币: 233
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
myicefox 2011-3-14 18:19
7
0
NDK并没有什么特别的地方啊,就是C++而已,只要注意android的Native API就行了,JNI都是好老的东西了,也没什么可说的
雪    币: 114
活跃值: (81)
能力值: (RANK:60 )
在线值:
发帖
回帖
粉丝
沙加L 1 2011-3-14 18:24
8
0
谢谢,恩,!
雪    币: 233
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
myicefox 2011-3-14 18:41
9
0
其实我想说的是,NDK最大的资料就是NDK的官方文档,写的很详细,真的很详细
雪    币: 114
活跃值: (81)
能力值: (RANK:60 )
在线值:
发帖
回帖
粉丝
沙加L 1 2011-3-14 18:46
10
0
是的,对于一个开发工具发布者来说,它的文档肯定写得很好!
游客
登录 | 注册 方可回帖
返回