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