您的位置:首页 > 移动开发 > Android开发

Android NDK开发入门

2016-01-12 20:16 549 查看
  接触Android有一段时间了,NDK算是一道坎,因为对c语言不熟悉,所以也没怎么去接触这一块,但是最近的学习,越发的觉得,如果想让app能有更高的效率,比如在图像的处理方面,游戏开发方面,甚至于要做一些涉及系统层面的操作时,不可避免的要去用到NDK。通过利用c/c++的能力来弥补java的缺点。

NDK的好处:

1. 提高程序的执行效率

2. 代码保护,java层容易被反编译,但是ndk层较难

3. 便于移植,而且也能方便使用c/c++开源库

这个是Android Studio的ndk入门版,于eclipse的不同,使用的是gradle进行构建。

下面就从hello ndk开始进入ndk的世界。这个sample可以在下载了ndk之后在ndk文件夹中的sample文件夹下找到,导入Android Stuido就可以开始学习了。

Android Studio中有两种方法去使用c/c++的代码:

1. 使用现有的.so库

2. 使用项目中当前的c/c++代码

使用现有的.so库

这一步是比较简单的,只要把所有的.so文件拷贝到对应的目录文件下就可以了。要对应好不同的平台。



接着,在要使用的地方加上加载库的代码,就可以使用当前的.so库了。

String libName = "helloNDK"; // 加载的module的名字,不用加.so
System.loadLibrary( libName );


库的名字构成是由,lib + moduleName + .so,当去加载库时,只需要使用moduleName不用加前缀或后缀。

如果想改变使用的jnilibs的路径,可以在gradle中定义如下的代码,既可以改变引用的.so的文件路径。

android {
sourceSets.main {
jniLibs.srcDir 'src/main/filePath' // 设置有so库的位置
}
}


使用当前项目中的c/c++代码

这个是很方便的一个开发方式,而且通过gradle去配置,将原本eclipse的复杂度降低了。主要要做以下的事情

1. 配置ndk的路径

2. 在gradle中配置ndk的module

3. 添加c/c++文件

配置ndk的路径

  可以通过在项目的ModuleSetting中设置,右键项目,选择ModuleSetting,在sdk location中可以选择下载或者是配置路径,下载的话去官网就有的下载了。

  也可以在工程根目录下的local.properties中增加ndk的配置。

ndk.dir=/Users/ndkPath


在gradle中配置ndk module

指明将要编译的c/c++代码

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"

defaultConfig {
...
ndk {
moduleName "modulename"
}
}
}


当然可以在增加一些指定的配置,类似于cFlags, stl, ldLibs.

ndk {
moduleName "myEpicGameCode"
cFlags "-DANDROID_NDK -D_DEBUG DNULL=0" // 定义宏变量
ldLibs "EGL", "GLESv3", "dl", "log"         // 链接这些库
stl "stlport_shared"                        // Use shared stlport library
}


添加c/c++文件

配置好上述步骤之后,我们就可以开始开发我门的c/c++代码了。c/c++代码的位置是在src/main/jni目录下,文件包括

1. Android.mk

2. Application.mk

3. c/c++文件包括头文件

当然和引入so库相似,对于c/c++的代码的位置也是可以改变,通过在gradle中进行配置

android {
sourceSets.main {
jni.srcDirs 'src/main/path' // your path
}
}


可以通过productFlavors去设定对于不同平台时候的不同的变量,比如通过设置全局变量指定不同平台去加载不同的头文件。

又或者编译制定平台的so库而不是所有的平台。通过这个方法来得到我们想要的结果。

android {

productFlavors {
x86 {
ndk {
abiFilter "x86"
}
}
arm {
ndk {
abiFilter "armeabi-v7a"
}
}
}

}


c/c++ 文件

这里开始真正的关于Hello NDK的代码编写。首先在MainActivity.java中先定义好我们的native的方法,使用的native的关键字。

private native String sayHello();
// 在btn的setListener中设定toast
Toast.makeText(MainActivity.this, sayHello(), Toast.LENGTH_SHORT).show();


在src/main/jni目录下创建hello-jni.c文件,方法名字的定义要注意,否则会引起方法找不到的错误,方法名称为Java_+完整类路径+方法。当然,为了防止手动的错误,可以使用javah的命令生成,具体请继续往下看。

#include <string.h>
#include <jni.h>

jstring Java_com_yxp_hellondk_MainActivity_sayHello( JNIEnv* env, jobject thiz ) {
return (*env)->NewStringUTF(env, "Hello NDK!");
}


使用javah生成头文件

# 进入src/main/java文件夹,-d指明输出文件路径
javah -d ../jni com.example.MainActivity


在gradle指定ndk module

defaultConfig {
...
ndk {
moduleName "hello-jni"
}
}


回到MainActivity.java中,引入ndk library,library的名称也就是module name无需加前缀或者后缀。

static {
System.loadLibrary("hello-jni");
}


Application.mk(官网

Application.mk文件的路径是在src/main/jni目录下,用来描述工程中需要用到的native库,包括静态库,共享库和可执行文件。在HelloNdk项目中的Application.mk内容如下:

APP_ABI := all


默认情况下,NDK的编译系统根据 “armeabi” ABI生成机器代码。可以使用APP_ABI 来选择一个不同的ABI。

比如:为了在ARMv7的设备上支持硬件FPU指令。可以使用:

APP_ABI := armeabi-v7a


当然,当有多个定义时,以空格分开。

Android.mk(官网

Application.mk文件的路径是在src/main/jni目录下,Android.mk文件是用来描述ndk相关源文件,便于构建工程。在构建的过程中它会被解析多次,以完成构建。在Android.mk文件中,可以定义一个到多个模块,模块之间可以共享文件。在文件当中,不用列出具体的头文件或者依赖,这些ndk编译器都会自动完成。

ndk编译系统的系统的变量都有如下的定义:

LOCAL_为前缀的变量,比如LOCAL_MODULE

以PRIVATE_、NDK_、APP_为前缀的变量

全小写字母的变量

所以在Android.mk文件中使用自定义变量的时候,建议使用MY_前缀。

在这个HelloNdk工程中,Android.mk文件定义如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)


CLEAR_VARS变量,主要在构建的时候会清除所有的LOCAL_开头的变量的定义,包括LOCAL_MODULE、LOCAL_SRC_FILES等,但是不包括LOCAL_PATH。由于在构建的时候这些变量都是全局的变量,所以在一个module在构建的时候,应该不受其他module的变量影响。使用方式就是:

inclued $(CLEAR_VARS)


my-dir属于一个方法(function)的全局定义,返回当前Android.mk文件的文件路径,值得注意的是,这个方法是包含最后一个构建文件的路径,所以这个定义要在开头,尤其是包含其他的文件的时候。使用的方法是

$(call my-dir)


LOCAL_PATH变量是指明当前文件的位置,必须定义在Android.mk文件的开头,定义方式:

LOCAL_PATH := $(call my-dir)


BUILD_SHARED_LIBRARY变量,收集从最近的CLEAR_VARS之后的LOCAL_前缀的变量,并以此生成so库。使用方法:

include $(BUILD_SHARED_LIBRARY)


参考文档:

NDK with Android Studio
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: