JNI在项开发中会被用到的场景

编程入门 行业动态 更新时间:2024-10-14 04:30:14

JNI在项开发<a href=https://www.elefans.com/category/jswz/34/1756890.html style=中会被用到的场景"/>

JNI在项开发中会被用到的场景

1、JNI注册
(1)静态注册
// Java
public native String stringFromJNI(String msg);
// JNI native方法实现
extern "C"
JNIEXPORT void JNICALL
Java_com_jni_study_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz,jstring msg) {std::string hello = "Hello from C++";//do somethingreturn env->NewStringUTF(hello.c_str());
}
(2)动态注册
jstring stringFromJNI(JNIEnv *env, jobject thiz){std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}static const JNINativeMethod gMethods[] = {{"stringFromJNI", "()Ljava/lang/String;", (jstring*)stringFromJNI}
};JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved){__android_log_print(ANDROID_LOG_INFO, "native", "Jni_OnLoad");JNIEnv* env = NULL;if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) //从JavaVM获取JNIEnv,一般使用1.4的版本return -1;jclass clazz = env->FindClass("com/example/efan/jni_learn2/MainActivity");if (!clazz){__android_log_print(ANDROID_LOG_INFO, "native", "cannot get class: com/example/efan/jni_learn2/MainActivity");return -1;}if(env->RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0]))){__android_log_print(ANDROID_LOG_INFO, "native", "register native method failed!\n");return -1;}return JNI_VERSION_1_4;
}
2、Java和C互调?
(1)Java调用C/C++
// Java代码
public class MainActivity extends AppCompatActivity {   // 静态加载c/c++文件static {System.loadLibrary("native-lib");}// 用native声明c/c++方法public native String stringFromJNI();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView tv = (TextView) findViewById(R.id.sample_text);tv.setText(stringFromJNI());}
}
// JNI代码
#include <jni.h>
#include <string> 
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_test_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {std::string hello = "Hello from C++";return env->NewStringUTF(hello.c_str());
}
(2)C/C++调用Java
// Java代码
public class PrintUtils{private void printMessage(String message) {System.out.print("....");}
}
// JNI代码
JNIEXPORT void JNICALL Java_com_jni_study_MainActivity_printMessage(JNIEnv *env, jclass cls){// 1、从classpath路径下搜索PrintUtils这个类,并返回该类的Class对象jclass clazz = (*env)->FindClass(env, "com/jni/study/PrintUtils");// 2、获取类的默认构造方法IDjmethodID mid_construct = (*env)->GetMethodID(env,clazz, "<init>","()V");// 3、查找实例方法的IDjmethodID  mid_instance = (*env)->GetMethodID(env, clazz, "printMessage", "(Ljava/lang/String;I)V");// 4、创建该类的实例jobject jobj = (*env)->NewObject(env,clazz,mid_construct);// 5、调用对象的实例方法jstring str_arg = (*env)->NewStringUTF(env,"我是实例方法");(*env)->CallVoidMethod(env,jobj,mid_instance,str_arg);// 删除局部引用(*env)->DeleteLocalRef(env,clazz);(*env)->DeleteLocalRef(env,jobj);(*env)->DeleteLocalRef(env,str_arg);
}
  • jclass FindClass(const char* name) 根据类名来查找一个类,完整类名。
  • jclass GetObjectClass(jobject obj) 根据一个对象,获取该对象的类。
  • jclass GetSuperClass(jclass obj) 获取一个传入的对象获取他的父类的jclass。
  • jmethodID GetMethodID(jclass clazz, const char* name, const char* sig) 获取非静态方法的ID。
  • jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig) 获取静态方法的ID。
3、JNI在开发中会被用到的场景
(1)加密算法
  • 对图片、文件、音视频进行加密处理。
