Android NDK开发笔记

1,508 阅读9分钟

日志打印优化

#include <jni.h>
#include <string>
#include <android/log.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
		LOGD("DEBUG");
		LOGI("INFO");
		LOGE("ERROR");
    return env->NewStringUTF(hello.c_str());
}

多线程开发

创建线程

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);

void* test(void* arg){
    for (int i = 0; i < 10; ++i) {
        LOGD("i=%d", i);
    }
    pthread_exit(0);

}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    pthread_t thread;
    pthread_create(&thread, NULL, test, NULL);
    pthread_join(thread, nullptr);
    return env->NewStringUTF(hello.c_str());
}

线程传参(int)

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);

void* test(void* arg){
    for (int i = 0; i < *(int*)arg; ++i) {
        LOGD("%d i=%d", *(int*)arg, i);
    }
    pthread_exit(0);

}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    pthread_t thread;
    int num = 11;
    pthread_create(&thread, NULL, test, &num);
    pthread_join(thread, nullptr);
    return env->NewStringUTF(hello.c_str());
}

线程传参(C结构体struct写法)

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);

struct node{
    int num;
    std::string str;
};
void* test(void* arg){
    struct node* p = (struct node*)arg;
    for (int i = 0; i < p->num; ++i) {
        LOGD("%d i=%d", p->num, i);
    }
    LOGD("%s", (p->str).c_str())
    pthread_exit(0);

}
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    pthread_t thread;
    int num = 11;
    struct node abc;
    abc.num = 18;
    abc.str = "xty";
    pthread_create(&thread, NULL, test, &abc);
    pthread_join(thread, nullptr);
    return env->NewStringUTF(hello.c_str());
}

线程传参(C++结构体struct写法)

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);

typedef struct {
    int num;
    std::string str;
} node;

void* test(void* arg) {
    node *p = (node *) arg;
    for (int i = 0; i < p->num; ++i) {
        LOGD("%d i=%d", p->num, i);
    }
    LOGD("%s", (p->str).c_str())
    pthread_exit(0);

}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    pthread_t thread;
    int num = 11;
    node abc;
    abc.num = 18;
    abc.str = "xty";
    pthread_create(&thread, NULL, test, &abc);
    pthread_join(thread, nullptr);
    return env->NewStringUTF(hello.c_str());
}

NDK开发(JavaVM与JNIEnv)

  1. 获取JavaVM的几种方式 JNI_OnLoad JNI_OnUnload env->GetJavaVM

  2. 获取JNIEnv的几种方式 函数静态注册传参 vm->GetEnv globalVM->AttachCurrentThread

    JNI_OnLoad 必须返回JNI版本 JNI_VERSION_1_6 对比各种方式获取的JavaVM与JNIEnv指针是否一致

  3. 进程中只有一个JavaVM,但可以有多个JNIEnv

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);
JavaVM *globalVM = nullptr;
typedef struct {
    int num;
    std::string str;
} node;

void *test(void *arg) {
    node *p = (node *) arg;
    for (int i = 0; i < p->num; ++i) {
        LOGD("%d i=%d", p->num, i);
    }
    LOGD("%s", (p->str).c_str())
    pthread_exit(0);

}

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";

    JavaVM* vm;
    env->GetJavaVM(&vm);
    LOGD("GetJavaVM %p", vm);
    LOGD("Java_com_example_cdemo_MainActivity_stringFromJNI JNIEnv %p", env);

    pthread_t thread;
    node abc;
    abc.num = 18;
    abc.str = "xty";
    pthread_create(&thread, NULL, test, &abc);
    pthread_join(thread, nullptr);
    return env->NewStringUTF(hello.c_str());
}
void *myThread(void *args) {

    JNIEnv *myThreadEnv = nullptr;
    if (globalVM->GetEnv((void **) &myThreadEnv, JNI_VERSION_1_6) == JNI_OK) {
        LOGD("globalVM->GetEnv success");
        LOGD("globalVM->GetEnv JNIEnv %p", myThreadEnv);
    } else {
        LOGD("globalVM->GetEnv failed");
    }
    if (globalVM->AttachCurrentThread(&myThreadEnv, nullptr) == JNI_OK){
        LOGD("globalVM->AttachCurrentThread success");
        LOGD("globalVM->AttachCurrentThread JNIEnv %p", myThreadEnv);
    }else {
        LOGD("globalVM->AttachCurrentThread failed");
    }

    globalVM->DetachCurrentThread();
    pthread_exit(0);
}

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    globalVM = vm;
    LOGD("JNI_OnLoad JavaVM %p", vm);

    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGD("GetEnv failed");
        return -1;
    }
    LOGD("JNI_OnLoad JNIEnv %p", env);

    pthread_t thread;
    pthread_create(&thread, nullptr, myThread, nullptr);
    pthread_join(thread, nullptr);
    LOGD("线程结束");
    return JNI_VERSION_1_6;
}

