Android Studio 2.2以上NDK开发流程

作者: MKiDlufi | 来源:发表于2017-04-25 16:44 被阅读0次

    android studio从2.2版本开始支持CMake的方式来搭建NDK项目,在这个版本下NDK的开发流程大概分为环境配置、本地方法与头文件生成、C/C++程序编写、本地方法调用这几个步骤。

    环境配置

    1.NDK下载

    在Android Studio界面,选择File→settings,然后找到android SDK→SDK Tools,在这个页面下可以下载NDK。


    NDK下载.png

    要为应用编译和调试原生代码需要以下组件:
    1.Android 原生开发工具包 (NDK):这套工具集允许您为 Android 使用 C 和 C++ 代码,并提供众多平台库,让您可以管理原生 Activity 和访问物理设备组件,例如传感器和触摸输入。
    2.CMake:一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果您只计划使用 ndk-build,则不需要此组件。
    3.LLDB:一种调试程序,Android Studio 使用它来调试原生代码。
    这里把上述三个都下载。

    2.Android Studio创建工程时自动生成C/C++项目目录

    创建项目.png

    在创建项目时,在New Project界面中,我们要把Include C++ support选中,然后Next,直到Customize C++ Support界面。


    自定义选项.png

    我们可以使用下列选项自定义项目:
    1.C++ Standard:使用下拉列表选择您希望使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置,这里我们选择C++ 11。
    2.Exceptions Support:如果您希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake,我们选中。
    3.Runtime Type Information Support:如果您希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle 文件的 cppFlags 中,Gradle 会将其传递到 CMake,我们选中。
    然后我们点Finish,创建好的项目目录如下:


    项目目录.png
    我们可以看到,比以前创建的项目多出两个目录,其中cpp目录存放的是C/C++的头文件如native-lib.cpp,External Build Files用于存放CMake脚本文件。
    gradle.png
    gradle多出了两个externalNativeBuile标签,第一个标签包含我们在创建项目选中的C++标准,异常支持和RTTI支持这三个标签。第二个标签包含cmake的脚本路径。

    我们需要再gradle中的android{defaultConfig{}}中添加ndk支持的平台,比如:

        defaultConfig {
           ...
              externalNativeBuild {
                cmake {
                    cppFlags "-std=c++11 -frtti -fexceptions"
                }
            }
            ndk{
                abiFilters "armeabi"
            }
        }
    

    我们再来看看CMakeLists.txt:


    cmakeLists.png

    原本项目生成的cmakeLists.txt有很多注释,上图为删减之后的结果。

    本地方法与头文件生成

    接下来我们要做的是创建本地方法和生成对应头文件。我们还是以最简单的HelloWorld为例,新建类文件HelloWorld:

    public class HelloWorld {
        static {
            System.loadLibrary("HelloWorld");
        }
        public native String getHelloWorldFromJNI();
    }
    

    然后选择Build→Make Project,这时会在project视图下的app/build/intermediates/debug生成类编译文件。然后我们需要在命令行生成HelloWorld头文件。


    build.png

    在命令行里面定位到debug目录下:

    cd app/build/intermediates/classes/debug
    

    然后用javah编译类文件:

    javah -jni com.example.caixunwei.ndktest.HelloWorld
    

    这里有两点需要注意:
    一是:如果在HelloWorld.java中import了其他类,则需要-classpath <path>参数设定加载类的路径,比如说我现在的项目应该设置为

    set classpath=C:\android\workspace\NDKTest\app\src\main\java
    

    然后再生成.h文件

    javah -jni com.example.caixunwei.ndktest.HelloWorld
    

    否则,会提示无法加载类之类的错误

    二是:如果提示没有找到javah之类的,需要把jdk的bin地址添加到环境路径path中。
    接着在当前debug目录下会生成头文件,生成的头文件com_example_caixunwei_ndktest_HelloWorld.h如下:

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

    如头文件第一段代码所说,我们不要编辑这个文件,而应该新建一个HelloWorld.cpp文件,把com_example_caixunwei_ndktest_HelloWorld.h的代码复制到HelloWorld.cpp文件里面,然后在HelloWorld.cpp中编写代码。
    在cpp目录下新建HelloWorld.cpp文件,这时Android Studio会提示this is not a part of project,我们还需要在CMake脚本文件中将要新建的HelloWorld.cpp相关信息添加进去。
    在CMakeLists.txt中添加:

    add_library(HelloWorld
                SHARED
                src/main/cpp/HelloWorld.cpp )
                
    target_link_libraries(HelloWorld
                          ${log-lib} )
    

    形式跟自动生成的十分相似,需要其他连接库还可以继续在target_link_libraries里面添加,然后点击Sync Now。此时在Android视图下cpp目录会自动生成HelloWorld的库目录。


    cpp.png

    然后将com_example_caixunwei_ndktest_HelloWord.h的代码复制进来,现在我们就可以编写逻辑代码了。

    C/C++代码编写

    JNIEXPORT jstring JNICALL Java_com_example_caixunwei_ndktest_HelloWorld_getHelloWorldFromJNI
            (JNIEnv *env, jobject obj){
        return env->NewStringUTF("HelloWorld!");
    };
    

    这里的逻辑代码很简单,只是在JNI环境下创建了一个字符串“HelloWorld!”然后返回。把生成的头文件的代码复制过来之后记得在命令行输入exit结束占用。

    本地方法调用

    调用该方法的结果如下:


    result.jpg

    完整的MainActivity的代码:

    public class MainActivity extends AppCompatActivity {
        private Button button;
        private TextView text;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = (Button)findViewById(R.id.button);
            text = (TextView)findViewById(R.id.textView);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    text.setText(new HelloWorld().getHelloWorldFromJNI());
                }
            });
        }
    
    }
    

    相关文章

      网友评论

        本文标题:Android Studio 2.2以上NDK开发流程

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