我的Android NDK之旅(二),使用ndk-build构建Jni

转载请注明出处:(http://blog.csdn.net/qq_35071078/article/details/70502481)

使用ndk-build构建Jni


ndk-build是什么

ndk-build 文件是 Android NDK r4 中引入的一个 shell 脚本。其用途是调用正确的 NDK 构建脚本。可以用这个命令来生成.so文件。

ndk-build如何使用

当你想使用该命令将.cpp/.c文件生成.so文件,必须有具备以下几个条件

  • 需有有Android.mk文件,并且与对应的.cpp/.c文件在同一个目录下

  • 需要有Application.mk文件,并且与对应的.cpp/.c文件在用一个目录下

什么是Android.mk

Android.mk 文件位于项目 jni/ 目录的子目录中,用于向构建系统描述源文件和共享库。 它实际上是构建系统解析一次或多次的微小 GNU makefile 片段。 Android.mk 文件用于定义 Application.mk、构建系统和环境变量所未定义的项目范围设置。 它还可替换特定模块的项目范围设置。
Android.mk 的语法用于将源文件分组为模块。 模块是静态库、共享库或独立可执行文件。 可在每个 Android.mk 文件中定义一个或多个模块,也可在多个模块中使用同一个源文件。 构建系统只会将共享库放入应用软件包。 此外,静态库可生成共享库。
除了封装库之外,构建系统还可为您处理各种其他详细信息。例如,您无需在 Android.mk 文件中列出标头文件或生成的文件之间的显式依赖关系。 NDK 构建系统会自动为您计算这些关系。 因此,您应该能够享受到未来 NDK 版本中新工具链/平台支持的优点,而无需接触 Android.mk 文件。
此文件的语法与随整个 Android 开放源代码项目分发的 Android.mk 文件中使用的语法非常接近。 虽然使用它们的构建系统实现不同,但类似之处在于,其设计决定旨在使应用开发者更容易重复使用外部库的源代码。
简单来说,这个文件可以定义生成的.so文件的名字,可以像.cpp/.c文件引入一些动态库。
具体可以去看谷歌官方的参考

什么是Application.mk

Application.mk 文件实际上是定义要编译的多个变量的微小 GNU Makefile 片段。 它通常位于 PROJECT/jni/ PROJECT 指向应用的项目目录。 另一种方式是将其放在顶级 $NDK/apps/ 目录的子目录下。
例如,Application.mk可以用来指定需要生成哪些cpu类型的.so文件,或者定义引用.so的最低android api。
详细请看谷歌官方参考

示例

首先创建一个项目:
我的Android NDK之旅(二),使用ndk-build构建Jni_第1张图片

创建一个类Jni,用来声明native方法:

我的Android NDK之旅(二),使用ndk-build构建Jni_第2张图片

用javah命令生成.h文件:首先 cd app/build/intermediates/classes/debug 进入到debug目录,然后 javah com.chenxin.testndk.MyJni 生成.h文件,在app/src/main目录下创建一个jni文件夹,将刚才生成的.h文件剪切到jni文件夹里面,在jni文件夹里面创建一个.c/.cpp的文件
我的Android NDK之旅(二),使用ndk-build构建Jni_第3张图片
如果创建的是.c:

#include 
#include 

#define LOG_TAG "infoo"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT jstring JNICALL Java_com_chenxin_testndk_MyJni_get
  (JNIEnv *env, jclass jz){

        LOGI("hello,这里是native层");
        return (*env)->NewStringUTF(env,"hello jni , you are so easy!");

  }

如果是.cpp:

#include 
#include 

#define LOG_TAG "infoo"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

JNIEXPORT jstring JNICALL Java_com_chenxin_testndk_MyJni_get
  (JNIEnv *env, jclass jz){

        LOGI("hello,这里是native层");
        return env->NewStringUTF("hello jni , you are so easy!");

  }

在jni目录下创建Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := MyJni 
LOCAL_SRC_FILES := test.c
LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -lm -llog
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE:是将要生成的.so的名字
LOCAL_SRC_FILES:是需要将哪个.c/.cpp文件生成.so文件,例如我这里是test.c
LOCAL_LDLIBS:这里是给.c/.cpp文件添加了一个log库,可以打印log

在jni目录下创建Application.mk文件

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := all
APP_PLATFORM := android-8
APP_ABI:是将要生成哪些cpu类型的so,all代表全部
APP_PLATFORM:生成的so的最低android版本

.c/.cpp,android.mk,application.mk创建完成之后:
我的Android NDK之旅(二),使用ndk-build构建Jni_第4张图片

打开android studio的终端,进入到jni文件夹,cd app/src/main/jni ,然后 输入 ndk-build 回车ok,so就生成了:
我的Android NDK之旅(二),使用ndk-build构建Jni_第5张图片

此时就可以看到libs文件夹里面的so文件了:

我的Android NDK之旅(二),使用ndk-build构建Jni_第6张图片

接下来就是使用so了,首先先与.so关联起来,有两种方法
(1)第一种方法,app/src/main目录下面创建一个jniLibs文件夹,将刚才生成的libs下的所有文件夹拷贝或者剪切到这里面,然后在 build.gradle中加入:

android {
   ......
    sourceSets {
        main() {
            jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
        }
    }
}

(2)第二种方法,直接在gradle中加入

android {
   ......
    sourceSets {
        main() {
            jniLibs.srcDirs = ['src/main/libs']
            jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
        }
    }
}

然后就是在代码中调用了:
MyJni.java:

public class MyJni {

    static {
        System.loadLibrary("MyJni");
    }

    public  native  static String get();

}

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e("info","调用jni层的结果 : "+MyJni.get());
    }
}

编译运行:

我的Android NDK之旅(二),使用ndk-build构建Jni_第7张图片

ok,成功!

你可能感兴趣的:(Android,NDK)