异常处理

#include <jni.h>
#include <string>
#include <android/log.h>
#include <pthread.h>


#define TAG "XTY_NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);
JavaVM *globalVM = nullptr;


extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}


void *myThread(void *args) {

    JNIEnv *myThreadEnv = nullptr;
    if (globalVM->GetEnv((void **) &myThreadEnv, JNI_VERSION_1_6) == JNI_OK) {
        LOGD("globalVM->GetEnv success");
        LOGD("globalVM->GetEnv JNIEnv %p", myThreadEnv);
    } else {
        LOGD("globalVM->GetEnv failed");
    }
    if (globalVM->AttachCurrentThread(&myThreadEnv, nullptr) == JNI_OK){
        LOGD("globalVM->AttachCurrentThread success");
        LOGD("globalVM->AttachCurrentThread JNIEnv %p", myThreadEnv);
    }else {
        LOGD("globalVM->AttachCurrentThread failed");
    }

    jclass TestJclass = nullptr;
    TestJclass = myThreadEnv->FindClass("com/xty/Cdemo/ReflectDemo");
    myThreadEnv->ExceptionDescribe();
    myThreadEnv->ExceptionClear();
    if (TestJclass == nullptr) {
        LOGD("myThreadEnv->FindClass failed");
    };

    globalVM->DetachCurrentThread();
    pthread_exit(0);
}

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    globalVM = vm;

    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGD("GetEnv failed");
        return -1;
    }

    pthread_t thread;
    pthread_create(&thread, nullptr, myThread, nullptr);
    pthread_join(thread, nullptr);
    LOGD("线程结束");
    return JNI_VERSION_1_6;

}

C与C++的区别

C

源码
#include <jni.h>

JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject obj /* this */) {
    char* hello = "Hello from C++";
    return (*env)->NewStringUTF(env, hello);
}

伪代码
__int64 __fastcall Java_com_xiaojianbang_demo2_MainActivity_stringFromJNI(_JNIEnv *a1)
{
  return ((__int64 (__fastcall *)(_JNIEnv *, const char *))a1->functions->NewStringUTF)(a1, "Hello from C++");
}

C++

源码
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_cdemo_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

伪代码
int __fastcall Java_com_xiaojianbang_demo_MainActivity_stringFromJNI(_JNIEnv *a1)
{
  _JNIEnv *v1; // ST24_4
  const char *v2; // r0
  int result; // r0
  int v4; // [sp+0h] [bp-40h]
  char v5; // [sp+28h] [bp-18h]
  int v6; // [sp+34h] [bp-Ch]

  v1 = a1;
  sub_8E60();
  v2 = (const char *)sub_8EC2((int)&v5);
  v4 = _JNIEnv::NewStringUTF(v1, v2);
  std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v5);
  result = _stack_chk_guard;
  if ( _stack_chk_guard == v6 )
    result = v4;
  return result;
}

JNI函数动态注册

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){
    return env->NewStringUTF("this string from cpp");
}

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
    globalVM = vm;

    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGD("GetEnv failed");
        return -1;
    }

    auto clazz = env->FindClass("com/example/demo/MainActivity");
    JNINativeMethod methods[] = {
            //public native String encode(int i, String str, byte[] byt);
            {"encode", "(ILjava/lang/String;[B)Ljava/lang/String;", (void *)encodeFromC}
    };
    env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(JNINativeMethod));

    return JNI_VERSION_1_6;
}

