首页 > 代码库 > 【译】NDK概述

【译】NDK概述

翻译自官方文档NDK概述

NDK概述

On this page

  1. NDK使用前
  2. 介绍
  3. NDK怎样工作
  4. Native Activitie和应用程序

开始前


本指南假设已经熟悉安卓开发中的本地程序的概念.

介绍


本节提供了NDK如何工作的高级说明。Android NDK是一组高级工具,允许你的Android应用程序中嵌入C或C++(“native code&rdquo)。在Android应用中使用本地代码的功能对于希望执行以下一项或多项操作的开发人员尤其有用:

  • 移植应用.
  • 重用现有库, 或提供自己的库以供重用.
  • 在某些情况下提高性能, 尤其像游戏一样的算密集的应用.

NDK如何工作


本节介绍在构建Android native应用程序时使用的主要组件, 并继续描述构建和打包过程.

主要组件

在构建应用程序时,您应该了解以下组件:

  • ndk-build: NDK的核心是构建脚本,然后使用ndk-build运行该脚本。这些脚本包含的内容是:
    • 能自动探测到开发环境以及应用程序项目文件确定要构建什么.
    • 生成二进制文件.
    • 拷贝二进制文件到你的应用中.

    更多信息, 请查看ndk-build.

  • Java: Android构建进程将Java源代码生成.dex(Dalvik可执行文件)文件,这个文件在运行Android操作系统的Dalvik虚拟机(“DVM”)中运行的。 即使应用程序根本不包含Java源代码,构建进程仍然会生成一个.dex可执行文件,这个可执行文件包含了本地组件。当开发Java组件时,使用native关键字来说明它是一个本地方法。例如下面的方法声明告诉编译器它的实现是在一个库中.

    When developing Java components, use the native keyword to indicate methods implemented as native code. For example, the following function declaration tells the compiler that the implementation is in a native library:

    publicnativeint add(int  x,int  y);
  • 本地动态库: NDK从本地源代码构建这些库或.so文件.

    注意: 如果两个库分别实现了相同的方法声明,在C中会发生衔接错误, "签名"意味着方法名唯一。在C++中, "签名"意味着不仅方法名称,还意味着其参数名称和类型.

  • 本地静态库: NDK还可以构建静态库或.a文件,你可以将其链接到其他库.
  • Java本地接口(JNI): JNI是Java和C ++组件彼此通信的接口.本指南假设知识JNI; 有关它的信息,请参阅 Java Navive接口规范.
  • 应用二进制接口(ABI): ABI准确地定义了应用程序的机器代码在运行时与系统交互。NDK根据这些定义构建.so文件。 不同的ABI对应于不同的体系结构:NDK包括对ARMEABI(默认),MIPS和x86的ABI支持。 有关更多信息,请参阅ABI管理.
  • Manifest: 如果您正在编写一个没有Java组件的应用程序, 则必须在manifest中声明NativeActivity类。在“native_activity.h”下, class in the . Native Activities和应用程序提供了有关如何执行此操作的更多详细信息。

以下两个项目只需要使用ndk-build 脚本进行构建,以及使用 ndk-gdb脚本进行调试。

  • Android.mk: 你必须在 jni目录中创建一个 Android.mk配置文件。ndk-build脚本将会查看这个文件,他定义了模块及名称,要编译的源文件,衔接标志和库。.
  • Application.mk: 此文件列举和描述应用程序需要的模块。此信息包括:
    • 编译用给于特定平台使用ABI.
    • 工具链.
    • 要包括的标准库(静态和动态STLport或默认系统).

流程

开发Android Native应用程序的一般流程如下:

  1. 设计应用程序, 决定Java中实现哪些部分, 以及本地代码实现哪些部分.

    注意: 虽然可以完全避免Java,你会发现Android Java框架对于包括控制显示和UI在内的任务非常有用.

  2. 像创建其它安卓项目一样创建安卓项目.
  3. 如果你只开发一个纯native应用程序,请在AndroidManifest.xml中声明NativeActivity类。有关详细信息,请参阅Native Activities和应用程序.
  4. 创建一个描述本地库的Android.mk文件,这个文件包含了在"JNI"目录下用于编译的名称,标识,衔接库和源文件.
  5. 或者,你可以创建一个Application.mk文件配置相应的ABI,工具链,发布/调试模式和STL。如果你没有任何配置,分别使用以下默认值:
    • ABI: armeabi
    • Toolchain: GCC 4.8
    • Mode: Release
    • STL: system
  6. 将原生代码放在项目的 jni目录下.
  7. 使用ndk-build编译本地库(.so, .a).
  8. 构建Java组件,生成可执行文件.dex文件.
  9. 将所有内容打包成APK文件,其中包含.so, .dex以及运行应用程序所需的其他文件.

