Android SDK全称是:Android Software Development Kit【Android 软件开发工具包】,Android SDK主要为开发者提供Java层的API调用以及开发过程中所需要的一些构建工具和其它工具;所以说你可以把Android SDK理解成就是Android应用的Java层开发【执行环境:虚拟机】
Android NDK全称是:Android Native Development Kit【Android 本地开发工具包】,Android NDK主要为开发者提供C/C++层的API接口以及开发过程中所需要的一些构建工具和其它工具;所以说你可以把Android NDK理解成就是Android应用的C/C++底层库开发【执行环境:操作系统】
Android JNI全称:Android native interface【Android 本地接口】,Android JNI主要是为上层Java/Kotlin与本地C/C++ 提供互通互调机制,简单点说: Java代码中可以调用Native C/C++代码,Native C/C++代码可以调用上层Java代码;所以说Android JNI就是连接上层Java与本地C/C++互通互调的一个桥梁和机制!
CPU架构: 指令派系:- 精简指令集【RISC】
Intel,AMD - 复杂指令集【CISC】
IBM,ARM
x86,x86-64/x64
arm64-v8a,armeabi-v7a【32位】,armeabi【32位】
- API
API【Application Program Interface 应用程序接口】其实就是一套预先定义的,无需了解内部的实现机理和细节,与硬件系统无关的一套调用接口! - ABI
ABI【Application Binary Interface 应用程序二进制接口】定义了一套二进制规则,它允许在所有兼容该ABI编译的目标代码的操作系统和硬件系统中,无须改动即可运行,从这里我们就看出,ABI其实就是一套约束底层,系统,硬件,编译规则的一套二进制接口!
【EABI : 是 arm 对于 ABI规范的较新(2005年)的实现】
-
安装Android Studio
https://developer.android.google.cn/studio 下载地址
https://developer.android.google.cn/studio/intro/ 帮助文档 -
创建NDK项目
-
配置NDK
手动配置: https://developer.android.google.cn/ndk/downloads
大厂适配ABI文章:https://mp.weixin.qq.com/s/jnZpgaRFQT5ULk9tHWMAGg
module模块: build.gradle
defaultConfig {
applicationId "com.example.ndkdemo"
minSdk 21
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ''
// 方法1:externalNativeBuild-》cmake:
// abiFilters 'armeabi-v7a'
}
}
// 方法2:defaultConfig-》ndk:
ndk{
abiFilters 'armeabi-v7a','arm64-v8a','x86'
}
}
配置输出目录
默认输出目录:
#不同Android Studio版本有的生效有的不生效
#方式1:
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
#方式2:
#set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI})
1.4-JNI基本语法
https://www.kancloud.cn/owenoranba/jni/120478 中文JNI学习参考文档
声明本地方法【Java层:Native方法】//Native方法-》目的-》调用本地C/C++方法! public native String stringFromJNI();实现本地方法【C++层:C++方法】
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_stringFromJNI(
JNIEnv* env,
jobject ) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
本地方法说明【Java层Native声明】
- 静态注册JNI
Java层:Native声明-》对应一种固定格式-》C++层:C++方法【Java_包名_Java类名_方法名】 - 动态注册JNI
JavaVM是虚拟机在JNI层的表示,一个进程只有JVM,所有线程共用JavaVM;
JNIEnv JNIEnv它是一个与线程相关的用来代表java运行环境的,用来进行java-native互调的一个结构体,内部包含了一个JNI本地接口指针【JNINativeInterface* functions】,这个指针又指向了函数指针数组【定义了JNI相关的函数指针】;
同一个线程调用本地方法,JNIEnv是同一个,不同线程调用native方法,JNIEnv不相同【java可以在不同线程中调用】
Native方法中传递过来的jobject其实就是一个java实例引用,实例就是一个具体的对象,这个native方法是一个具体的java对象调用的!
jclassNative方法中传递过来的jclass就是一个java类引用,这个native方法是一个静态类方法,jclass其实这个类引用!
JNI数据类型 基本类型JNI基本类型,可以直接拿来使用,本质还是C/C++的基本数据类型,只不过使用typedef定义了而已!
引用类型不能直接使用,必须通过JNIEnv中的JNI函数转换后,才能够使用!
public native String getNaitiveName(String name);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getNaitiveName(
JNIEnv *env,
jobject thiz,
jstring name) {
int strLen = 0;
strLen = env->GetStringLength(name);
const char* pStr = env->GetStringUTFChars(name,NULL);
env->ReleaseStringUTFChars(name,pStr);
const jchar* pjStr = env->GetStringChars(name,NULL);
env->ReleaseStringChars(name,pjStr);
jstring jNewStr = env->NewStringUTF("Haha");
strLen = env->GetStringUTFLength(jNewStr);
jstring jOutStr = env->NewStringUTF("gaga");
char outStrBuffer[128] = {0};
int outStrLen = 0;
outStrLen = env->GetStringLength(jOutStr);
env->GetStringUTFRegion(jOutStr,0,outStrLen,outStrBuffer);//GetStringRegion unicode
jOutStr = env->NewStringUTF(outStrBuffer);
return jOutStr;
}
数组
public native String getArrayToStr(int[] ary);
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getArrayToStr(
JNIEnv *env,
jobject thiz,
jintArray ary) {
int iNumAry[128];
int jAryLen = 0;
jAryLen = env->GetArrayLength(ary);
env->GetIntArrayRegion(ary,0,jAryLen,iNumAry);
std::string strRet = "";
for(int i=0;i
strRet += std::to_string(iNumAry[i]);
}
jstring jStrRet = env->NewStringUTF(strRet.c_str());
return jStrRet;
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ndkdemo_MainActivity_getArrayToStr(
JNIEnv *env,
jobject thiz,
jintArray ary) {
jint* jAry = env->GetIntArrayElements(ary,NULL);
if(!jAry){
return 0;
}
std::string strRet = "";
int jAryLen = env->GetArrayLength(ary);
for(int i=0;i
strRet += std::to_string(jAry[i]);
}
env->ReleaseIntArrayElements(ary,jAry,0);
jstring jStrRet = env->NewStringUTF(strRet.c_str());
return jStrRet;
}
Naitive构造一维数组:
public native int[] newArrayFromNative();
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_ndkdemo_MainActivity_newArrayFromNative(JNIEnv *env, jobject thiz) {
int nums[10] = {5,2,1};
jintArray jAry = env->NewIntArray(10);
env->SetIntArrayRegion(jAry,0,10,nums);
return jAry;
}
属性
- 获取/修改实例属性
public String name = "哈哈";
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myjnifieldfunc_MainActivity_stringFromJNI(
JNIEnv* env,
jobject jobj) {
//获取jclass
jclass jcls = env->GetObjectClass(jobj);
//获取jFieldID
jfieldID jfId = env->GetFieldID(jcls,"name", "Ljava/lang/String;");
if(!jfId){
return env->NewStringUTF("");
}
//Java:String -> JNI:jstring
jstring jName;
jName = env->NewStringUTF("嘎嘎");
env->SetObjectField(jobj,jfId,jName);
jstring jRetStr;
jRetStr = static_cast(env->GetObjectField(jobj, jfId));
return jRetStr;
}
- 获取/修改全局属性
static public String gName = "全局奥利给";
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnifieldfunc_MainActivity_gstringFromJNI(
JNIEnv *env,
jclass clazz) {
//获取FieldId
jfieldID jfId = env->GetStaticFieldID(clazz,"gName", "Ljava/lang/String;");
//修改FieldValue
jstring jValue = env->NewStringUTF("我改了,你咋滴!");
env->SetStaticObjectField(clazz,jfId,jValue);
}
方法
public void PrintLog(){
Log.d("MainActivity", "PrintLog: Native->Java");
}
public static void PrintStaticLog(){
Log.d("MainActivity", "PrintStaticLog: Native->Java");
}
public native void CallJavaFuncFromJNI();
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myjnifieldfunc_MainActivity_CallJavaFuncFromJNI(
JNIEnv *env,
jobject jobj) {
//jclass
jclass jcls = env->GetObjectClass(jobj);
jmethodID jmId = env->GetMethodID(jcls,"PrintLog", "()V");
if(!jmId){
return;
}
//call 成员方法
env->CallVoidMethod(jobj,jmId);
jmethodID jgmId = env->GetStaticMethodID(jcls,"PrintStaticLog","()V");
if(!jgmId){
return;
}
//call 全局方法
env->CallStaticVoidMethod(jcls,jgmId);
}
局部引用-全局引用
- 局部引用
Native方法作用域中创建的引用对象,返回的引用被称之为局部引用,只能在本Native方法以及调用Native方法的范围内使用,执行完毕离开作用域会被自动释放,没有被释放前,是不能被垃圾回收的,不能保存局部引用至全局【内存异常或系统崩溃】!
**局部引用手动释放:**DeleteLocalRef - 全局引用
NewGlobalRef唯一创建全局引用API【局部引用的区别】
DeleteGlobalRef 释放全局引用
都是需要手动创建和释放!



