美文网首页Android音视频系列
OpenGL-ES 3.0学习指南(一)——Hello NDK

OpenGL-ES 3.0学习指南(一)——Hello NDK

作者: 798fe2ac8685 | 来源:发表于2016-11-21 12:06 被阅读529次

    标签(空格分隔): OpenGL-ES

    版本:1
    作者:陈小默
    声明:禁止商业,禁止转载
    

    发布于作业部落简书


    前言

    本篇内容介绍NDK环境的基本搭建和最简单的NDK示例。示例工程发布到GitHub-NDK。在开始本系列之前,请确保已经了解JNI的相关知识,如果没有,可以到这里学习JNI完全指南系列。水平有限,如有错误,恳请批评指正。


    [toc]


    一、在Android Studio 2.2及以上版本搭建NDK开发环境

    Android Studio在其2.2及以上版本继承了流行的C++编译器CMake,于是我们很方便的就能够搭建出NDK开发环境。

    1.1 创建NDK工程

    在Android Studio 2.2 及以上版本创建NDK的工程只需要勾选Include C++ Support即可。

    1.2 CMakeList.txt文件说明

    在工程创建完成之后,我们将目录视图切换到Project,我们发现app目录下多了一个CMakeList.txt文件,这个文件的作用是指引CMake编译器如何去编译我们的源文件,打开文件我们会看见如下内容(注释已精简)。

    # 这里指定了CMake的最低版本为3.4.1
    cmake_minimum_required(VERSION 3.4.1)
    # 这里用来添加一个库
    add_library( # 这里设置so库的名称为native-lib
                 native-lib
                 # 这里设置该库为共享
                 SHARED
                 # 这里是源文件的路径,可以有多个,最终这个源文件将被编译并打包进native-lib库。
                 src/main/cpp/native-lib.cpp )
    # 这里用来查找一个库,并设置到路径变量中去
    find_library( # 设置路径变量
                  log-lib
                  # 你希望CMake编译器加载的NDK函数库
                  log )
    # 将一个库关联到目标函数库中
    target_link_libraries( # 目标函数库
                           native-lib
                           # 想要在目标函数库中使用的函数库,其中${路径变量}
                           ${log-lib} )
    

    更详细的CMakeList.txt可以参照这里CMakeList.txt说明。


    二、使用Android Studio搭建Kotlin开发环境

    目前kotlin语言的版本是1.0.4。搭建过程详见在Android Studio中配置Kotlin开发环境


    三、Hello JNI

    本章内容为调用JNI方法,并返回一段字符串。

    3.1 创建Java文件

    在{$package}/lib包下创建一个Java文件HelloJniLib.java,其中的内容为

    public class HelloJniLib {
        public static native String helloJNI();
    }
    

    3.2 创建源文件

    当我们声明了一个native方法后,需要在一个源文件中实现业务逻辑,接下来,我们在cpp文件夹下创建一个hello-jni.cpp,并在其中实现声明的本地方法:

    #include <jni.h>
    
    extern "C"
    JNIEXPORT jstring JNICALL
    Java_com_github_cccxm_ndk_lib_HelloJniLib_helloJNI(JNIEnv *env,
                                                       jobject thiz) {
    #if defined(__arm__)
        #if defined(__ARM_ARCH_7A__)
            #if defined(__ARM_NEON__)
                #if defined(__ARM_PCS_VFP)
                    #define ABI "armeabi-v7a/NEON (hard-float)"
                #else
                    #define ABI "armeabi-v7a/NEON"
                #endif
            #else
                #if defined(__ARM_PCS_VFP)
                    #define ABI "armeabi-v7a (hard-float)"
                #else
                    #define ABI "armeabi-v7a"
                #endif
            #endif
        #else
            #define ABI "armeabi"
        #endif
    #elif defined(__i386__)
        #define ABI "x86"
    #elif defined(__x86_64__)
        #define ABI "x86_64"
    #elif defined(__mips64)  /* mips64el-* toolchain defines __mips__ too */
        #define ABI "mips64"
    #elif defined(__mips__)
        #define ABI "mips"
    #elif defined(__aarch64__)
        #define ABI "arm64-v8a"
    #else
        #define ABI "unknown"
    #endif
        return env->NewStringUTF("Hello from JNI !  Compiled with ABI " ABI ".");
    }
    

    3.3 修改CMakeList.txt文件

    在这里我们需要指定生成的so库的名字,还有需要被编联到这个库的源文件的位置,注意,这里的源文件路径是相对于CMakeList.txt的路径。这里我们指定库名为ndk-lib。

    elseif (${ANDROID_PLATFORM_LEVEL} LESS 18)
      add_definitions("-DDYNAMIC_ES3")
      set(OPENGL_LIB GLESv2)
    else ()
      set(OPENGL_LIB GLESv3)
    endif (${ANDROID_PLATFORM_LEVEL} LESS 11)
    
    add_library(ndk-lib SHARED
                src/main/cpp/hello-jni.cpp)
    
    target_link_libraries(ndk-lib
                          android
                          log
                          m)
    

    3.4 在Activity中显示结果

    接下来我们需要一个用来显示结果的ActivityHelloJniActivity,其中包含一个TextView

        <TextView
            android:text="TextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/tv_hello_jni" />
    
    class HelloJniActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_hello_jni)
    
            tv_hello_jni.text = HelloJniLib.helloJNI()
        }
    }
    

    3.5 加载本地库

    在使用本地方法之前,我们需要通知JVM加载本地库,由于本地库仅需要加载一次,而且必须在使用native方法之前,所以这里可以将加载过程放置到Application类中,这样程序启动时就会自动链接本地库。

    class NDKApplication : Application() {
        init {
            System.loadLibrary("ndk-lib")
        }
    }
    

    3.6 小结

    到此为止,我们的第一个程序就完成了,如果运行以上程序,我们就能在Activity上看到JNI方法返回的数据。现在我们总结一下一个NDK程序的开发过程:

    • 在一个java文件中声明一个native方法。
    • 在cpp文件夹下创建一个C/C++源文件,并按照JNI规范声明native函数。注意:如果是在C++文件中声明的native函数,需要在函数前声明extern "C"
    • 修改CMakeList.txt文件,在add_library中将源文件添加进相应的库中,有必要的话,再在target_link_libraries中将库与其他相关源码进行关联。
    • 在使用native方法前的任意位置使用System.loadLibrary是程序与本地库关联。

    下一篇:OpenGL-ES 3.0学习指南(二)——Hello Java

    相关文章

      网友评论

        本文标题:OpenGL-ES 3.0学习指南(一)——Hello NDK

        本文链接:https://www.haomeiwen.com/subject/allupttx.html