NDK&JNI開發總結
簡介
附個不錯的博客 https://www.jianshu.com/p/87ce6f565d37
在Android Framework中,需要提供一種媒介或 橋梁,將Java層(上層)與C/C++層(下層)有機的聯系起來,使得他們互相協調完成某些任務,而充當這種媒介的就是Java本地介面(JNI,Java Native Interface),JNI提供一些列的介面,允許Java類與C/C++等本地編輯語言(在JNI中,這些語言被稱為 本地語言)撰寫的應用 程式、模塊 、庫進行互動操作,比如,在Java類中使用C語言庫中的函式或在C語言中使用 Java類別庫,都需要借助JNI,
Android NDK是一個開發工具集,提供一系列工具快速開發C/C++的動態庫,并能自動將 .so/.dll 和 Java 應用一起打包到Apk;
NDK提供工具可以方便JNI呼叫C/C++,而且提供了交叉編譯器可以修改.mk檔案生成特定CPU平臺的動態庫,并能將so和java應用一起打包到apk中;簡單說就是JNI負責Java與C/C++進行互相操作,NDK提供工具方便在Android平臺使用JNI;
JNI的優點
- 可以呼叫c/c++代碼,效率和性能好
- JNI編譯的so庫反編譯難度更大
java呼叫c/c++代碼
extern "C"
JNIEXPORT jstring JNICALL
native_test_ffmpeg(JNIEnv *env,jobject thiz){
return env->NewStringUTF("native_test_ffmpeg");
}
//nativeTest是java的native方法名,native_test_ffmpeg是c/c++的實作方法,"()Ljava/lang/String;"代表此方法輸入引數為空,輸出引數為String
static JNINativeMethod g_methods[] = {
{"nativeTest","()Ljava/lang/String;",(void*)native_test_ffmpeg}
};
//把c/c++方法和java方法關聯起來,不需要按照“Java_包名_類名_方法名”規則來生成方法
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
vm->GetEnv((void**)&env,JNI_VERSION_1_6);
jclass pJclass = env->FindClass(JNI_CLASS_PATH);
env->RegisterNatives(pJclass,g_methods,sizeof(g_methods)/sizeof(g_methods[0]));
return JNI_VERSION_1_6;
}
signature說明
輸入引數在"()"內,輸出引數在"()"外,多個引數順序存放,陣列用"["標識,例如:
([Student;)[Student; => Student[] xxx(Student[]){}
(I)S => short xxx(int i){}
基本資料型別對應符號如下:
boolean Z
byte B
char C
short S
int I
long L
float F
double D
void V
java類對應:
L包路徑/類名
c/c++呼叫java代碼
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_ffmpegtest_MainActivity_stringFromJNI2(JNIEnv *env, jobject thiz) {
//step1 找到類
jclass sJclass = env->FindClass(JNI_CLASS_PATH_2);
//step2 找到方法
jmethodID method_init_id = env->GetMethodID(sJclass, "<init>", "()V");//找到構造方法
jmethodID method_set_id = env->GetMethodID(sJclass, "setYear", "(I)V");//找到構造方法
jmethodID method_get_id = env->GetMethodID(sJclass, "getYear", "()I");//找到構造方法
//step3 new object
jobject obj = env->NewObject(sJclass, method_init_id);
//step4 呼叫相應方法
env->CallVoidMethod(obj,method_set_id,18);
jint year = env->CallIntMethod(obj, method_get_id);
char temp[] = {0,};
sprintf(temp,"%d",year);
std::string helloF = "hello ffmpeg from C++, year =";
helloF.append(temp);
return env->NewStringUTF(helloF.c_str());
}
CMakeLists.txt配置
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
#專案名稱,也就是我安卓專案的名字
project("ffmpegtest")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 方式一(驗證不通過)
# 引入FFmpeg的庫檔案,設定內部的方式引入,指定庫的目錄是 -L 指定具體的庫-l
# 這種方式方便快捷
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L../../../libs/${CMAKE_ANDROID_ARCH_ABI}")
#設定ffmpeg庫所在路徑的變數
set(FF ${CMAKE_SOURCE_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI})
add_library(avcodec SHARED IMPORTED) #三個引數,第一個,庫名稱;第二個,SHARED動態庫或STATIC靜態庫;第三個,IMPORTED或xx.cpp
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${FF}/libavcodec.so) #來源,此處是添加外部引入的庫libs/libavcodec.so->avcodec
add_library(avformat SHARED IMPORTED)
set_target_properties(avformat PROPERTIES IMPORTED_LOCATION ${FF}/libavformat.so)
add_library(avutil SHARED IMPORTED)
set_target_properties(avutil PROPERTIES IMPORTED_LOCATION ${FF}/libavutil.so)
add_library(swscale SHARED IMPORTED)
set_target_properties(swscale PROPERTIES IMPORTED_LOCATION ${FF}/libswscale.so)
add_library(swresample SHARED IMPORTED)
set_target_properties(swresample PROPERTIES IMPORTED_LOCATION ${FF}/libswresample.so)
add_library(avfilter SHARED IMPORTED)
set_target_properties(avfilter PROPERTIES IMPORTED_LOCATION ${FF}/libavfilter.so)
add_library( native-lib
SHARED
${CMAKE_SOURCE_DIR}/src/main/cpp/native-lib.cpp)#來源是從native-lib.cpp檔案編譯
find_library( log-lib log )
find_library( android-lib android )
include_directories(${CMAKE_SOURCE_DIR}/libs/includes)
target_link_libraries( #目標庫
native-lib
# 把ffmpeg的動態庫以來進來
avformat
avcodec
avutil
avfilter
swscale
swresample
${log-lib}
${android-lib})
專案名稱,也就是我安卓專案的名字
project("ffmpegtest")
三個引數,第一個,庫名稱;第二個,SHARED動態庫或STATIC靜態庫;第三個,IMPORTED(外部引入)或xx.cpp(從CPP編譯)
add_library( native-lib SHARED ${CMAKE_SOURCE_DIR}/src/main/cpp/native-lib.cpp)
add_library(avcodec SHARED IMPORTED)
來源,此處是添加外部引入的庫libs/libavcodec.so->avcodec
set_target_properties(avcodec PROPERTIES IMPORTED_LOCATION ${FF}/libavcodec.so)
添加依賴的庫
find_library( android-lib android )
依賴庫檔案路徑
include_directories(${CMAKE_SOURCE_DIR}/libs/includes)
把動態庫鏈接到一個庫,第一個引數目標庫,后面引數都是要鏈接的庫
target_link_libraries( #目標庫
native-lib
# 把ffmpeg的動態庫以來進來
avformat
avcodec
avutil
avfilter
swscale
swresample
${log-lib}
${android-lib})
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/229391.html
標籤:Android
上一篇:小程式用webview內嵌h5頁面,實作分享、微信支付功能 , h5傳參跳轉web-view 微信小程式
下一篇:NDK&JNI開發總結
