安卓项目模块集成JNI的两种方式回顾

发布于:2024-06-16 ⋅ 阅读:(18) ⋅ 点赞:(0)

在 Android 模块中编写 JNI 模块来调用第三方的 .so 文件,可以使用 NDK Build (老项目)或 CMake 两种方式。以下是详细的操作步骤:

使用 NDK Build

1. 创建 JNI 目录结构

在你的 Android 模块中创建一个 jni 目录,并在其中创建 Android.mkApplication.mk 文件。

your_android_module/
├── app/
│   ├── src/
│   └── jni/
│       ├── Android.mk
│       ├── Application.mk
│       └── your_jni_code.c
2. 编写 Android.mk 文件

jni/Android.mk 文件中定义你的模块和第三方库:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := your_jni_code
LOCAL_SRC_FILES := your_jni_code.c
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := third_party_lib  # 这里是你的第三方.so库名称
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := third_party_lib
LOCAL_SRC_FILES := libs/$(TARGET_ARCH_ABI)/libthird_party.so  # 第三方库的位置
include $(PREBUILT_SHARED_LIBRARY)
3. 编写 Application.mk 文件

jni/Application.mk 文件中指定编译的目标架构和应用设置:

APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_PLATFORM := android-21
APP_STL := c++_shared
4. 编写你的 JNI 代码

jni/your_jni_code.c 文件中编写你的 JNI 代码:

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

#define LOG_TAG "YourJNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

JNIEXPORT jstring JNICALL
Java_com_example_yourmodule_MainActivity_stringFromJNI(JNIEnv *env, jobject instance) {
    LOGD("This is a debug message from JNI");
    return (*env)->NewStringUTF(env, "Hello from JNI");
}
5. 在项目中使用 JNI

在你的 build.gradle 文件中配置 NDK 支持:

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            ndkBuild {
                path "src/main/jni/Android.mk"
            }
        }
    }
    externalNativeBuild {
        ndkBuild {
            path file("src/main/jni/Android.mk")
        }
    }
}

在 Java 代码中加载 JNI 库并调用本地方法:

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("your_jni_code");
    }

    public native String stringFromJNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
}

使用 CMake

1. 创建 CMake 目录结构

在你的 Android 模块中创建一个 cpp 目录,并在其中创建 CMakeLists.txt 文件和你的 JNI 代码文件:

your_android_module/
├── app/
│   ├── src/
│   └── cpp/
│       ├── CMakeLists.txt
│       └── your_jni_code.cpp
2. 编写 CMakeLists.txt 文件

cpp/CMakeLists.txt 文件中定义你的模块和第三方库:

cmake_minimum_required(VERSION 3.4.1)

# 指定你的本地库名
add_library( your_jni_code SHARED your_jni_code.cpp )

# 引入log库
find_library( log-lib log )

# 引入第三方库
add_library( third_party_lib SHARED IMPORTED )
set_target_properties( third_party_lib PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libthird_party.so )

# 链接库
target_link_libraries( your_jni_code ${log-lib} third_party_lib )
3. 编写你的 JNI 代码

cpp/your_jni_code.cpp 文件中编写你的 JNI 代码:

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

#define LOG_TAG "YourJNI"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_yourmodule_MainActivity_stringFromJNI(JNIEnv *env, jobject instance) {
    LOGD("This is a debug message from JNI");
    std::string hello = "Hello from JNI";
    return env->NewStringUTF(hello.c_str());
}
4. 在项目中使用 JNI

在项目下的 build.gradle 文件中配置 CMake 支持:

android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                path "src/main/cpp/CMakeLists.txt"
            }
        }
    }
    externalNativeBuild {
        cmake {
            path file("src/main/cpp/CMakeLists.txt")
        }
    }
}

在 Java 代码中加载 JNI 库并调用本地方法:

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("your_jni_code");
    }

    public native String stringFromJNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }
}