為什么要使用NDK開發:
實際的開發程序中會有業務需要使用Java與C/C++兩者之間進行資料互動,
很多的業務里都需要C/C+ +層拿到資料去呼叫Java層的方法,這兩層之間的相互呼叫顯得如此的重要,兩層之間的相互呼叫使得程式更具有高效性、安全性,下面主要講解一下C/C+ +與Java的相互呼叫,
如何建立一個JNI工程:
新建工程示例:

next,

next

這樣一個新的JNI工程就創建完成
已有工程上 創建JNI
步驟:
第一步:新建一個native呼叫java類,
第二步:得到native呼叫java類的.class檔案和 .h頭檔案,
第三步:撰寫CMakeLists.txt檔案,
第四步:定義實作頭檔案的函式,
第五步:java層呼叫通過native的java方法 呼叫 JNI當中的函式,實作Java與C/C++互動,
首先新建一個空白工程:空白表單的布局
第一步:然后在Activity目錄下新建一個JavaNativeUtils類:

JavaNativeUtils.java具體代碼:
public class JavaNativeUtils {
public static final String LOG_TAG = "==JavaNativeUtils.LOG==";
public static final String RETURN_TAG = "==JavaNativeUtils.RETURN==";
/***********************無引數無回傳****************************/
public void noParams(){
Log.e(LOG_TAG,"JavaNativeUtils describe() Called!");
}
public static void staticNoParams(){
Log.e(LOG_TAG,"JavaNativeUtils.staticNoParams() Called!");
}
/***********************有引數有回傳****************************/
public String hasParams(String param1){
Log.e(LOG_TAG,"JavaNativeUtils javaMethodHasParams(String msg) is Called!");
return LOG_TAG+ " javaMethodHasParams Method return!";
}
public static String staticHasParams(String param1s, int params2){
Log.e(LOG_TAG,"JavaNativeUtils javaStaticHasParams(String msg) is Called!");
return LOG_TAG+ "javaStaticHasParams Method return!!!";
}
/****************************native 方法區********************************/
//java物件 呼叫Jni無參無回傳
public native void JavaCallJniVoid();
//java物件 呼叫Jni有參無回傳
public native void JavaCallJniVoidHasParams(String p1, int p2);
//Java類呼叫 Jni無參有回傳
public static native String JavaStaticCallJniVoid();
//Java類呼叫 Jni有參有回傳
public static native String JavaStaticCallJniVoidHasParams(String p1 ,int[] p2);
}
第二步:寫好native方法之后,就需要我們生成對應的.class和.h頭檔案
生成.class檔案:
如果我們直接在當前目錄下運行javac JavaNativeUtils.java 肯定會報錯:

提示的是編碼錯誤:修改方案如下
javac -encoding UTF-8 JavaNativeUtils.java
這樣就可以成功生成.class檔案
生成.h檔案
javac -h cpp\jni java\com\wcc\jnitest\JavaNativeUtils.java -encoding UTF-8