(2)图片压缩
  • 使用libjpeg,在ubuntu系统下生成Android平台不同cpu架构使用的头文件和.a静态库并导入Android项目中。
  • 然后通过JNI是调用头文件和静态库中的方法去进行图片压缩,比如哈夫曼算法压缩、去掉透明度等一系列方式在保证图片清晰度在Android上相差不大的情况下降低图片文件大小。
  • 最后在编程成apk的时候会生成对应的.so库。
(3)音频压缩
  • 使用FFAC,在ubuntu系统下生成Android平台不同cpu架构使用的头文件和.a静态库并导入Android项目中。
  • 首先通过Android系统提供的AudioRecord进行音频采集。
  • 然后通过FAAC将采集好PCM音频数据编码成AAC。
  • 最终将AAC音频数据通过流媒体协议(rtmp或webrtc)将其发送到流媒体服务。
(4)视频压缩
  • 使用x264,在ubuntu系统下生成Android平台不同cpu架构使用的头文件和.a静态库并导入Android项目中。
  • 首先通过Android系统提供的Camera2进行视频数据采集。
  • 然后通过x264将采集好的YUV/RGB原始视频数据编程h264。
  • 最终h264视频数据通过流媒体协议(rtmp或webrtc)将其发送到流媒体服务。
(5)推流
  • 使用RTMPDump,在ubuntu系统下生成Android平台不同cpu架构使用的头文件和.a静态库并导入Android项目中。
  • 然后使用RTMPDump将压缩后的音频和视频上传大流媒体服务器。
4、JNI Crash定位步骤
(1)找到未strip且符号表完整的so库文件
# 这几行代码表示debug版本的so文件保留so保留符号库,这样会导致so文件很大,
# 如果要让release版本保留符号库文件,就替换成CMAKE_C_FLAGS_RELEASE和CMAKE_CXX_FLAGS_RELEASE
# 但务必在正式对外发布的时候去掉release 配置的-g选项,以免增加文件size
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
# R16之前版本的NDK默认是编译时加-g的,新版本不确定,所以需要不strip的 so文件,最好在CMake里配置一下-g// strip之后的文件所在目录:
app/build/intermediaters/transforms/stripDebugSymbol/debug
(2)确定发生Crash的设备对应的CPU架构
  • 在JNI Crash的日志里,如果有lib/arm, 则是armeabi-v7a架构; 如果有lib/arm64, 则是arm64-v8a架构;然后根据CPU架构找相应的toolchain:
  • arm64-v8a对应的是aarch64-linux-android-4.9
  • armeabi-v7a对应的是arm-linux-androideabi-4.9
(3)使用add2line和ndk-stack等工具分析JNI Crash的log
  • addr2line:作用是根据内存地址找到对应的报错代码的文件名和行号。
// 所在目录是toolchain的bin文件夹
// 比如aarch64-linux-android-4.9对应的bin文件夹是:
/Android/Sdk/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin// arm-linux-androideabi-4.9,对应的bin文件夹是:
/media/kyle/a393d005-ebe5-42a0-8c6a-c86fdfb185c1/Android/Sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin// 用法:
# -f表示显示函数名, -e表示execution,后面是包含符号库的文件 以及报错的内存地址(即Crash log里pc后的字段)
arm-linux-androideabi-addr2line -f -e xxx.so 0x8eb09258
  • ndk-stack:作用是一键生成更可读的Crash日志。
// 所在目录是:
/media/kyle/a393d005-ebe5-42a0-8c6a-c86fdfb185c1/Android/Sdk/ndk-bundle/ndk-stack// 用法1:
# -sym表示symbols
ndk-stack -sym App/build/intermediates/transforms/mergeJniLibs/release/0/lib/对应的abi目录 -dump jniCrash.log// 用法2:
adb logcat | ndk-stack -sym  App/build/intermediates/transforms/mergeJniLibs/release/0/lib/对应的abi目录

更多推荐

JNI在项开发中会被用到的场景

本文发布于:2024-02-08 21:12:56,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675107.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:中会   场景   JNI

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!