Native Activities和应用程序


Android SDK提供了一个帮助类NativeActivity, 它允许你写一个完全的NativeActivityNativeActivity处理Android框架和你的本地代码之间的通信,所以你不必让它成为派生类或调用它的方法。你只需要在AndroidManifest.xml文件中声明你的应用程序是native应用程序。.

使用NativeActivity的Android应用程序仍然在其自己的虚拟机中运行,其它应用程序在沙盒中运行。你仍然可以通过JNI访问Android框架API,在某些情况下,例如对于传感器,输入事件,资源文件,NDK提供本地接口调用,而不必通过JNI调用。有关此类支持的详细信息,请参阅Android NDK Native APIs..

无论您是否正在开发native Activity, 我们建议你使用传统的Android构建工具创建项目。这样做能确保构建和打包的应用程序是正确构造的.

Android NDK为您提供两种选择来实现native activity:

  • native_activity.h头文件定义了NativeActivity类的native版本,它包含创建Native Activity所需的回调接口和数据结构。因为你应用程序的主线程处理回调,你的回调实现不能阻塞,如果回调实现阻塞,你可能会收到ANR(应用程序不响应)错误,因为您的主线程没有响应,直到回调返回。.
  • native_activity.h接口基础上, android_native_app_glue.h文件定义了一个静态辅助库。它产生另一个线程处理事件循环中的回调或输入事件。将这些事件移动到单独的线程防止任何回调阻塞你的主线程。.

<ndk_root>/sources/android/native_app_glue/android_native_app_glue.c 源文件是可用的, 允许你修改实现.

有关如何使用此静态库的更多信息,请查看native-activity示例应用程序和文档。 进一步阅读可以查看在<ndk_root>/sources/android/native_app_glue/android_native_app_glue.h文件中的注释.

使用native_activity.h接口

使用native_activity.h接口实现一个native activity

1.在你项目的根目录下创建一个jni目录。此目录存储所有本地代码.

2.在在AndroidManifest.xml文件中声明native activity文件中声明native activity.

   因为你的应用程序没有Java代码,请将android:hasCode设置false.

<applicationandroid:label="@string/app_name"android:hasCode="false">

   你必须设置activity标记(android:name属性)为NativeActivity.

<activityandroid:name="android.app.NativeActivity"
            android:label="@string/app_name">

       注意: 你可以创建一个NativeActivity的派生类,这是要把ndroid:name属性值设为派生类的类名.

  meta-data标签的android:value属性指定为动态库的名称, 他包含了应用程序的入口点(例如C/C++的main函数),库名省略lib前缀和.so后缀.

<meta-dataandroid:name="android.app.lib_name"
            android:value="native-activity"/>
            <intent-filter>
              <actionandroid:name="android.intent.action.MAIN"/>
              <categoryandroid:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
          </activity>
        </application>
      </manifest>

 

3.为native activity创建一个文件,并实现在 ANativeActivity_onCreate变量中命名的函数。当native activity开始运行时应用程序将调用这个函数。这个函数类似于C/C++中的main函数,它接收一个指向ANativeActivity结构的指针,该结构体包含了各种需要你编写实现的函数指针。在ANativeActivity->callbacks中的回调函数指针设置为回调的实现.

4.将ANativeActivity->instance字段设置为你想使用的任何特定数据实例的地址.

5.在Activity启动前可以实现你想做的其它一些工作.

6.在ANativeActivity->callbacks.中设置实现的其余回调,有关调用回调的更多信息,请查看 Activity生命周期..

7.开发应用程序的其余部分.

8.在项目的jni/目录中创建一个Android.mk file文件,描述本地模块信息以便构建系统编译。有关详细信息,请参阅Android.mk.

9.如果你有一个Android.mk文件, 使用ndk-build命令编译本地代码.

    $ cd <path>/<to>/<project>
    $ <ndk>/ndk-build

10.像以往一样构建和安装你的Android项目。如果您的本地代码在jni/目录中,构建脚本会自动将构建的.so文件打包到APK中.

【译】NDK概述