目录
- 1. 背景
- 2. Java调C-Demo代码
- JNI.java
- MainActivity.java
- Android.mk
- Application.mk
- com_stone_javacallc_JNI.h
- javacallc.c
- build.gradle
- 3. C调Java-Demo代码
- 3.1 查看JNI代码方法签名的方法
- 3.2 代码结构
- 3.3 JNI.class
- 3.4 MainActivity.class
- 3.5 Android.mk
- 3.6 Application.mk
- 3.7 CCallJava.c
- 3.8 com_stone_ccalljava_JNI.h
- 3.9 layout/activity_main.xml
- 3.10 build.gradle
- 3.11 运行结果截图
1. 背景
2. Java调C-Demo代码
代码结构
JNI.java
package com.stone.javacallc;/*** Created by stoneWang* Created on 2024/1/16* java调用C*/
public class JNI {{System.loadLibrary("javacallc");}/*** 让C代码做加法运算,把结果返回** @param x* @param y* @return*/public native int add(int x, int y);/*** 从Java传入字符串,C代码进行拼接** @param s I am from java* @return I am from java add I am from C*/public native String sayHello(String s);/*** 让C代码给每个元素加上10** @param intArray* @return*/public native int[] increaseArrayEles(int[] intArray);
}
MainActivity.java
package com.stone.javacallc;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.util.Log;
import android.view.View;public class MainActivity extends AppCompatActivity {private JNI jni;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);jni = new JNI();}public void add(View view) {int result = jni.add(99, 1);Log.e(MainActivity.class.getSimpleName(), "result:" + result);}public void string(View view) {String result = jni.sayHello("I am from java ");Log.e(MainActivity.class.getSimpleName(), "result:" + result);}public void array(View view) {}public void checkpw(View view) {}
}
Android.mk
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=javacallc
LOCAL_SRC_FILES :=javacallc.c
include $(BUILD_SHARED_LIBRARY)
Application.mk
App_ABI:=all
com_stone_javacallc_JNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_stone_javacallc_JNI */#ifndef _Included_com_stone_javacallc_JNI
#define _Included_com_stone_javacallc_JNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class: com_stone_javacallc_JNI* Method: add* Signature: (II)I*/
JNIEXPORT jint JNICALL Java_com_stone_javacallc_JNI_add(JNIEnv *, jobject, jint, jint);/** Class: com_stone_javacallc_JNI* Method: sayHello* Signature: (Ljava/lang/String;)I*/
JNIEXPORT jstring JNICALL Java_com_stone_javacallc_JNI_sayHello(JNIEnv *, jobject, jstring);/** Class: com_stone_javacallc_JNI* Method: increaseArrayEles* Signature: ([I)[I*/
JNIEXPORT jintArray JNICALL Java_com_stone_javacallc_JNI_increaseArrayEles(JNIEnv *, jobject, jintArray);#ifdef __cplusplus
}
#endif
#endif
javacallc.c
//
// Created by wanglei on 2024/1/16.
//
# include "com_stone_javacallc_JNI.h"
# include "string.h"/*** 把一个jstring转换成一个c语言的char* 类型.*/
char* _JString2CStr(JNIEnv* env, jstring jstr) {char* rtn = NULL;jclass clsstring = (*env)->FindClass(env, "java/lang/String");jstring strencode = (*env)->NewStringUTF(env,"GB2312");jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B");jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312");jsize alen = (*env)->GetArrayLength(env, barr);jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE);if(alen > 0) {rtn = (char*)malloc(alen+1); //"\0"memcpy(rtn, ba, alen);rtn[alen]=0;}(*env)->ReleaseByteArrayElements(env, barr, ba,0);return rtn;
}/**** @param env* @param jobj* @param ji* @param jj* @return*/
jint Java_com_stone_javacallc_JNI_add(JNIEnv *env, jobject jobj, jint ji, jint jj){int result = ji + jj;return result;
};jstring Java_com_stone_javacallc_JNI_sayHello(JNIEnv *env, jobject jobj, jstring jstr){char* fromJava = _JString2CStr(env, jstr);char* fromc = "add I am from C";// 拼接函数strcatstrcat(fromJava, fromc); // 把拼接的结果放在第一参数里面// 将char转为jstringreturn (*env)->NewStringUTF(env, fromJava);
};
build.gradle
apply plugin: 'com.android.application'android {compileSdkVersion 30buildToolsVersion "30.0.2"defaultConfig {applicationId "com.stone.javacallc"minSdkVersion 26targetSdkVersion 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"ndk{moduleName "javacallc"abiFilters "armeabi", "armeabi-v7a", "arm64-v8a" // cpu类型}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}externalNativeBuild {ndkBuild {path "src/main/jni/Android.mk"}}
}dependencies {implementation fileTree(dir: "libs", include: ["*.jar"])implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.1'testImplementation 'junit:junit:4.12'androidTestImplementation 'androidx.test.ext:junit:1.1.2'androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'}
3. C调Java-Demo代码
3.1 查看JNI代码方法签名的方法
先Build工程,生成class文件,再找到对应的class文件,打开对应目录
执行javap -s xxx.class,可答应该class对应的Java文件的方法签名
3.2 代码结构
3.3 JNI.class
package com.stone.ccalljava;import android.util.Log;/*** Created by stoneWang* Created on 2024/1/18*/
public class JNI {{System.loadLibrary("ccalljava");}/*** 当执行这个方法的时候,让C代码调用* public int add(int x, int y)*/public native void callbackAdd();/*** 当执行这个方法的时候,让C代码调用* public void helloFromJava()*/public native void callbackHelloFromJava();/*** 当执行这个方法的时候,让C代码调用void printString(String s)*/public native void callbackPrintString();/*** 当执行这个方法的时候,让C代码静态方法 static void sayHello(String s)*/public native void callbackSayHello();public int add(int x, int y) {Log.e("TAG", "add() x=" + x + " y=" + y);return x + y;}public void helloFromJava() {Log.e("TAG", "helloFromJava()");}public void printString(String s) {Log.e("TAG","C中输入的:" + s);}public static void sayHello(String s){Log.e("TAG", "我是java代码中的JNI."+ "java中的sayHello(String s)静态方法,我被C调用了:"+ s);}
}
3.4 MainActivity.class
package com.stone.ccalljava;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;public class MainActivity extends AppCompatActivity {private JNI jni;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);jni = new JNI();}public void onClick (View view) {jni.callbackAdd();jni.callbackHelloFromJava();jni.callbackPrintString();jni.callbackSayHello();}
}
3.5 Android.mk
LOCAL_PATH :=$(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE :=ccalljava
LOCAL_SRC_FILES :=ccalljava.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
3.6 Application.mk
App_ABI:=all
3.7 CCallJava.c
#include "com_stone_ccalljava_JNI.h"
#include <stdlib.h>
#include <stdio.h>#include <android/log.h>
#define LOG_TAG "System.out"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)/*** 让C代码调用 java 中JNI类的 public int add(int x, int y)*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackAdd
(JNIEnv * env, jobject jobj){//1.得到字节码//jclass (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env,"com/stone/ccalljava/JNI");//2.得到方法jmethodID jmethodIDs = (*env)->GetMethodID(env, jclazz, "add", "(II)I");//3.实例化该类jobject jobject = (*env)->AllocObject(env, jclazz);//4.调用方法jint value = (*env)->CallIntMethod(env, jobject, jmethodIDs, 99, 1);//成功调用了public int add(int x, int y)printf("value===%d\n",value);LOGE("value===%d\n",value);
};/*** 让C代码调用* public void helloFromJava()*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackHelloFromJava(JNIEnv * env, jobject jobj){//1.得到字节码//jclass (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env,"com/stone/ccalljava/JNI");//2.得到方法//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIDs= (*env)->GetMethodID(env,jclazz,"helloFromJava","()V");//3.实例化该类// jobject (*AllocObject)(JNIEnv*, jclass);jobject jobject =(*env)->AllocObject(env,jclazz);//4.调用方法//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);(*env)->CallVoidMethod(env,jobject,jmethodIDs);//成功调用了public void helloFromJava()
};/*** 让C代码调用void printString(String s)*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackPrintString(JNIEnv *env , jobject jobj){//1.得到字节码//jclass (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env,"com/stone/ccalljava/JNI");//2.得到方法//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIDs= (*env)->GetMethodID(env,jclazz,"printString","(Ljava/lang/String;)V");//3.实例化该类// jobject (*AllocObject)(JNIEnv*, jclass);jobject jobject =(*env)->AllocObject(env,jclazz);//4.调用方法//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);//jstring (*NewStringUTF)(JNIEnv*, const char*);jstring jst = (*env)->NewStringUTF(env, "I am stone!!! this is CCallJava.c");(*env)->CallVoidMethod(env,jobject,jmethodIDs, jst);//成功调用了public void helloFromJava()
};/*** 让C代码调用静态方法static void sayHello(String s)*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackSayHello(JNIEnv * env, jobject jobj){//1.得到字节码//jclass (*FindClass)(JNIEnv*, const char*);jclass jclazz = (*env)->FindClass(env,"com/stone/ccalljava/JNI");//2.得到方法//jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);//最后一个参数是方法签名jmethodID jmethodIDs= (*env)->GetStaticMethodID(env,jclazz,"sayHello","(Ljava/lang/String;)V");//3.实例化该类//void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);// static的不用实例化//4.调用方法//void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);jstring jst = (*env)->NewStringUTF(env, "I am static stone!!! this is CCallJava.c");(*env)->CallStaticVoidMethod(env,jclazz,jmethodIDs, jst);//成功调用了static void sayHello(String s)
};
3.8 com_stone_ccalljava_JNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_stone_ccalljava_JNI */#ifndef _Included_com_stone_ccalljava_JNI
#define _Included_com_stone_ccalljava_JNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class: com_stone_ccalljava_JNI* Method: callbackAdd* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackAdd(JNIEnv *, jobject);/** Class: com_stone_ccalljava_JNI* Method: callbackHelloFromJava* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackHelloFromJava(JNIEnv *, jobject);/** Class: com_stone_ccalljava_JNI* Method: callbackPrintString* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackPrintString(JNIEnv *, jobject);/** Class: com_stone_ccalljava_JNI* Method: callbackSayHello* Signature: ()V*/
JNIEXPORT void JNICALL Java_com_stone_ccalljava_JNI_callbackSayHello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif
3.9 layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:onClick="onClick"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="C调用Java代码" /></LinearLayout>
3.10 build.gradle
apply plugin: 'com.android.application'android {compileSdkVersion 30buildToolsVersion "30.0.2"defaultConfig {applicationId "com.stone.ccalljava"minSdkVersion 26targetSdkVersion 30versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"ndk{moduleName "ccalljava"abiFilters "armeabi", "armeabi-v7a", "arm64-v8a" // cpu类型}ndk {ldLibs "log"}}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}externalNativeBuild {ndkBuild {path "src/main/jni/Android.mk"}}
}dependencies {implementation fileTree(dir: "libs", include: ["*.jar"])implementation 'androidx.appcompat:appcompat:1.2.0'implementation 'androidx.constraintlayout:constraintlayout:2.0.1'testImplementation 'junit:junit:4.12'androidTestImplementation 'androidx.test.ext:junit:1.1.2'androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'}