Android Studio JNI 开发详细教程

1. 环境准备

安装 NDK 和 CMake

  • 打开 Android Studio → Tools → SDK Manager → SDK Tools
  • 勾选 NDK (Native Development Kit) 和 CMake
  • 点击 Apply 安装

image-20250325095619376

2. 创建新项目

新建项目

  • 选择”Empty Activity”模板
  • 确保语言选择 Java(或 Kotlin,本例使用 Java)

image-20250325095856866

image-20250325100038611

3. 配置 NDK 路径

local.properties中添加:

1
ndk.dir=/path/to/ndk  # 通常自动配置,无需手动修改

image-20250325100531006

4. 创建 Java Native 接口

创建 Java 类

app/src/main/java/com/example/myjnidemo/NativeLib.java

1
2
3
4
5
6
7
8
9
10
package com.example.myjnidemo;

public class NativeLib {
static {
System.loadLibrary("native-lib");
}

public native String getNativeString();
public native int addNumbers(int a, int b);
}

5. 生成 C/C++头文件

定位到 Java 目录

1
cd app/src/main/java

生成头文件

1
javac -h ../cpp com/example/myjnidemo/NativeLib.java

命令说明:

  • 编译NativeLib.java生成.class文件(存放于app/src/main/java/com/example/myjnidemo/
  • 生成 JNI 头文件com_example_myjnidemo_NativeLib.h(存放于app/src/main/cpp/

6. 编写 C++实现

app/src/main/cpp/native-lib.cpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <jni.h>
#include <string> // 明确包含,为后续扩展做准备
#include "com_example_myjnidemo_NativeLib.h" // 关键头文件

// 使用头文件中的声明,避免签名错误
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myjnidemo_NativeLib_getNativeString(JNIEnv* env, jobject) {
// 虽然当前未使用 std::string,但包含<string>可为后续优化留余地
std::string message = "Hello from C++!";
return env->NewStringUTF(message.c_str());
}

extern "C" JNIEXPORT jint JNICALL
Java_com_example_myjnidemo_NativeLib_addNumbers(JNIEnv*, jobject, jint a, jint b) {
return a + b; // 基础类型操作无需字符串支持
}

7. 配置 CMake

创建/修改app/CMakeLists.txt

1
2
3
4
5
6
7
8
cmake_minimum_required(VERSION 3.10.2)
project("native-lib")

add_library(native-lib SHARED src/main/cpp/native-lib.cpp)

find_library(log-lib log)

target_link_libraries(native-lib ${log-lib})

8. 配置 Gradle

app/build.gradle的 android 块内添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
version "3.10.2"
}
}
}

9. 使用 Native 方法

MainActivity中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

NativeLib nativeLib = new NativeLib();
String text = nativeLib.getNativeString();
int sum = nativeLib.addNumbers(5, 3);

TextView tv = findViewById(R.id.sample_text);
tv.setText(text + "\n5 + 3 = " + sum);
}
}

10. 修改页面布局

文件位置app/src/main/res/layout/activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<!-- 用于显示 JNI 调用结果的 TextView -->
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textColor="@android:color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Hello from JNI!"/>

</androidx.constraintlayout.widget.ConstraintLayout>

最终效果示意图

1
2
3
4
+-----------------------------+
| Hello from C++! |
| 5 + 3 = 8 |
+-----------------------------+

11. 构建运行

  1. 点击 Build → Make Project
  2. 运行到设备/模拟器

12. 完整的 JNI 项目文件树

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
26
MyJniDemo/                  # 项目根目录
├── gradle/ # Gradle 包装器
├── app/ # 主模块
│ ├── libs/ # 第三方库(本项目未使用)
│ ├── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ └── myjnidemo/
│ │ │ ├── MainActivity.java # 主 Activity
│ │ │ └── NativeLib.java # JNI 接口类
│ │ ├── cpp/
│ │ │ ├── native-lib.cpp # C++实现
│ │ │ └── com_example_myjnidemo_NativeLib.h # 生成的头文件
│ │ ├── res/ # 资源文件
│ │ │ ├── layout/
│ │ │ │ └── activity_main.xml # 布局文件
│ │ │ └── values/
│ │ │ └── strings.xml # 字符串资源
│ │ └── AndroidManifest.xml # 清单文件
│ ├── CMakeLists.txt # CMake 配置文件
│ └── build.gradle # 模块级 Gradle 配置
├── gradle/ # Gradle 相关文件
├── settings.gradle # 项目级设置
└── local.properties # NDK/SDK 路径配置

构建后生成的。so 文件位置

1
2
3
4
5
6
7
8
9
10
11
12
app/
└── build/
└── intermediates/
└── cmake/
└── debug/
└── obj/
├── arm64-v8a/
│ └── libnative-lib.so
├── armeabi-v7a/
│ └── libnative-lib.so
└── x86_64/
└── libnative-lib.so

image-20250325150834365

image-20250325151048399