JNI中创建对象

Java代码示例

package com.example.demo;

import android.util.Log;

public class ExampleClass {
    public static String publicStaticStringField = "this is publicStaticStringField";
    public String publicStringField = "this is publicStringField";

    private static String privateStaticStringField = "this is privateStaticStringField";
    private String privateStringField = "this is privateStringField";

    public ExampleClass(){
        Log.d("example", "this is ExampleClass()");
    }

    public ExampleClass(String str){
        Log.d("example", "this is ExampleClass(String str)");
    }

    public ExampleClass(String str, int i){
        Log.d("example", i + " " + str);
        Log.d("example", "this is ExampleClass(String str, int i)");
    }

    public static void publicStaticFunc(){
        Log.d("example", "this is publicStaticFunc");
    }

    public void publicFunc(){
        Log.d("example", "this is publicFunc");
    }

    private static void privateStaticFunc(){
        Log.d("example", "this is privateStaticFunc");
    }

    private void privateFunc(){
        Log.d("example", "this is privateFunc");
    }

}

方法一:

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){
    //NewObject创建对象
    auto clazz = env->FindClass("com/example/demo/ExampleClass");
    auto methodID = env->GetMethodID(clazz, "<init>", "()V");
    auto ExampleClassObj = env->NewObject(clazz, methodID);
    LOGD("ExampleClassObj %p", ExampleClassObj);

    return env->NewStringUTF("this string from cpp");
}

方法二:

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){
    //AllocObject创建对象
    auto clazz = env->FindClass("com/example/demo/ExampleClass");
    auto methodID = env->GetMethodID(clazz, "<init>", "()V");
    auto ExampleClassObj = env->AllocObject(clazz);
    env->CallNonvirtualVoidMethod(ExampleClassObj, clazz, methodID);
    
    return env->NewStringUTF("this string from cpp");
}

JNI中访问Java属性

访问静态属性

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){

    auto clazz = env->FindClass("com/example/demo/ExampleClass");
    //获取静态字段
    auto privateStaticStringField = env->GetStaticFieldID(clazz, "privateStaticStringField", "Ljava/lang/String;");
    jstring privateStaticString = static_cast<jstring>(env->GetStaticObjectField(clazz,
                                                                                 privateStaticStringField));
    const char* privatecstr = env->GetStringUTFChars(privateStaticString, nullptr);
    LOGD("privateStaticString: %s", privatecstr);

    return env->NewStringUTF("this string from cpp");
}

访问非静态属性

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){

    auto clazz = env->FindClass("com/example/demo/ExampleClass");
		auto ExampleClassObj = env->AllocObject(clazz);
    //获取对象字段
    auto publicStringField = env->GetFieldID(clazz, "publicStringField", "Ljava/lang/String;");
    jstring publicString = static_cast<jstring>(env->GetObjectField(ExampleClassObj,
                                                                    publicStringField));
    const char* publiccstr = env->GetStringUTFChars(publicString, nullptr);
    LOGD("publicStringField: %s", publiccstr);

    return env->NewStringUTF("this string from cpp");
}

JNI中访问Java数组

jstring encodeFromC(JNIEnv* env, jobject obj, jint a, jstring b, jbyteArray jbt){
    //NewObject创建对象
    auto clazz = env->FindClass("com/example/demo/ExampleClass");
    auto methodID = env->GetMethodID(clazz, "<init>", "()V");
    auto ExampleClassObj = env->NewObject(clazz, methodID);
    LOGD("ExampleClassObj %p", ExampleClassObj);

    //获取数组字段ID
    auto byteArrayID = env->GetFieldID(clazz, "byteArray", "[B");
    jbyteArray byteArray = static_cast<jbyteArray>(env->GetObjectField(ExampleClassObj,
                                                                       byteArrayID));
    int _byteArrayLength = env->GetArrayLength(byteArray);

    //修改数组字段
    char javaByte[10];
    for(int i = 0; i < 10; i++){
        javaByte[i] = static_cast<char>(100 - i);
    }
    const jbyte *java_array = reinterpret_cast<const jbyte *>(javaByte);
    env->SetByteArrayRegion(byteArray, 0, _byteArrayLength, java_array);

    //获取数组字段
    byteArray = static_cast<jbyteArray>(env->GetObjectField(ExampleClassObj,
                                                                       byteArrayID));
    _byteArrayLength = env->GetArrayLength(byteArray);
    char* str = reinterpret_cast<char *>(env->GetByteArrayElements(byteArray, nullptr));
    for(int i = 0; i< _byteArrayLength; i++){
        LOGD("str[%d]=%d", i, str[i]);
    }

    return env->NewStringUTF("this string from cpp");
}

