Java 获取加载 SO 的依赖

在 Android 开发中,使用 JNI (Java Native Interface)调用 C/C++ 代码时,我们会用到共享库(即 .so 文件)。这篇文章将帮助刚入行的小白开发者学习如何在 Java 中获取和加载这些 SO 文件的依赖。

整体流程

我们可以把整个流程分为以下几个步骤:

步骤描述
1创建一个 C/C++ 文件并编写需要的函数
2编译 C/C++ 代码生成 SO 文件
3在 Java 代码中加载 SO 文件
4调用 SO 文件中的本地方法
1. 创建 C/C++ 文件

首先,我们需要在项目中创建一个 C/C++ 文件,比如 native-lib.cpp,并编写需要的函数。下面是一个简单的例子,定义了一个返回字符串的函数。

// native-lib.cpp
#include <jni.h>
#include <string>

// 定义一个返回字符串的本地方法
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapp_MainActivity_stringFromJNI(JNIEnv *env, jobject /* this */) {
    return env->NewStringUTF("Hello from C++");
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

注释:此函数使用 JNI 提供的接口返回一个字符串。

2. 编译 C/C++ 代码生成 SO 文件

接下来,我们需要用 NDK(Native Development Kit)来编译这个 C/C++ 文件。打开 build.gradle 中的 Android 配置,确保启用了 C/C++ 支持。例如:

android {
    ...
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

然后,创建 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.4.1)

# 指定库的名称和源文件
add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides the relative path to your source file(s).
             native-lib.cpp )

# 找到需要的本地库
find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the log library.
              log )

# 连接库
target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       ${log-lib} )
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

注释:这段 CMake 脚本编译我们定义的原生代码生成 SO 文件。

3. 在 Java 代码中加载 SO 文件

在 Java 代码中,我们需要加载这个生成的 SO 文件。通常在 MainActivity 中进行如下操作:

package com.example.myapp;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    
    // 加载 SO 文件的本地方法
    static {
        System.loadLibrary("native-lib");
    }

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

    // 声明本地方法
    public native String stringFromJNI();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

注释:System.loadLibrary("native-lib") 加载之前编译生成的 SO 文件,stringFromJNI 是 JNI 提供的本地方法。

4. 调用 SO 文件中的本地方法

最后,在 onCreate 方法中调用这个本地方法并显示结果。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 调用本地方法并获取返回值
    String result = stringFromJNI();
    System.out.println(result); // 控制台输出 'Hello from C++'
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

注释:这里我们调用了 stringFromJNI() 方法并输出返回结果。

类图

MainActivity +void onCreate(Bundle savedInstanceState) +native String stringFromJNI()

结论

通过本篇文章的介绍,我们详细讲解了如何在 Android 项目中创建、编译 C/C++ 代码并在 Java 中加载和调用生成的 SO 文件。整件事情的流程虽然看似复杂,但只要按步骤来,就能够成功地实现 JNI 调用。在实际开发中,记得遵循良好的编码规范,保证代码的可读性和可维护性!希望这对你的开发旅程有所帮助!