此時有紅色報錯,無需吃驚,此檔案我們是不需要用來編譯的,
在此檔案同目錄下隨便新建一個XXX.cpp檔案 參考這個頭檔案,
第三步:撰寫CMakeLists.txt代碼如下:
cmake_minimum_required(VERSION 3.4.1) #支持最小的版本號3.4.1 /3.10.2
add_library(
# Sets the name of the library.
JavaNUtils #生成的library名稱
# Sets the library as a shared library.
SHARED #
# Provides a relative path to your source file(s).
demo.cpp #通過目標cpp檔案,或者是檔案串列,下放有具體串列方法
#src/main/cpp/nativec.cpp
)
find_library( #查找lib
# Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
#指定用到的系統庫或者NDK庫或者第三方庫的搜索路徑,可選,
#LINK_DIRECTORIES(/usr/local/lib)
target_link_libraries( #連接${}里面的 library到 上方的 library
# Specifies the target library.
JavaNUtils
# Links the target library to the log library
# included in the NDK.
${log-lib})
第四步:
XXX.cpp這里命名為demo.cpp,代碼如下:
#include "com_dywcc_jnitest_JavaNativeUtils.h"
#include <jni.h>
#include "stdio.h"
using namespace std;
#include "android/log.h"
#define LOG_TAG "demo.cpp"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG ,__VA_ARGS__) // //呼叫Android列印
extern "C"
JNIEXPORT void
JNICALL Java_com_dywcc_testjni_JavaNativeUtils_JavaCallJniVoid(JNIEnv* env,jobject thiz) {
// TODO: 呼叫JAVA層 無引數無回傳值noParams()方法
//1.通過java物件獲取所在的類名
jclass j_clz = env->GetObjectClass( thiz);
//2.通過方法名和 類名,以及標記號 獲得方法的所在的記憶體地址
jmethodID j_methodId = env->GetMethodID(j_clz,"noParams","()V");
//3.通過AllocObject(j_clz)函式得到物件. C++沒有GC ,所以之后需要手動釋放資源
jobject j_obj = env->AllocObject(j_clz);
LOGE("===========JavaCallJniVoid======call noParams ");
//4.通過物件和方法名 呼叫java層方法
env->CallVoidMethod(j_obj,j_methodId);
}
extern "C"
JNIEXPORT void
JNICALL Java_com_dywcc_testjni_JavaNativeUtils_JavaCallJniVoidHasParams(JNIEnv* env,jobject thiz, jstring p1,jint p2) {
// TODO: 呼叫Java 無參無回傳靜態方法staticNoParams()
//1.通過java物件獲取其類名
jclass j_clz = env->GetObjectClass( thiz);
//2.通過方法名和 類名,以及標記號 獲得方法的所在的記憶體地址
jmethodID j_methodId = env->GetStaticMethodID(j_clz,"staticNoParams", "()V");
char * pp = (char *)env->GetStringUTFChars(p1,0);
LOGE("===========JavaCallJniVoidHasParams====== call staticNoParams=== %s %d",pp, p2);
//3.通過物件和方法名 呼叫java層方法
env->CallStaticVoidMethod(j_clz,j_methodId);
}
extern "C"
JNIEXPORT jstring
JNICALL Java_com_dywcc_testjni_JavaNativeUtils_JavaStaticCallJniVoid(JNIEnv * env, jclass clazz) {
// TODO: JNI層呼叫 java層物件的有參hasParams方法
//1.通過方法名和 類名,以及標記號 獲得方法的所在的記憶體地址
jmethodID j_methodId = env->GetMethodID(clazz,"hasParams","(Ljava/lang/String;)Ljava/lang/String;");
//2.通過類名,分配一個java物件
jobject j_obj = env->AllocObject(clazz);
//定義一個傳入的引數變數
char * jni_params = "===jni_prams ===";
jstring params = env->NewStringUTF(jni_params);
LOGE("===========JavaStaticCallJniVoid====== call hasParams");
//3.通過物件和方法名及其引數 呼叫java層方法
jstring result = (jstring)env->CallObjectMethod(j_obj,j_methodId,params);
return result;
}
extern "C"
JNIEXPORT jstring
JNICALL Java_com_dywcc_testjni_JavaNativeUtils_JavaStaticCallJniVoidHasParams(JNIEnv * env, jclass clazz,jstring p1, jintArray p2) {
// TODO: JNI層呼叫 java層 有參靜態 staticHasParams 方法
//1.通過方法名和 類名,以及標記號 獲得方法的所在的記憶體地址
jmethodID j_methodId = env->GetStaticMethodID(clazz,"staticHasParams","(Ljava/lang/String;I)Ljava/lang/String;");
//定義兩個個傳入的引數變數
jint params =100;
LOGE("===========JavaStaticCallJniVoidHasParams======call staticHasParams");
//2.通過物件和方法名 呼叫java層方法
jstring result = (jstring)env->CallStaticObjectMethod(clazz,j_methodId,p1,params);
return result;
}
第五步:
Java層呼叫代碼如下
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private JavaNativeUtils utils;
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
utils = new JavaNativeUtils();
binding.JavaCallJniVoid.setOnClickListener(this::testClick);
binding.JavaCallJniVoidHasParams.setOnClickListener(this::testClick);
binding.JavaStaticCallJniVoid.setOnClickListener(this::testClick);
binding.JavaStaticCallJniVoidHasParams.setOnClickListener(this::testClick);
}
public void testClick(View view){
switch (view.getId()){
case R.id.JavaCallJniVoid:
utils.JavaCallJniVoid();
break;
case R.id.JavaCallJniVoidHasParams:
utils.JavaCallJniVoidHasParams("lixiaolong",288888);
break;
case R.id.JavaStaticCallJniVoid:
String result= JavaNativeUtils.JavaStaticCallJniVoid();
binding.tvStaticNativeInfo.setText(result);
break;
case R.id.JavaStaticCallJniVoidHasParams:
String re= JavaNativeUtils.JavaStaticCallJniVoidHasParams("zhangsan ",new int[]{2021});
binding.tvStaticNativeInfo.setText(re);
break;
}
}
}
activity_main.xml檔案
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.dywcc.testjni.MainActivity">
<TextView
android:id="@+id/tv_native_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="非靜態native:Jni呼叫無參函式"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/JavaCallJniVoid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CallJniVoid"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_native_info" />
<Button
android:id="@+id/JavaCallJniVoidHasParams"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CallJniVoidHasParams"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/JavaCallJniVoid" />
<TextView
android:id="@+id/tv_static_native_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="靜態native:Jni呼叫有參函式"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/JavaCallJniVoidHasParams" />
<Button
android:id="@+id/JavaStaticCallJniVoid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CallJniVoid"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_static_native_info" />
<Button
android:id="@+id/JavaStaticCallJniVoidHasParams"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CallJniVoidHasParams"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/JavaStaticCallJniVoid" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/291342.html
標籤:其他
