文章目录
- 1、jni java 文件 CallJni.java
- 2、C++ 文件 testnative.cpp
- 3、C++ 头文件,testnative.h
- 4、CMakeLists.txt
- 5、proguard-rules.pro 添加防混淆
- 6、build.gradle(app)添加cmake 编译 路径
- 7、ManiActivity.java 引用jni函数
- 8、结果
1、jni java 文件 CallJni.java
package com.example.testjni;
import android.util.Log;
public class CallJni {
private String TAG = "callJni";
static {
System.loadLibrary("TestJniLib"); //编译的 so 库名称
}
//java 调用 C++
public static native int testAddNumJavaToNative(int numa,int numb);
//java 调用 C++
public static native void testStringJavaToNative(String sttr);
//C++调用java 方法
public void nativeCallJavaBack(String sttr) {
Log.i(TAG,"native to java: " + sttr);
}
}
2、C++ 文件 testnative.cpp
#include "include/testnative.h"
#include<android/log.h>
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cassert>
#define TAG "test_native"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
static JavaVM* g_JavaVM = NULL;
static jobject g_InterfaceObject = 0;
static const char *g_JavaClassName = "com/example/testjni/CallJni";
//native 获取 java 类实例
static jobject getInstance(JNIEnv *env, jclass obj_class) {
jmethodID c_id = env->GetMethodID(obj_class, "<init>", "()V");
jobject obj = env->NewObject(obj_class, c_id);
return obj;
}
//native 回调 java 的方法
void nativeCallJava() {
JNIEnv *env = NULL;
int status;
status = g_JavaVM->GetEnv((void**) &env, JNI_VERSION_1_6);
jclass cls = env->FindClass(g_JavaClassName);
if (cls != 0) {
jobject obj = getInstance(env, cls);
jmethodID mid = env->GetMethodID(cls, "nativeCallJavaBack", "(Ljava/lang/String;)V");
env->CallVoidMethod(obj, mid, env->NewStringUTF("hello java"));
LOGD("nativeCallJava");
}
}
static jint testAddNum_JavaToNative(JNIEnv* envd, jobject obj, jint numa, jint numb) {
jint summ = 0;
summ = numa + numb;
LOGD("summ is %d",summ);
nativeCallJava(); //native 回调java 方法
return summ;
}
void testStringJavaToNative(JNIEnv* envd, jobject obj, jstring sttr) {
const char *c_str = NULL;
c_str = envd->GetStringUTFChars(sttr, NULL);
LOGD("c_str: %s",c_str);
}
//动态注册jni方法
static JNINativeMethod getMethods[] = {
{"testAddNumJavaToNative","(II)I",(void*)testAddNum_JavaToNative},
{"testStringJavaToNative","(Ljava/lang/String;)V",(void*)testStringJavaToNative}
};
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* getMethods,int methodsNum){
jclass clazz;
clazz = env->FindClass(className);
if(clazz == NULL){
return JNI_FALSE;
}
if(env->RegisterNatives(clazz,getMethods,methodsNum) < 0){
return JNI_FALSE;
}
return JNI_TRUE;
}
//注册jni类和函数
static int registerNatives(JNIEnv* env){
const char* className = "com/example/testjni/CallJni";
return registerNativeMethods(env,className,getMethods, sizeof(getMethods)/ sizeof(getMethods[0]));
}
//jni 默认函数
static void GetInterfaceObject(JNIEnv *env, const char *path, jobject *objptr) {
jclass cls = env->FindClass(path);
if (!cls) {
return;
}
jmethodID constr = env->GetMethodID(cls, "<init>", "()V");
if (!constr) {
return;
}
jobject obj = env->NewObject(cls, constr);
if (!obj) {
return;
}
(*objptr) = env->NewGlobalRef(obj);
}
//jni 默认 加载入口函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
g_JavaVM = vm;
JNIEnv* env = NULL;
if(vm->GetEnv((void**)&env,JNI_VERSION_1_6)!= JNI_OK){
return -1;
}
assert(env != NULL);
if(!registerNatives(env)){
return -1;
}
GetInterfaceObject(env, g_JavaClassName, &g_InterfaceObject);
return JNI_VERSION_1_6;
}
3、C++ 头文件,testnative.h
#ifndef TESTJNIANDCALLBACK_TESTNATIVE_H
#define TESTJNIANDCALLBACK_TESTNATIVE_H
#ifdef __cplusplus
extern "C" {
#endif
void nativeCallJava();
int testAddNumJavaToNative(int numa, int numb);
#ifdef __cplusplus
}
#endif
#endif
4、CMakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.
project("TestJniLib")
include_directories(src/main/jni/include)
# 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.
add_library( # Sets the name of the library.
TestJniLib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
testnative.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
TestJniLib
# Links the target library to the log library
# included in the NDK.
${log-lib} )
5、proguard-rules.pro 添加防混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#2.不混淆类
-keep class com.example.testjni.CallJni { *; }
6、build.gradle(app)添加cmake 编译 路径
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.example.testjni"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
//添加
externalNativeBuild {
cmake {
path "src/main/jni/CMakeLists.txt"
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
7、ManiActivity.java 引用jni函数
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testAddNumJavaToNative(1,2);
testStringJavaToNative("hello native");
}
}
8、结果
编译的so 库
从 log 看 java --> jni —> java