开头

Android NDK官方介绍

The Android NDK is a toolset that lets you implement parts of your app using native-code languages such as C and C++. For certain types of apps, this can help you reuse code libraries written in those languages.

实现在你的Android应用中调用C程序实现一些功能。那为什么要在Java开发中使用C语言呢?

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

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

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

  • 便于移植。用C/C++写得库可以方便在其他的嵌入式平台上再次使用。
    PS:资料来源

虽然关于NDK开发的学习资料不多,Google官方并很多关于NDK开发文档,但竟然NDK开发包那必然有它的意义。所以我们有必要对NDK开发有个初步认识。这节主要搭建NDK开发环境并在应用中调用native函数方法。

开发环境搭建

从ndk-7后,谷歌已经改良了ndk的操作,不需用使用cygwin来交叉编译,所以这里就不再讲cygwin的配置。所搭建的开发环境是Android Studio

  • 1.在官方下载Android NDK开发包 下载地址目前最新的版本为r12b

  • 2.添加java系统环境变量(如果Android Studio的terminal中无法使用javah指令的时候需要做此步操作)

变量
CLASSPATH .;%JAVA_HOME%lib;
JAVA_HOME X:XXJavajdk1.8.0_05
PATH %JAVA_HOME%bin;
  • 3.新建Android工程,添加项目构建NDK本地路径
    图片描述

  • 4.local.propertices中添加ndk.dir=c:\Android-ndk

  • 5.gradle.properties文件中添加android.useDeprecatedNdk=true

趁热打铁,写demo实践一下

  • 1.新建类JniFunction,实现两个native方法

public class JniFunction {

    static public native String getJniString();//获取字符串
    static public native int addNumber(int a,int b);//获取两个整数相加值
}
  • 2.rebuild Project,在工程目录下app/intermediates/classes/debug下查找到JniFunction.class

  • 3.在main目录下创建一个jni文件夹

  • 4.打开Android Studio的terminal,使用cd定位在Android工程的app目录下输入

javah -d jni -classpath ..\..\build\intermediates\classes\debug com.xxxxxxx.xxx.JniFunction
//切记debug和com之间有空格
  • 5.在jni文件夹中就生成了com_learnncode_learnndk_JniFunction.h的头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_learnncode_learnndk_JniFunction */

#ifndef _Included_com_learnncode_learnndk_JniFunction
#define _Included_com_learnncode_learnndk_JniFunction
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_learnncode_learnndk_JniFunction
 * Method:    getJniString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_learnncode_learnndk_JniFunction_getJniString
  (JNIEnv *, jclass);

/*
 * Class:     com_learnncode_learnndk_JniFunction
 * Method:    addNumber
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_learnncode_learnndk_JniFunction_addNumber
  (JNIEnv *, jclass, jint, jint);

#ifdef __cplusplus
}
#endif
#endif
  • 6.在jni文件夹下新建C/C++ Source File,复制h头文件中定义的函数实现函数内容。需要注意的是选择新建.c文件而不是.cpp,另外记得多添加一个无用的c文件,不然编译可能会出错。

#include "com_learnncode_learnndk_JniFunction.h"
/*
 * Class:     com_learnncode_learnndk_JniFunction
 * Method:    getJniString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_learnncode_learnndk_JniFunction_getJniString
  (JNIEnv * env, jclass obj){
    return (*env)->NewStringUTF(env,"Hello Android NDK");
  }

/*
 * Class:     com_learnncode_learnndk_JniFunction
 * Method:    addNumber
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_learnncode_learnndk_JniFunction_addNumber
  (JNIEnv * env, jclass obj, jint a, jint b){
    return a + b;
  }
  • 7.在app build.gradle添加ndk配置

defaultConfig {
        applicationId "com.learnncode.learnndk"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        ndk{
            moduleName "JniFunction"  //设置库(so)文件名称
        }
    }
  • 8.在jni调用的地方添加以下内容

static {
        System.loadLibrary("JniFunction");
    }
//JniFunction就是build.gradle中NDK的文件名

新增内容补充16.10.21

  • 1.so文件的生成
    在app build.gradle中设置ndk生成so文件库文件名

    ndk{
            moduleName "JniFunction"  //设置库(so)文件名称
            abiFilters "armeabi","armeabi-v7a","x86"
        }

clipboard.png

编译项目后在项目目录下ndk文件中就能看到生成的so文件

clipboard.png

ABI:指应用基于哪种指令集来进行编译,ABI总共有四种,分别是armeabi、armeabi-v7a、mips、x86,它们都是表示cpu的类型。
安卓支持三类处理器(CPU):ARM、Intel和MIPS。ARM无疑被使用得最为广泛。Intel因为普及于台式机和服务器而被人们所熟知,然而对移动行业影响力相对较小。MIPS在32位和64位嵌入式领域中历史悠久,获得了不少的成功,可目前Android的采用率在三者中最低。

  • 2.Android studio2.2环境下目录变化
    更新了Android Studio之后发现加载目录发现了变化,原来的Jni文件放置在了单独的文件目录下

Project
clipboard.png

Android
clipboard.png

新增内容补充16.11.09

Android项目调用.so文件方法:在src/main/目录下新建jniLibs文件夹把ndk abiFilters生成的so文件拷贝在此目录下,再在build.gradle defultConfig中配置jniLibs路径,看过其他人写的默认写的是libs好像也是可运行的,这里我还是填上正式新建时的路径

sourceSets.main{
            jniLibs.srcDirs  "src/main/jniLibs"
        }

结尾及成果展示

NDK开发环境的搭建算不上特别难,就是麻烦了些。之前看别人的教程说NDK r10b版本是比较稳定的,我使用的是r12b也能编译成功,目前看来还是可以使用的。这节先为NDK开发开一个头,其中也没详细讲解关于NDK开发的语法等内容。学习NDK的道路还是任重而道远啊。附上google官方的NDK开发Demo实例
本节Demo项目地址
图片描述


一个无
110 声望6 粉丝