我理解的NDK

一、NDK和JNI简介

NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。

NDK集成了交叉编译器(交叉编译器需要UNIX或LINUX系统环境),并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

JNI的全称是Java Native Interface,它提供了若干的API实现了Java和其他语言的通信(主要是C和C++),是java语言提供的Java和C/C++相互沟通的机制。

二、为什么使用NDK和JNI

NDK

1、代码的保护。由于apk的java层代码很容易被反编译,而C/C++库反汇难度较大。

2、可以方便地使用现存的开源库。大部分现存的开源库都是用C/C++代码编写的。

3、提高程序的执行效率。将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。

4、便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。

JNI

JNI的目的是使java方法能够调用c实现的一些函数。

三、Android.mk

1、简介:

Android.mk文件是Android提供的一种makefile文件,是为了向编译系统描述你的源代码。

2、用途:

用来指定诸如编译生成so库名、引用的头文件目录、需要编译的.c/.cpp文件和.a静态库文件等。

3.使用和语法:

一个Android.mk文件可以编译多个模块,每个模块属下列类型之一:

1)APK程序 -- 一般的Android程序,编译打包生成apk文件

2)JAVA库 -- java类库,编译打包生成jar文件

3)C\C++应用程序 -- 可执行的C\C++应用程序

4)C\C++静态库 -- 编译生成C\C++静态库,并打包成.a文件

5)C\C++共享库 -- 编译生成共享库(动态链接库),并打包成.so文, 有且只有共享库才能被安装/复制到您的应用软件(APK)包中。

示例

#简单编译动态库
LOCAL_PATH := $(call my-dir) //这里返回当前Android.mk所在的目录的路径
include $(CLEAR_VARS)        //清除LOCAL_PATH外的类似LOCAL_XXX 的变量
LOCAL_MODULE    := demo      //定义.so文件的名字
LOCAL_SRC_FILES := demo.c    //指定需要编译的源代码文件 demo.c
include $(BUILD_SHARED_LIBRARY) //执行编译动态库命令,编译动态库

#编译动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = libhellod
LOCAL_SRC_FILES = hellod.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_SHARED_LIBRARY)  

#使用动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellod
LOCAL_MODULE_TAGS := debug
LOCAL_SHARED_LIBRARIES := libc libcutils libhellod
LOCAL_LDLIBS += -ldl
LOCAL_SRC_FILES := maind.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)

基本语法:

“#” 注释

“:=” 赋值

“+=” 追加

“$” 引用某变量的值

模块描述变量:

(1)LOCAL_PATH: 这个变量用于给出当前文件的路径。

必须在 Android.mk 的开头定义,可以这样使用:LOCAL_PATH := $(call my-dir), 如当前目录下有个文件夹名称 src,则可以这样写 $(call src),那么就会得到 src 目录的完整路径。这个变量不会被$(CLEAR—VARS)清除,因此每个 Android.mk 只需要定义一次(即使在一个文件中定义了几个模块的情况下)。

(2)include
$(CLEAR-VARS): 清除除了LOCAL_PATH的所有变量。

这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

(3)LOCAL_MODULE: 这是模块的名字,它必须是唯一的,而且不能包含空格。
必须在包含任一的$(BUILD—XXXX)脚本之前定义它。模块的名字决定了生成文件的名字。

(4)LOCAL-MODULE-FILENAME:用户可重新定义最终生成的目标文件名。

(5)LOCAL-SRC_FILES: 这是需要编译的源代码文件列表。

只要列出要传递给编译器的文件,因为编译系统自动计算依赖。

注意源代码文件名称都是相对于 LOCAL—PATH的,你可以使用路径部分,例如: LOCAL—SRC—FILES := foo.c toto/bar.c\ Hello.c 文件之间可以用空格或Tab键进行分割,换行请用"\" 如果是追加源代码文件的话,请用LOCAL—SRC—FILES += 注意:可以LOCAL—SRC—FILES := $(call all-subdir-java-files)这种形式来包含local_path目录下的所有java文件。

(6)LOCAL-C-INCLUDES: 可选变量,表示头文件的搜索路径。
默认的头文件的搜索路径是LOCAL_PATH目录。

(7)LOCAL-STATIC-LIBRARIES: 表示该模块需要使用哪些静态库,以便在编译时进行链接。

(8)LOCAL-SHARED-LIBRARIES: 表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。只是加载静态库中用到的函数。

注意:它不会附加列出的模块到编译图,也就是仍然需要在Application.mk 中把它们添加到程序要求的模块中。

