欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

android java 与 c++ 相互调用的方法

程序员文章站 2022-06-12 19:42:38
...

android java 与 c++ 相互调用的方法

最近在写native部分的代码,需要c++和java相互调用。记得JK之前说过他弄了一个新的方法,在写jni的时候会*一点,我对了一下他的代码,根据我的场景写了一个出来。在这里给自己做一点笔记吧。

Android.mk

LOCAL_MODULE := SDKBridge_shared
LOCAL_MODULE_FILENAME := libSDKBridge
LOCAL_SRC_FILES := $(LOCAL_PATH)/hellocpp/sdk_bridge.cpp
LOCAL_CPPFLAGS += -fexceptions  # enable try...catch
LOCAL_LDLIBS := -llog           # enable android logcat
include $(BUILD_SHARED_LIBRARY)

如果要引用自己的so库的时候

LOCAL_SHARED_LIBRARIES := SDKBridge_shared

java层中这样引用这个库

package org.cocos2dx.cpp;

public class SDKBridge {
    static {
        System.loadLibrary("SDKBridge");
    }
    public static void quit() {
        Log.d(TAG, "Java quit");
        AppActivity ac = AppActivity.getActivity();
        if (ac != null) ac.quit();
    }

    public static native void _init();

    public static native void _onQuit();
}

重点就是在 cpp 中的 JNI_OnLoad 的方法,这样设计

sdk_bridge.cpp

#include <android/log.h>
#include <stdio.h>
#include <jni.h>
#include <cstdlib>
#include "sdk_bridge.h"
#include "stddef.h"

#define LOG_TAG "SDKBridge"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG,  __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

#define JAVA_SDK_CLASS_PATH        "org/cocos2dx/cpp/SDKBridge"

namespace sdk {
    JavaVM *_vm = NULL;
    jclass _sdk_bridge_cls = NULL;
    jmethodID _sdk_quit = NULL;

    void check_jni_ready(JNIEnv *env) {
        if (NULL == env || NULL == _sdk_bridge_cls
            || NULL == _sdk_login || NULL == _sdk_logout
            || NULL == _sdk_pay || NULL == _sdk_quit) {
            LOGE("jni is not ready! init error!");
            abort();
        }
    }

    JNIEnv *getEnv() {
        if (NULL == _vm) {
            LOGE("jni is not ready! Please call _init first!");
            abort();
        }
        JNIEnv *env;
        _vm->AttachCurrentThread(&env, nullptr);
        return env;
    }

    void java_quit(JNIEnv *env) {
        check_jni_ready(env);
        env->CallStaticVoidMethod(_sdk_bridge_cls, _sdk_quit);
    }

    void native_init(JNIEnv *env) {
        LOGI("init");
    }

    void native_on_quit() {
        LOGE("TODO:native on quit");
        if (NULL != sCallbackFunction) {
            sCallbackFunction("onQuit","");
        }
    }
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *unused) {
    JNIEnv *env = NULL;
    jclass sdk_bridge_cls;

    static JNINativeMethod methods[] = {
            {"_init",     "()V",                   (void *) sdk::native_init},
            {"_onQuit",   "()V",                   (void *) sdk::native_on_quit}
    };

    if ((*vm).GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGE("get env error, abort!");
        abort();
    }
    sdk_bridge_cls = env->FindClass(JAVA_SDK_CLASS_PATH);
    if (!sdk_bridge_cls) {
        LOGE("native registration unable to find class '%s'!", JAVA_SDK_CLASS_PATH);
        abort();
    }
    if (env->RegisterNatives(sdk_bridge_cls, methods, sizeof(methods) / sizeof(methods[0])) <
        0) {
        LOGE("native registration failed!");
        abort();
    }

    sdk::_sdk_login = env->GetStaticMethodID(sdk_bridge_cls, "quit", "()V");
    if (!sdk::_sdk_login) {
        LOGE("can not get login method id!");
        abort();
    }

    sdk::_vm = vm;
    sdk::_sdk_bridge_cls = (jclass) env->NewGlobalRef(sdk_bridge_cls);
    (*env).DeleteLocalRef(sdk_bridge_cls);
    return JNI_VERSION_1_6;
}

sdk_bridge.h

#ifndef PROJ_ANDROID_SDK_BRIDGE_H
#define PROJ_ANDROID_SDK_BRIDGE_H

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

namespace sdk {
    typedef void (*OnJavaCallback)(std::string, std::string);

    OnJavaCallback sCallbackFunction = NULL;

    void register_print(OnJavaCallback callback) {
        sCallbackFunction = callback;
    }

    JNIEnv *getEnv();

    void java_quit(JNIEnv *env);

}
#endif //PROJ_ANDROID_SDK_BRIDGE_H

一个注意点就是 JNIEnv 不能做缓存,能缓存的只有 JavaVM

相关标签: jni