Skip to content

模块添加C/C++支持

我们已经知道如何给工程添加C/C++支持。 本文记录如何给工程中的模块(library)添加C/C++支持。

新建模块

模块化是项目开发的常见方式。可以按照功能划分模块,区分管理。达到解耦的效果。

工程中已有app模块。 新建模块fishpole

create

选择Android Library

selete

一路点击下一步直至完成。

查看项目的settings.gradle,看到多了fishpole模块。

include ':fishpole'

app模块依赖fishpoleapp模块的gradle添加了依赖。

dependencies {
    // ...
    implementation project(path: ':fishpole')
}

模块添加NDK

和之前给现有项目添加C/C++支持类似。 大致步骤如下:

  • 添加cpp目录
  • cpp目录中添加cmake
  • 在gradle中配置cmake
  • 新建native方法
  • 编写cpp实现方法

cmake

CMakeLists.txt文件。模块名字为fisher-pole

cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
             fisher-pole

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             tom.cpp jerry.cpp )

cpp文件在下文。

gradle

模块gradle文件添加cmake配置

android {
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

Java, Kotlin, C++

新建Java类FisherTom。声明几个native方法。不要忘记System.loadLibrary

public class FisherTom {
    static {
        System.loadLibrary("fisher-pole");
    }

    public native int addFish(int a, int b);

    public native float calFish(float f1, float f2);

    public native String name();
}

FisherTom对应的tom.cpp

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_rustfisher_fishpole_worker_FisherTom_name(JNIEnv *env, jobject thiz) {
    std::string myName = "Tom";
    return env->NewStringUTF(myName.c_str());
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_rustfisher_fishpole_worker_FisherTom_addFish(JNIEnv *env, jobject thiz, jint a, jint b) {
    return a + b;
}

extern "C"
JNIEXPORT jfloat JNICALL
Java_com_rustfisher_fishpole_worker_FisherTom_calFish(JNIEnv *env, jobject thiz, jfloat f1,
                                                      jfloat f2) {
    return f1 * f2;
}

再新建一个Kotlin类Jerry。声明几个external方法。

class Jerry {
    companion object {
        init {
            System.loadLibrary("fisher-pole")
        }
    }

    external fun addFish(a: Int, b: Int): Int
    external fun calFish(f1: Float, f2: Float): Float
    external fun name(): String?
}

Java中的native方法,在Kotlin中使用external。

Jerry对应的jerry.cpp

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jint JNICALL
Java_com_rustfisher_fishpole_worker_Jerry_addFish(JNIEnv *env, jobject thiz, jint a, jint b) {
    return a + b;
}

extern "C"
JNIEXPORT jfloat JNICALL
Java_com_rustfisher_fishpole_worker_Jerry_calFish(JNIEnv *env, jobject thiz, jfloat f1, jfloat f2) {
    return f1 * f2 * 1.1f; // Different with Tom ;)
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_rustfisher_fishpole_worker_Jerry_name(JNIEnv *env, jobject thiz) {
    std::string jerry = "Jerry";
    return env->NewStringUTF(jerry.c_str());
}

使用

在我们的app模块中使用这2个类。

FisherTom tom = new FisherTom();
Jerry jerry = new Jerry();
String tomMsg = tom.name() + ": int: " + tom.addFish(1, 2) + ", float: " + tom.calFish(2, 3.4f);
String jerryMsg = jerry.name() + ": int: " + jerry.addFish(1, 2) + ", float: " + jerry.calFish(2, 3.4f);

项目地址Tutorial2020