(9)LOCAL-WHOLE-STATIC-LIBRARIES:会加载整个静态库

(10)LOCAL-LDLIBS: 指定该模块依赖的其他库。

例:LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog

这对于 使用‘-l’前缀传递指定库的名字,‘-L’指定库的路径。 例如,LOCAL-LDLIBS := -lz表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so

(11)LOCAL-JNI-SHARED-LIBRARIES:

定义了要包含的so库文件的名字,如果程序没有采用jni,不需要 。 LOCAL-JNI-SHARED-LIBRARIES := libxxx 这样在编译的时候,NDK自动会把这个libxxx打包进apk; 放在youapk/lib/目录下

四、NDK提供的GNU Make函数宏和系统变量

1.GNU Make函数宏

GNU Make函数宏,必须通过使用‘$(call )‘来调用,返回值是文本化的信息。

(1)my-dir:返回当前
Android.mk 所在的目录的路径,相对于 NDK 编译系统的顶层。这是有用的,在 Android.mk 文件的开头如此定义:

    LOCAL_PATH := $(call my-dir)

(2)all-subdir-makefiles: 返回一个位于当前‘my-dir‘路径的子目录中的所有Android.mk的列表。

   例如,某一子项目的目录层次如下:
        src/foo/Android.mk
        src/foo/lib1/Android.mk
        src/foo/lib2/Android.mk
  如果 src/foo/Android.mk 包含一行:
       include $(call all-subdir-makefiles)
  那么它就会自动包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。
  这项功能用于向编译系统提供深层次嵌套的代码目录层次。
  注意,在默认情况下,NDK 将会只搜索在 src/*/Android.mk 中的文件。

(3)this-makefile: 返回当前Makefile
的路径(即这个函数调用的地方)

(4)parent-makefile: 返回调用树中父
Makefile 路径。即包含当前Makefile的Makefile 路径。

(5)grand-parent-makefile:返回调用树中父Makefile的父Makefile的路径

(6)import-module:

允许寻找并inport其它modules到本Android.mk中来。

它会从NDKMODULEPATH寻找指定的模块名。

$(call import-module,)

2.GNU Make系统变量

这些 GNU Make变量在你的 Android.mk 文件解析之前,就由编译系统定义好了。

注意在某些情况下,NDK可能分析 Android.mk 几次,每一次某些变量的定义会有不同。

(1)CLEAR-VARS: 指向一个编译脚本,几乎所有未定义的
LOCAL_XXX 变量都在"Module-description"节中列出。必须在开始一个新模块之前包含这个脚本:include$(CLEAR-VARS),用于重置除LOCAL-PATH变量外的,所有LOCAL-XXX系列变量。

(2)BUILD-SHARED-LIBRARY: 指向编译脚本,根据所有的在
LOCAL-XXX 变量把列出的源代码文件编译成一个共享库。 注意,必须至少在包含这个文件之前定义 LOCAL-MODULE 和 LOCALSRCFILES。

(3)BUILD-STATIC-LIBRARY: 一个
BUILD-SHARED-LIBRARY 变量用于编译一个静态库。静态库不会复制到的APK包中,但是能够用于编译共享库。

   示例:include $(BUILD_STATIC_LIBRARY)
   注意,这将会生成一个名为 lib$(LOCAL_MODULE).a 的文件

(4)BUILD-EXECUTABLE: 与前面类似,它也指向一个编译脚本,收集自从上次调用
include $(CLEAR-VARS) 后的所有LOCAL_XXX信息。并决定如何将你列出的Source编译成一个可执行Native程序。 include $(BUILD-EXECUTABLE)

(5)PREBUILT-SHARED-LIBRARY:把这个共享库声明为
“一个” 独立的模块。 指向一个build 脚本,用来指定一个预先编译好多动态库。

与BUILD-SHARED-LIBRARY and BUILD-STATIC-LIBRARY不同,此时模块的LOCAL-SRC-FILES应该被指定为一个预先编译好的动态库,而非source file.

LOCAL-PATH := $(call my-dir) include $(CLEAR-VARS) LOCAL-MODULE := foo-prebuilt # 模块名 LOCAL-SRC-FILES := libfoo.so # 模块的文件路径(相对于 LOCAL_PATH)

include $(PREBUILT-SHARED-LIBRARY) # 注意这里不是 BUILD-SHARED-LIBRARY

这个共享库将被拷贝到 $PROJECT/obj/local 和 $PROJECT/libs/(stripped)

(6)PREBUILT-STATIC-LIBRARY: 预先编译的静态库。同上。

(7)TARGET_ARCH:
目标 CPU平台的名字

(8)TARGET_PLATFORM: Android.mk
解析的时候,目标 Android 平台的名字.详情可考/development/ndk/docs/stable- apis.txt.

   android-3 -> Official Android 1.5 system images
   android-4 -> Official Android 1.6 system images
   android-5 -> Official Android 2.0 system images

(9)TARGET-ARCH-ABI: value:armeabi
、 armeabi-v7a和X86。。

时间: 2024-10-05 23:08:21

我理解的NDK的相关文章

深入理解Android NDK日志符号化

为了进行代码及产品保护,几乎所有的非开源App都会进行代码混淆,这样当收集到崩溃信息后,就需 要进行符号化来还原代码信息,以便开发者可以定位Bug.基于使用SDK和NDK的不同,Android的崩溃分为两类:Java崩溃和C/C++崩溃.Java崩溃通过mapping.txt文件进行符号化,比较简单直观,而C/C++崩溃的符号化则需要使用Google自带的一些NDK工具,比如ndk-stack.addr2line.objdump等.本文不去讨论如何使用这些工具,有兴趣的朋友可以参考同事写的另一篇

【转】JNI和NDK的区别

原文网址:http://blog.csdn.net/ithomer/article/details/6828830 NDK(Native Development Kit)“原生”也就是二进制 android常用的开发方式是java封装的库,而这些库的底层实现是由C/C++实现,如媒体,图形库等 java调用这样实现就需要用JNI(Java Native Interface) 平时用的也就是google给我们封装的好的库,即底层实现用的不是Java,但都有统一的Java接口 NDK的作用是“我们自

[Google Android] 理解NDK(1)-- 编译Android .so文件

原帖地址:http://www.cnblogs.com/tamer/archive/2011/01/18/1938307.html 说白了就是c代码做成动态库,被java代码调用(JNI).用C写不出可以直接在Android上跑的可执行程序来. NDK开发需要一个交叉编译环境,需要安装Cygwin, NDK. 这些准备工作就不说了网上很多,当然也可以问我. 讲一下.so文件的生成 ----------------------------------------------------------

对于Android NDK编译器ARM和Thumb模式的理解

编译NDK项目时,编译器无法识别arm汇编,设置LOCAL_ARM_MODE := arm后问题解决, NDK文档上对LOCAL_ARM_MODE的说明如下: LOCAL_ARM_MODE By default, ARM target binaries are generated in 'thumb' mode, where each instruction are 16-bit wide, and linked with /thumb STL libraries. You can define

基于 Android NDK 的学习之旅----- C调用Java

http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html 基于 Android NDK 的学习之旅----- C调用Java许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现. 下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态方法. 1.主要流程 1.  新建一个测试类TestProvider.java a)       

Android NDK学习笔记(一) 为什么要用NDK?

NDK是什么 NDK是Native Development Kit的简称,即本地开发工具包.通过NDK,Android允许开发人员使用本地代码语言(例如C/C++)来完成应用的部分(甚至全部)功能.注意:由于翻译原因,有些地方也把Native翻译为"原生". NDK是SDK的一个补充,可以帮助你做这些事情: 生成可以在ARM CPU,Android 1.5(及以上)平台运行的JNI兼容的共享库. 将生成的共享库放置在应用程序项目路径的合适位置,使其能自动地添加进你最终的(和经过签名的)

【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据传输二(引用数据类型)(附源码) 基于 Android NDK 的学习之旅-----数据传输(引用数据类型) 接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1.  String 字符串传输 a)         上层定义一个native的方法

从NDK在非Root手机上的调试原理探讨Android的安全机制(转载)

从NDK在非Root手机上的调试原理探讨Android的安全机制 最近都在忙着研究Android的安全攻防技术,好长一段时间没有写博客了,准备回归老本行中--Read the funcking android source code.这两天在看NDK文档的时候,看到一句话"Native debugging ... does not require root or privileged access, aslong as your application is debuggable".咦

Android NDK R9环境配置,开发教程

最近,在学习android ndk开发,配置环境的时候遇到了些问题,总算不负有心人--在这里记录哈过程,与筒子们分享哈--想学NDK的筒子们有福啦-- 教程本人亲测,非copy的-- 如有什么不明白的地方,可以留言 大神也可以进来瞧瞧有什么不对的地方,请指教两招 ----------------------------------------------------------------------------------------------------------------------