JNI中访问Java函数

调用静态函数

//public native String encodeB(int i, String str, byte[] byt);
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_demo_MainActivity_encodeB(
        JNIEnv* env,
        jobject /* this */,
        jint a, jstring b, jbyteArray c) {
    //1、调用静态函数
    jclass ExampleClassClazz = env->FindClass("com/example/demo/ExampleClass");
    jmethodID publicStaticFuncID = env->GetStaticMethodID(ExampleClassClazz, "publicStaticFunc", "()V");
    env->CallStaticVoidMethod(ExampleClassClazz, publicStaticFuncID);

    return env->NewStringUTF("");
}

调用对象函数(CallObjectMethod)

//public native String encodeB(int i, String str, byte[] byt);
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_demo_MainActivity_encodeB(
        JNIEnv* env,
        jobject /* this */,
        jint a, jstring b, jbyteArray c) {
    //2、调用对象函数
    jclass ExampleClassClazz = env->FindClass("com/example/demo/ExampleClass");

    jmethodID privateFuncID = env->GetMethodID(ExampleClassClazz, "privateFunc",
                                               "(Ljava/lang/String;I)Ljava/lang/String;");
    jmethodID ExampleClassInit = env->GetMethodID(ExampleClassClazz, "<init>", "(Ljava/lang/String;)V");
    jstring str1 = env->NewStringUTF("this is from NDK");
    jobject ExampleClassObj = env->NewObject(ExampleClassClazz, ExampleClassInit, str1);

    jstring str2 = env->NewStringUTF("this is from JNI");
    jstring retval = static_cast<jstring>(env->CallObjectMethod(ExampleClassObj, privateFuncID, str2, 1000));

    const char* cpp_retval = env->GetStringUTFChars(retval, nullptr);
    LOGD("cpp_retval: %s", cpp_retval);
    env->ReleaseStringUTFChars(retval, cpp_retval);

    return env->NewStringUTF("");
}

调用对象函数(CallObjectMethodA)

//public native String encodeB(int i, String str, byte[] byt);
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_demo_MainActivity_encodeB(
        JNIEnv* env,
        jobject /* this */,
        jint a, jstring b, jbyteArray c) {
    jclass ExampleClassClazz = env->FindClass("com/example/demo/ExampleClass");

    jmethodID privateFuncID = env->GetMethodID(ExampleClassClazz, "privateFunc",
                                               "(Ljava/lang/String;I)Ljava/lang/String;");
    jmethodID ExampleClassInit = env->GetMethodID(ExampleClassClazz, "<init>", "(Ljava/lang/String;)V");
    jstring str1 = env->NewStringUTF("this is from NDK");
    jobject ExampleClassObj = env->NewObject(ExampleClassClazz, ExampleClassInit, str1);

    jstring str2 = env->NewStringUTF("this is from JNI");

    jvalue args[2];
    args[0].l = str2;
    args[1].i = 1000;
    jstring retval = static_cast<jstring>(env->CallObjectMethodA(ExampleClassObj, privateFuncID,
                                                                 args));
    const char* cpp_retval = env->GetStringUTFChars(retval, nullptr);
    LOGD("cpp_retval: %s", cpp_retval);
    env->ReleaseStringUTFChars(retval, cpp_retval);

    return env->NewStringUTF("");
}

参数是数组返回值是数组

