Environment

  • Operating System: Win 10
  • Android Studio: Version 4.2
  • SDK: API 26: Android 8.0(Oreo)
  • C++: Version 14

Introduction

JNIJava Native Interface的缩写,通过Java本地接口书写程序,可以确保代码在不同的平台上方便移植。JNI标准成为Java平台的一部分,它允许Java代码和其他语言写的代码进行交互

Step1

创建以Native C++为模板的安卓项目

  1. 打开Android Studio

1

  1. 选择Native C++模板并点击Next

2

  1. 填写相应字段并点击Next

3

  1. 选择C++版本并点击Finish创建项目
  • 这里我选择的是标准C++ 14

4

Step2

项目创建成功后会发现默认的启动程序并不为空,布局中包括一个示例文本,且/src/main路径下有一个cpp文件夹,其中包括Android Studio提供的CMakeLists.txt文本文件以及native-lib.cppC++文件,如下图所示

5

Android Studio提供的文件为样例,可以"照猫画虎"地编写新的JNI或C语言程序,步骤大体如下

  1. 将写好的C++程序放在cpp目录下
  2. CMakeLists.txt文件中注册声明并进行同步编译
  3. Java文件中引入相应的库并声明native函数

执行上面3步后且操作无误,就可以在Java文件中使用C++程序的代码或函数了

Step3

下面来具体演示一下操作流程

  1. 将写好的C++程序放在cpp目录下
  • 新建jni-test.cpp文件,代码如下所示
1
2
3
4
5
6
7
8
9
10
11
12
#include <jni.h>
#include <string>

using namespace std;

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_androidstudiojni_MainActivity_jniTest(
JNIEnv* env,
jobject) {
string jniTestString = "JNI Test Success!";
return env->NewStringUTF(jniTestString.c_str());
}

这里Java_com_example_androidstudiojni_MainActivity_jniTest的含义如下

  • Java为起始符
  • com_example_androidstudiojni为包名
  • MainActivity为使用此函数的Java文件名
  • jniTest为此函数在Java文件中的函数名
  1. CMakeLists.txt文件中注册声明并进行同步编译
  • 修改CMakeLists.txt文件
1
2
3
4
5
6
7
8
add_library( # Sets the name of the library.
jniTest-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
jni-test.cpp )
  • 同步编译 FileSync with Gradle Files
  1. Java文件中引入相应的库并声明native函数
  • 这里我们直接在MainActivity.java中进行声明与测试
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// 这是修改前的代码
package com.example.androidstudiojni;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import com.example.androidstudiojni.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());
}

/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
// 这是修改后的代码
package com.example.androidstudiojni;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import com.example.androidstudiojni.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
System.loadLibrary("jniTest-lib");
// 在这里引入刚才自己写的库 即add_library中第二行的库名
}

private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());

// JNI测试
tv.setText(jniTest());

}

/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native String jniTest();
// 在这里声明函数
}
  1. 至此编写工作就完成了,下面运行查看结果
  • MainActivity.java中原本将tv中的文本置为stringFromJNI()函数的返回值
  • 修改后应为我们自己编写的函数的结果,即JNI Test Success!

6

Success!

Conclusion

这里成功实现了在安卓项目中使用JNI,但是JNI的内容远不止于此,还需要大量的学习,包括CMakeLists.txt文件的书写,关联Gradle,导入大量程序时的操作,创建Android库等等

Android Studio官网提供了很好的开发文档,包括但不限于JNI的说明,非常有助于安卓开发的学习