美文网首页
Android Studio NDK 初尝

Android Studio NDK 初尝

作者: feifei_fly | 来源:发表于2018-06-19 11:59 被阅读0次
NDK 适合的场景:

1 . 重要核心代码保护。由于java层代码很容易反编译,而C/C++代码反汇编难度很大,所以对于重要的代码,可以使用C/C++来编写,Android去调用即可。

2 . Android中需要用到第三方的C/C++库。由于很多优秀的第三方库(比如FFmpeg)都是使用C/C++来编写的,我们想要使用它们,就必须通过NDK的方式来操作。

3 . 便于代码的移植。比如我们对于一些核心的公共组件(比如微信开源的的Mars),可能需要写一套代码在多个平台上运行(比如在Android和iOS上共用一个库),那么就需要选用NDK的方式。

4 . 对于音视频处理、图像处理这种计算量比较大追求性能的场景,也需要使用到NDK。

什么是JNI

JNI的全称是Java Native Interface,它允许Java语言可以按照一定的规则去调用其他语言,与其进行交互。

编写Java代码(.java) —————> 编译生成字节码文件(.class) —————> 产生C头文件(.h) —————> 编写jni实现代码(.c) —————> * 编译成链接库(.so)**
什么是CMake

CMake是一款开源的跨平台自动化构建系统,它通过CMakeLists.txt来声明构建的行为,控制整个编译流程.

搭建NDK 环境

Tools->SDK Manager->System Settings->Android SDK ->SDK Tools->勾选CMake、LLDB、NDK 进行下载安装

image

NDK 环境变量配置:

export PATH=${PATH}:~/Library/Android/sdk/platform-tools
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home
export JAVA_HOME
CLASS_PATH=$JAVA_HOME/lib
ANDROID_NDK_ROOT=/Users/feifei/Library/Android/sdk/ndk-bundle
PATH=${PATH}:${JAVA_HOME}/bin
PATH=${PATH}:${ANDROID_NDK_ROOT}
新建NDK 工程,编译so库

新建工程时勾选 include C++ support

image
image

新建完有如下几个变化:

  • main目录下增加了一个cpp文件夹,用来存放编写的cpp文件
  • app目录下 增加了一个CMakeList.txt文件,用于指导CMake构建项目


    image
  • buid.gradle中新增了NDK相关的配置
image
  • 声明native函数

在任何一个java文件 用native关键字声明nativie函数,但最好统一发放到一个工具类中,这样方便管理。

然后在声明的native方法上面,点击option+Enter键,会自动在cpp目录下hello-lib.cpp中生成函数的实现体

JNIUtils.java

package com.example.myndk;
  public class JNIUtils {

    static {
        System.loadLibrary("hello-lib");
    }

    public native String stringFromJNI();

    public native void writeFile(String filePath);

    public native void operationArray(int[]args);
    public native void operationArray2(int[]args);

}

生成的navtive方法实现类:

//
// Created by 飞飞 on 2018/6/12.
//

#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <android/log.h>

#define  LOG    "JNILOG" // 这个是自定义的LOG的TAG
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__) // 定义LOGD类型
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__) // 定义LOGI类型
#define  LOGW(...)  __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...)  __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__) // 定义LOGF类型


JNIEXPORT jstring JNICALL
Java_com_example_myndk_JNIUtils_stringFromJNI(JNIEnv *env, jobject instance) {

    // TODO
    LOGD("stringFromJNI was called");

    return (*env)->NewStringUTF(env, "Hello World");
}

这里存在一个问题,初次生成,AndroidStudio会创建一个jni文件夹,然后在里面创建hello-lib.cpp文件,并且自动生成对应的C代码,但是,由于我们在CMakeLists.txt中指定的路径为src/main/cpp/hello-lib.cpp,所以我们这里直接将我们的src/main/jni/hello-lib.cpp中的代码拷贝到rc/main/cpp/hello-lib.cpp中,并将jni目录删除即可。

  • buld Project,会在如下目录生成so
image
在另一个工程中使用so库
  • 在main目录中,建立一个与java平级的jniLibs目录。将
    编译生成的armeabi-v7a、x86等相关文件夹拷贝到jniLibs目录中。
image
  • java目录下,建立JNIUtils所声明的包名目录,将JNIUtils.java拷贝到com.example.myndk 目录下。(注意:在引用so的工程中,JNIUtils.java所处的目录结构一定要与原始包名一致,否则会报错)
  • 在工程中使用JNIUtils
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView tv_title = (TextView) findViewById(R.id.tv_title);
        tv_title.setText(new JNIUtils().stringFromJNI());
    }
}
关于CMakeList.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

add_library(hello-lib SHARED src/main/cpp/hello-lib.c)

find_library(log-lib log)

target_link_libraries(hello-lib ${log-lib})
  • cmake_minimum_required(VERSION 3.4.1) 用来设置在编译本地库时我们需要的最小的cmake版本,AndroidStudio自动生成,我们几乎不需要自己管

  • add_library用来设置编译生成的本地库的名字为hello-lib,SHARED表示编译生成的是动态链接库(这个概念前面已经提到过了),src/main/cpp/hello-lib.cpp表示参与编译的文件的路径,这里面可以写多个文件的路径。

  • find_library 是用来添加一些我们在编译我们的本地库的时候需要依赖的一些库,由于cmake已经知道系统库的路径,所以我们这里只是指定使用log库,然后给log库起别名为log-lib便于我们后面引用,此处的log库是我们后面调试时需要用来打log日志的库,是NDK为我们提供的。

  • target_link_libraries 是为了关联我们自己的库和一些第三方库或者系统库,这里把我们把自己的库hello-lib库和log库关联起来。

参考文章:

https://blog.csdn.net/bingjianit/article/details/75567410

https://www.jianshu.com/p/a05aa98faaf3

lame库(pcm转mp3)https://www.jianshu.com/p/ae19af93886b

相关文章

网友评论

      本文标题:Android Studio NDK 初尝

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