//public native String encodeB(int i, String str, byte[] byt);
extern "C" JNIEXPORT jstring JNICALL
Java_com_xiaojianbang_demo_MainActivity_encodeB(
        JNIEnv* env,
        jobject /* this */,
        jint a, jstring b, jbyteArray c) {
    jclass ExampleClassClazz = env->FindClass("com/example/demo/ExampleClass");

    //  参数是数组 返回值是数组
    //private static int[] privateStaticFunc(String[] str)

    jclass StringClazz = env->FindClass("java/lang/String");
    jobjectArray StringArr = env->NewObjectArray(3, StringClazz, nullptr);
    for(int i = 0; i < 3; i++){
        jstring str3 = env->NewStringUTF("NDK");
        env->SetObjectArrayElement(StringArr, i, str3);
    }
    jmethodID privateStaticFuncID = env->GetStaticMethodID(ExampleClassClazz, "privateStaticFunc", "([Ljava/lang/String;)[I");
    jintArray intArr = static_cast<jintArray>(env->CallStaticObjectMethod(ReflectDemoClazz,
                                                                          privateStaticFuncID,
                                                                          StringArr));
    int *cintArr = env->GetIntArrayElements(intArr, nullptr);
    LOGD("cintArr[0]=%d", cintArr[0]);
    //3、调用父类函数
    return env->NewStringUTF("");

}

JNI中访问父类方法

extern "C" JNIEXPORT void JNICALL
Java_com_xiaojianbang_demo_MainActivity_onCreate(JNIEnv *env, jobject thiz,
                                                 jobject saved_instance_state) {
    //调用父类函数
    jclass AppCompatActivityClazz = env->FindClass("androidx/appcompat/app/AppCompatActivity");
    jmethodID onCreateID = env->GetMethodID(AppCompatActivityClazz, "onCreate", "(Landroid/os/Bundle;)V");
    env->CallNonvirtualVoidMethod(thiz, AppCompatActivityClazz, onCreateID, saved_instance_state);
}

onCreateNative化

Java源码

package com.example.demo;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity implements OnClickListener {

    // Used to load the 'native-lib' library on application startup.
    String nativePathA = null;
    String nativePathB = null;

    static {
        System.loadLibrary("exampleA");
        System.loadLibrary("exampleB");

    }

    @Override
    protected native void onCreate(Bundle savedInstanceState);

//    protected void onCreate(Bundle savedInstanceState) {
//        super.onCreate(savedInstanceState);
//
//        setContentView(R.layout.activity_main);
//        TextView tv = findViewById(R.id.sample_text);
//
//        nativePathA = new Utils().getPath(getApplicationContext()) + "/libexampleA.so";
//        nativePathB = new Utils().getPath(getApplicationContext()) + "/libexampleB.so";
//        getApplicationContext();
//        tv.setText(stringFromJNIA(nativePathB));
//        stringFromJNIB(nativePathA);
//
//        Log.d("example", encode(100, "example", new byte[]{49,50,51,52,53,54,55,56,57,58,59}));
//        Log.d("example", encodeB(100, "example", new byte[]{49,50,51,52,53,54,55,56,57,58,59}));
//
//        findViewById(R.id.button).setOnClickListener(this);
//    }

    public void onClick(View v) {
        stringFromJNIA(nativePathB);
    }
    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNIA(String str);
    public native String stringFromJNIB(String str);
    public native String encode(int i, String str, byte[] byt);
    public native String encodeB(int i, String str, byte[] byt);

}

JavaToC

