NDK:Native Development Kit,是Android的一种开发工具包,能够快速开发C,C++的动态库,并自动将so和应用打包成APK。而NDK的使用场景就是通过NDK在Android中使用JNI。
JNI:Java Native Interface的缩写,即Java的本地接口,JNI可以使得Java与C,C++语言进行交互。
NDK优点:
1.APK的Java层代码很容易被反编译,而C/C++库反编译难度较大
2.将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。
3.用C/C++写的库可以方便在其他的嵌入式平台上再次使用,如在Android、iOS使用
1.在新建native项目后,项目目录结构会包含一个cpp目录,包含CMakeLists.txt(AS版本差异,不一定在cpp目录下)与native-lib.cpp两个文件。native-lib中包含一个本地方法的实现。
2.demo的MainActivity中,加载了名为native-lib的so库,并声明了一个本地方法。该方法与native-lib.cpp文件中的方法对应。
3.app的build.gradle中,会声明cmake的版本与路径,路径依据CMakeLists.txt文件路径决定
4.demo中CMakeLists.txt主要配置说明:
add_library():将native-lib.cpp转换成SHARED(共享)库,命名为native-lib;
find_library():寻找想要添加的NDK库名,一般为系统提供的库;
target_link_libraries():将目标库与库文件进行连接,可以链接多个库;
set_target_properties():加载第三方so库;
例子一:C对象转换为Java对象,基本数据类型的转换与方法互调用练习
step 1:新增一个名为Hero.cpp文件,并编写各类C方法,详细信息间注释。
/**
* Herocpp
*
* @author wangqikai5
* @version 1.0, 2022/1/17
* @since 产品模块版本
*/
#include
#include
#include
using namespace std;
//定义结构体
struct Flash{
int age;
char firstName;
float speed;
double weight;
bool gender;
string name;
unsigned char array[3];
}flash;
//赋值
Flash getFlash () {
flash.age = 23;
flash.firstName = 'f';
flash.speed = 233333.2f;
flash.weight = 58.9;
flash.gender = true;
flash.name = "Bary Alen";
for (int i = 0; i < 3; ++i) {
//asckII码往上加,值为f g h
flash.array[i] = i + 'f';
}
return flash;
}
extern "C" JNIEXPORT jobject JNICALL
Java_com_helper_jnidemo_MainActivity_getFlash(JNIEnv *env, jobject thiz) {
//获取结构体数据
Flash f = getFlash();
//string转成Java String的时候要转成jstring
jstring name = env->NewStringUTF(f.name.c_str());
//初始化一个jchararray用于存放array数据
jcharArray array = env->NewCharArray(3);
//开辟一个jchar数组
jchar *pArry = (jchar*) malloc(3);
for (int i = 0; i < 3; i++) {
//将char[]数组中的内容,先赋值到jchar数组
*(pArry + i) = f.array[i];
}
//然后再付给jchararray
env->SetCharArrayRegion(array, 0, 3, pArry);
//获取Java类
jclass flash = env->FindClass("com/helper/jnidemo/Flash");
//获取Java类的构造方法,
// 代表类的构造方法,如果是其他方法,就是传方法名
//第三个参数,sig,分别为Flash类构造方法中各参数的代表值
//I:int, C:char, F:float, D:double, Z:boolean, [C:char[], Ljava/lang/String;代表String
jmethodID init = env->GetMethodID(flash, "", "(ICFDZ[CLjava/lang/String;)V");
//构造Flash对象,注意后最后的数组与String,是取上面装换的内容
jobject obj = env->NewObject(flash, init, f.age, f.firstName, f.speed, f.weight, f.gender, array, name);
//释放开辟的内存
free(pArry);
return obj;
}
step 2:CMakeLists里面添加名为Hero的库。
#设置编译时CMake的最低需求版本
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
project("jnidemo")
# 这里是将native-lib.cpp转换成SHARED(共享)库,命名为native-lib
add_library(
# 库名称
native-lib
# 库的类型:SHARED表示动态so库,STATIC表示静态a库
SHARED
#编译的cpp文件源文件路径
native-lib.cpp)
# 这里将Hero.cpp文件装换成转换成SHARED库,命名为Hero
add_library(
# 库名称
Hero
# 库的类型:SHARED表示动态so库,STATIC表示静态a库
SHARED
#编译的cpp文件源文件路径
Hero.cpp)
#可以add多个库,继续写 add_library
#寻找想要添加的NDK库名,一般为系统提供的库
find_library( # 自定义名称
log-lib
#系统库名称,这边是系统提供的log库
log)
# 将so库与库文件进行连接,可以链接多个库,类似Android里面的依赖添加
target_link_libraries(
#
native-lib
#
Hero
#avcodec
# log的库名称
${log-lib})
step 3:Java层新建一个名为Flash的类。
/**
* Flash类
*
* @author wangqikai5
* @version 1.0, 2022/1/17
* @since 产品模块版本
*/
public class Flash {
private int age;
private char firstName;
private float speed;
private double weight;
private boolean gender;
private String name;
private char[] array;
public Flash(int age, char firstName, float speed, double weight, boolean gender, char[] array,String name) {
this.age = age;
this.firstName = firstName;
this.speed = speed;
this. weight = weight;
this.gender = gender;
this.array = array;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getFirstName() {
return firstName;
}
public void setFirstName(char firstName) {
this.firstName = firstName;
}
public float getSpeed() {
return speed;
}
public void setSpeed(float speed) {
this.speed = speed;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char[] getArray() {
return array;
}
public void setArray(char[] array) {
this.array = array;
}
}
step 4:Java层MainActivity方法调用。
public class MainActivity extends AppCompatActivity {
/**
* 加载native库
*/
static {
System.loadLibrary("native-lib");
System.loadLibrary("Hero");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.sample_text);
tv.setText(JSON.toJSONString(getFlash()));
}
public native String stringFromJNI();
/**
* 声明native方法
* @return
*/
public native Flash getFlash();
}
step 5:结果展示。