文章目录

  • 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、结果



Cmake 编译jni 以及C++调用java_#define

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 添加防混淆

Cmake 编译jni 以及C++调用java_#define_02

-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 库

Cmake 编译jni 以及C++调用java_android_03

从 log 看 java --> jni —> java

Cmake 编译jni 以及C++调用java_#define_04