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

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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页