Android NDK编程入门
Android支持C和C++编译程序,使用NDK。方式如下(这里以简单的helloworld为例子):
使用ndk-build编译:
1. 在使用ndk-build工具的时候,首先要一个Android工程,可以按照如下命令:
a) 首先用android list 命令查看当前的SDK版本。
b) 之后选择一个版本作为项目的平台版本号,输入以下命令:
androidcreate project –n hello2 –p hello2 –t android-10 –k com.droider.hello2 –aMyActiviry
其中-n指的是Android工程的名称;-t指的是Android工程所需要的SDK平台版本;-p指的是工程的目录名;-k指的Android工程包名;-a指的是Activity的名称
2. 在建立好的工程目录中添加一个jni文件夹,并将hello.c文件复制进去,并编写Android.mk和Application.mk作为脚本文件,其中Application.mk是可选的。目的是描述在你的应用程序中所需要的模块(即静态库或动态库)。但是Android.mk是必须的,这里内容如下:
LOCAL_PATH :=$(call my-dir)
include$(CLEAR_VARS)
LOCAL_ARM_MODE:= arm
LOCAL_MODULE :=hello
LOCAL_SRC_FILES:= hello.c
include$(BUILD_EXECUTABLE)
LOCAL_PATH :=$(call my-dir) ,一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数‘my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
include $(CLEAR_VARS),CLEAR_VARS由编译系统提供((可以在 android 安装目录下的/build/core/config.mk文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让GNUMAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
LOCAL_MODULE := hello,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件。就是最后的文件名。
LOCAL_SRC_FILES:= helloworld.c,LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
此处虽没用到其他常用的还有:
LOCAL_C_INCLUDES:可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:LOCAL_C_INCLUDES := sources/foo或LOCAL_C_INCLUDES :=$(LOCAL_PATH)/../foo
TARGET_ARCH:目标 CPU平台的名字;TARGET_PLATFORM:Android.mk 解析的时候,目标Android 平台的名字;TARGET_ARCH_ABI:暂时只支持两个 value,armeabi 和 armeabi-v7a
LOCAL_STATIC_LIBRARIES:表示该模块需要使用哪些静态库,以便在编译时进行链接。
LOCAL_SHARED_LIBRARIES: 表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。
LOCAL_LDLIBS: 编译模块时要使用的附加的链接器选项。
LOCAL_ARM_MODE: 默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm如果你希望你的 module 是以 32 位指令的形式
LOCAL_CFLAGS: 可选的编译器选项,在编译 C 代码文件的时候使用
include $(callall-subdir-makefiles):返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。
include$(BUILD_PACKAGE)则是编译出一个apk。
include$(BUILD_STATIC_JAVA_LIBRARY)则是编译出jar包
3. 之后在cmd中输入命令 ndk-build就可以看到在libs/ armeabi下看到生成的文件。
4. 将文件拷贝到安卓虚拟机中,可以使用命令adb push hello /data/local;拷贝完毕后执行命令adb shellchmod 755 /data/local/hello;将文件改为可执行文件
5. 之后执行adb shell/data/local/hello;就可以看到执行成功的界面。
另外一种是使用eclipse来建立
1. 首先建立android工程,并在工程中新建文件夹jin,将hello.c文件和Android.mk文件导入jin文件夹中。
2. 在工程上右键选择Properties,点击Builders选项,之后点击New按钮,之后点击Program并点击OK按钮。
3. 配置如下:
------Main选项卡----------------
在“Location”中输入${env_var:ANDROID_NDK}/ndk-build.cmd
在“Working Diretcoty”中点击“BrowseWorkspace”来选取HelloJni目录
-------Refresh选项卡--------------
勾选“Refresh resourcesupon compl
勾选“The entireworkspace”,
勾选“Recuresivelyinclude sub-fol
--------BuildOptions选项卡-------
勾选“After a “Clean””,
勾选“During manualbuilds”,
勾选“During auto builds”,
勾选“Specify workingset of relev”。
点击“Specify Resources…”
勾选工程的“jni“目录,并点击finish之后点击确定,点击OK后会自动在libs/armeabi目录下创建生成的文件。
Android的NDK快速开发
1. 打开Eclipse,Window->Preferences->Android->NDK,设置NDK路径
2. 建立一个Android工程,并且在工程上右键点击Android Tools->Add Native Support
这时候工程就会多一个jni的文件夹,jni下有Android.mk和ndktest.cpp文件。Android.mk是NDK工程的Makefile,ndktest.cpp就是NDK的源文件。
1. 在ndktest.cpp中写入代码
#include <jni.h>
extern "C"
{
JNIEXPORT
jstring JNICALL Java_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv*env, jobject thiz);
}
JNIEXPORT
jstring JNICALLJava_com_example_ndktest_MainActivity_stringFromJNI(JNIEnv *env,jobject thiz){
returnenv->NewStringUTF("Hellojni");
}
使用Alt + '/'可以代码提示
NI接口的命名规范是:Java_ + 调用该方法的包名(包名的点用_代替) + _ + 调用该接口的类名 + _+ 方法名,对于实例方法,有两个参数是必要的,一个JNI的环境指针JNIEnv *,另一个是调用该方法的Java实例jobject
5.在MainActivity中添加代码。
static{
System.loadLibrary("ndtest");
}
//声明JNI层的原生方法,使用native关键字
public native String stringFromJNI();
其中实现了一个编辑框的事件,代码如下:
public void testndk(View view){
editText.setText(stringFromJNI());
}
1. 工程右键选择properties->Builders->New->Program->ok
将编译器up到最先位置
这个时候就会在lib->armeabi下生成libndktest.so文件。这就是我们需要的动态库
之后运行就可以了。