extern "C" JNIEXPORT void JNICALL
Java_com_xiaojianbang_demo_MainActivity_onCreate(JNIEnv *env, jobject thiz,
                                                 jobject saved_instance_state) {
    //super.onCreate(savedInstanceState);
    jclass AppCompatActivityClazz = env->FindClass("androidx/appcompat/app/AppCompatActivity");
    jmethodID onCreateID = env->GetMethodID(AppCompatActivityClazz, "onCreate", "(Landroid/os/Bundle;)V");
    env->CallNonvirtualVoidMethod(thiz, AppCompatActivityClazz, onCreateID, saved_instance_state);

    //R.layout.activity_main
    jclass R$layoutClazz = env->FindClass("com/example/demo/R$layout");
    jfieldID activity_mainID = env->GetStaticFieldID(R$layoutClazz, "activity_main", "I");
    int activity_mainValue = env->GetStaticIntField(R$layoutClazz, activity_mainID);
    LOGD("activity_mainValue=%d", activity_mainValue);

    //setContentView(R.layout.activity_main);
    jmethodID setContentViewID = env->GetMethodID(AppCompatActivityClazz, "setContentView", "(I)V");
    env->CallVoidMethod(thiz, setContentViewID, activity_mainValue);

    //R.id.sample_text
    jclass R$idClazz = env->FindClass("com/example/demo/R$id");
    jfieldID sample_textID = env->GetStaticFieldID(R$idClazz, "sample_text", "I");
    int sample_textValue = env->GetStaticIntField(R$idClazz, sample_textID);
    LOGD("sample_textValue=%d", sample_textValue);

    //TextView tv = findViewById(R.id.sample_text);
    jmethodID findViewByIdID = env->GetMethodID(AppCompatActivityClazz, "findViewById", "(I)Landroid/view/View;");
    jobject TextViewObj = env->CallObjectMethod(thiz, findViewByIdID, sample_textValue);

    //nativePathA = new Utils().getPath(getApplicationContext()) + "/libexampleA.so";
    //nativePathB = new Utils().getPath(getApplicationContext()) + "/libexampleB.so";
    jclass UtilsClazz = env->FindClass("com/example/demo/Utils");
    jmethodID getPathID = env->GetMethodID(UtilsClazz, "getPath", "(Landroid/content/Context;)Ljava/lang/String;");
    jmethodID UtilsInitID = env->GetMethodID(UtilsClazz, "<init>", "()V");
    jobject UtilsObj = env->NewObject(UtilsClazz, UtilsInitID);

    jclass ContextWrapperClazz = env->FindClass("android/content/ContextWrapper");
    jmethodID getApplicationContextID = env->GetMethodID(ContextWrapperClazz, "getApplicationContext", "()Landroid/content/Context;");
    jobject ContextObj = env->CallObjectMethod(thiz, getApplicationContextID);

    jstring nativePath = static_cast<jstring>(env->CallObjectMethod(UtilsObj, getPathID, ContextObj));
    std::string nativePathCStr = env->GetStringUTFChars(nativePath, nullptr);
    std::string nativePathACStrA = nativePathCStr + "/libexampleA.so";
    std::string nativePathACStrB = nativePathCStr + "/libexampleB.so";
    LOGD("ndk nativePathA=%s", nativePathACStrA.c_str());
    LOGD("ndk nativePathB=%s", nativePathACStrB.c_str());
    jclass MainActivityClazz = env->GetObjectClass(thiz);
    jfieldID nativePathBID = env->GetFieldID(MainActivityClazz, "nativePathB", "Ljava/lang/String;");
    env->SetObjectField(thiz, nativePathBID, env->NewStringUTF(nativePathACStrB.c_str()));

    //stringFromJNIA(nativePathB)
    jmethodID stringFromJNIAID = env->GetMethodID(MainActivityClazz, "stringFromJNIA", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring stringFromJNIARetval = static_cast<jstring>(env->CallObjectMethod(thiz,
                                                                              stringFromJNIAID,
                                                                              env->NewStringUTF(
                                                                                      nativePathACStrB.c_str())));
    //tv.setText(stringFromJNIA(nativePathB));
    jclass TextViewClazz = env->GetObjectClass(TextViewObj);
    jmethodID setTextID = env->GetMethodID(TextViewClazz, "setText", "(Ljava/lang/CharSequence;)V");
    env->CallVoidMethod(TextViewObj, setTextID, stringFromJNIARetval);

    //stringFromJNIB(nativePathA)
    jmethodID stringFromJNIBID = env->GetMethodID(MainActivityClazz, "stringFromJNIB", "(Ljava/lang/String;)Ljava/lang/String;");
    env->CallObjectMethod(thiz, stringFromJNIBID, env->NewStringUTF(nativePathACStrA.c_str()));
}

JNI内存管理

JNI内存管理及优化