Android NDK 简介

NDK 产生的背景

Android 平台从诞生起,就已经支持 CC++ 开发。众所周知,Android 的 SDK 基于 Java 实现,这意味着基于Android SDK 进行开发的第三方应用都必须使用 Java 语言。但这并不等同于“第三方应用只能使用 Java”。在Android SDK 首次发布时,Google 就宣称其虚拟机 Dalvik 支持 JNI 编程方式,也就是第三方应用完全可以通过 JNI 调用自己的 C 动态库,即在 Android 平台上,“Java+C”的编程方式是一直都可以实现的。不过,Google 也表示,使用原生 SDK 编程相比 Dalvik 虚拟机也有一些劣势,Android SDK 文档里,找不到任何 JNI 方面的帮助。即使第三方应用开发者使用 JNI 完成了自己的 C 动态链接库(so)开发,但是 so 如何和应用程序一起打包成 apk 并发布?这里面也存在技术障碍。比如程序更加复杂,兼容性难以保障,无法访问Framework API,Debug 难度更大等。开发者需要自行斟酌使用。于是 NDK 就应运而生了。NDK 全称是 Native Development Kit。NDK 的发布,使“Java+C”的开发方式终于转正,成为官方支持的开发方式。NDK 将是 Android 平台支持 C 开发的开端。

为什么使用 NDK

1.代码的保护。由于 apk 的 java 层代码很容易被反编译,而 C/C++ 库反汇难度较大。2.可以方便地使用现存的开源库。大部分现存的开源库都是用 C/C++ 代码编写的。3.提高程序的执行效率。将要求高性能的应用逻辑使用 C 开发,从而提高应用程序的执行效率。4.便于移植。用 C/C++ 写得库可以方便在其他的嵌入式平台上再次使用。

NDK 简介

1.NDK 是一系列工具的集合2.NDK 提供了一系列的工具,帮助开发者快速开发 C(或C++)的动态库,并能自动将 so 和 java 应用一起打包成 apk。这些工具对开发者的帮助是巨大的。3.NDK 集成了交叉编译器,并提供了相应的 mk 文件隔离 CPU、平台、ABI 等差异,开发人员只需要简单修改 mk 文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出 so。4.NDK 可以自动地将 so 和 Java 应用一起打包,极大地减轻了开发人员的打包工作。5.NDK 提供了一份稳定、功能有限的 API 头文件声明6.Google 明确声明该 API 是稳定的,在后续所有版本中都稳定支持当前发布的 API。从该版本的 NDK 中看出,这些 API 支持的功能非常有限,包含有:C 标准库(libc)、标准数学库(libm)、压缩库(libz)、Log 库(liblog)。

Mac os 环境变量的配置

在AS中新建一个Project,然后再新建一个class为NdkJniUtils,在内部声明native方法(jni使用的定义,后面系列教程会细说)。

package io.github.yanbober.ndkapplication;public class NdkJniUtils {    public native String getCLanguageString();}

在工程主文件Activity中写入如下代码调运JNI的东西显示在UI上。

public class MainActivity extends ActionBarActivity {    private TextView mTextView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mTextView = (TextView) this.findViewById(R.id.test);        NdkJniUtils jni = new NdkJniUtils();        mTextView.setText(jni.getCLanguageString());    }}

然后build project得到其中中间文件,我们关注的是.class文件。编译OK以后生成的class文件在AS工程的如下目录:
NDKApplication\app\build\intermediates\classes\debug
然后接下来的步骤就是根据生成的class文件,利用javah 生成对应的 .h头文件。

点开AS的Terminal标签,默认进入到该项目的app文件夹下。我在windows平台下输入如下命令跳转到class中间文件生成路径:

xxxxx\app> cd build\intermediates\classes\debug
然后执行如下javah命令生成h文件。

xxxxx\debug> javah -jni io.github.yanbober.ndkapplication.NdkJniUtils

执行完之后你可以在文件夹
NDKApplication\app\build\intermediates\classes\debug
下看见生成的 .h头文件为:
io_github_yanbober_ndkapplication_NdkJniUtils.h
其内容为:

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class io_github_yanbober_ndkapplication_NdkJniUtils */#ifndef _Included_io_github_yanbober_ndkapplication_NdkJniUtils#define _Included_io_github_yanbober_ndkapplication_NdkJniUtils#ifdef __cplusplusextern "C" {#endif/* * Class: io_github_yanbober_ndkapplication_NdkJniUtils * Method: getCLanguageString * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

在工程的main目录下新建一个名字为jni的目录,然后将刚才的 .h文件剪切过来。 在jni目录下新建一个c文件,随意取名,我的叫jnitest.c 。然后编辑代码如下(后面会解释啥意思,这里重在工具使用):

#include "io_github_yanbober_ndkapplication_NdkJniUtils.h"/* * Class: io_github_yanbober_ndkapplication_NdkJniUtils * Method: getCLanguageString * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString  (JNIEnv *env, jobject obj){     return (*env)->NewStringUTF(env,"This just a test for Android Studio NDK JNI developer!");  }

接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样,我的添加后如下:

sdk.dir=D\:\\AndroidStdioSDK\\sdkndk.dir=D\:\\AndroidStdioSDK\\android-ndk-r10d-64bit

接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:

defaultConfig {    ......    ndk{        moduleName "YanboberJniLibName"         //生成的so名字        abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无。    }}

现在生成的so库名字也有了,那就去代码的NdkJniUtils java文件添加静态初始化load代码,添加如下:

static {        System.loadLibrary("YanboberJniLibName");   //defaultConfig.ndk.moduleName    }

好了,到此AS下NDK JNI开发的代码编写和设置就OK了,接下来就是编译工程运行就可以了。

但是有些电脑好奇怪此时编译会报错,妹的,没辙,后来网上找到答案说这是NDK在Windows下一个bug,当只编译一个单一文件时出现,解决办法就是 再添加一个空的文件就行了,这个网站有介绍:NDK在Windows的一个bug。不过 你要是刚才能顺利编译就没必要蛋疼这个问题了。

创建NDK项目时注意事项:

1.You should checkout to current Project’s build derectory execute: javah -jni packagename.classname(the class include native method).
2.You will get a file end with “.h” and then you can change the file directory to app/src/main/jni derectory.
3.Add this in your app/build.gradle:

  • java
    ndk {
    moduleName "math"
    abiFilters "armeabi", "armeabi-v7a", "x86"
    }

4.Add “ndk.dir=/Users/bluezhang/AndroidStudioProjects/android-ndk-r11c” in file “local.properties”
5.Add “android.useDeprecatedNdk=true” in file “gradle.properties”.
6.Rebuild project and see app/build/intermediates/ndk (in this file you can see .so file is created!)
7.There is also a Android.mk file is created.
8.Copy the file and .so into jniLibs file and Android.mk file into the jni derectory.

更多相关文章

  1. 网络对讲机C#服务器 Android客户端(三) android客户端代码分析 附
  2. Android入门教程(四)之------Android工程目录结构介绍
  3. Application Fundamentals
  4. android OKHttp的基本使用详解
  5. android中使用MediaRecorder进行视频录制笔记
  6. Android入门教程(四)之-------->Android工程目录结构介绍
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. Android获取屏幕尺寸大小
  2. java.lang.ClassCastException: com.goog
  3. Android 编译系统理解:envsetup.sh学习
  4. android软键盘把页面挤上去的解决方法
  5. Android中xml解析
  6. 【Android 应用开发】GitHub 优秀的 Andr
  7. [android]android命令行截图
  8. Android应用程序的权限列表
  9. Android在应用中固定屏幕方向
  10. android ExpandableListView简单例子