Cocos2d-x 之使用 Jni

Jni 技术

Android 里面有个 jni.h 封装了 java 代码与原生代码交互的功能,cocos2dx 在cocos/platform/android/jni下面有个jniHelper 类是对 jni 的再次封装,使用 jniHelper 能很容易地实现 c++ 代码与 java 互调。

C++ 调 Java

  • Android 端没什么特别要做的,只需要把函数定义好就行,函数分静态和实例两种。
  • Cocos 端要注意的东西就比较多,
    首先要引入相关的库,这里需要 jni.h 和 jniHelper.h 两个库,但其实 jniHelper.h 里面已经包含 jni.h 了,所以只需要包含 jniHelper.h 就行。jniHelper.h 位于
#if (CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID)
#include <platform/android/jni/JniHelper.h>
#endif

然后就是调 android 方法了,同样要加上平台判断预处理。

  • 声明jni方法结构体
JniMethodInfo jm;
  • 查找方法是否存在
静态方法 bool b=JniHelper::getStaticMethodInfo(jm,"完整类名“,”方法名“,”(函数参数)返回值“);
实例方法 bool b=JniHelper::getStaticMethodInfo(jm,"完整类名”,“方法名”,“(函数参数)返回值”);

完整类名是指包含完整的包名,比如 org/cocos2dx/cpp/AppActivity。
函数参数及返回值指的是类型,要写 jni 里面的类型,关于 c++ 数据类型与 jni 的对应关系,请自行上网查。

  • 调用方法
    根据返回值不同调用不同的函数
  • 返回整型静态方法
jint jRes = jm.env->CallStaticIntMethod(jm.classID, jm.methodID, 函数参数);
  • 无返回值实例方法
jm.env->CallVoidMethod(类实例, jm.methodID);
  • 类实例通过调用静态方法来获得
jobject jIns = jm.env->CallStaticObjectMethod(jm.classID, jm.methodID);

Java 调 C++

  • Android 声明原生函数,只声明不用实现,实现放在 C++ 端。
public [static] native 返回值 方法名(参数);
  • Cocos 端实现原生函数
    不仅参数和返回值要和 Android 端定义的一样,函数名也有要求,函数名格式 Java_包1_包2_类名_原生函数名。比如类 Foo 有个原生函数叫 test,所在包是 org/cocos2dx/cpp,则 cocos 端实现的函数叫 Java_org_cocos2dx_cpp_Foo_test

  • Android端直接调该函数。

静态方法

// Java端
public class AppActivity extends Cocos2dxActivity {
    /**
     * c++调java函数
     * 静态方法
     */
    public static int nativeCallJava(String name, String filter) {
        String fullName=name+"."+filter;
        javaCallNative(fullName);
        return 110;
    }

    /**
     * java调c++原生函数
     * 静态方法
     */
    public static native void javaCallNative(String packageName);

}
// C++端
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
    //声明jni结构体
    JniMethodInfo jm;

    //查找java静态方法
    bool b = JniHelper::getStaticMethodInfo(jm, "org/cocos2dx/cpp/AppActivity", "nativeCallJava", "(Ljava/lang/String;Ljava/lang/String;)I");

    if (b)
    {
        //定义java字符串变量
        jstring jTitle = jm.env->NewStringUTF("sound/bg");
        jstring jText = jm.env->NewStringUTF("mp3");

        //调用java静态方法
        jint jRes = jm.env->CallStaticIntMethod(jm.classID, jm.methodID, jTitle, jText);

        //资源回收
        jm.env->DeleteLocalRef(jTitle);
        jm.env->DeleteLocalRef(jText);

        //取得java方法返回值
        char name[16];
        sprintf(name, "return code:%d", jRes);

        this->addChild(m_tip_text);
        m_tip_text->setVisible(true);
        m_tip_text->setString(name);
    }
#endif

#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
extern "C"
{
    /**
    * java调原生函数
    */
    void Java_org_cocos2dx_cpp_AppActivity_javaCallNative(JNIEnv* env, jobject thiz, jstring name)
    {
        JniMethodInfo jm;

        const char* cName = jm.env->GetStringUTFChars(name, NULL);

        SimpleAudioEngine::getInstance()->playBackgroundMusic(cName);
        SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(100);

        env->ReleaseStringUTFChars(name, cName);
    }
}
#endif

实例方法

//Java端
package org.cocos2dx.cpp;
public class Foo
{
    /**
     * c++调java函数
     * 静态方法
     * 获取类实例
     */
    private static Foo _ins;
    public static Object getInstance() {
        if (_ins == null)
        {
            _ins = new Foo();
        }
        return _ins;
    }

    /**
     * c++调java函数
     * 非静态方法
     */
    public int nativeCallJava() {
        javaCallNative();
        return 111;
    }

    /**
     * java调c++原生函数
     * 非静态方法
     */
    public native void javaCallNative();
}
//C++端
#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
    //声明jni结构体
    JniMethodInfo jm;

    //声明java类实例
    jobject jIns;

    //先调用静态方法获得类实例
    if (JniHelper::getStaticMethodInfo(jm, "org/cocos2dx/cpp/Foo", "getInstance", "()Ljava/lang/Object;"))
    {
        jIns = jm.env->CallStaticObjectMethod(jm.classID, jm.methodID);
        if (!jIns)
        {
            m_tip_text->setString("ins is null");
            return;
        }
    }

    //查找非静态方法
    bool b = JniHelper::getMethodInfo(jm, "org/cocos2dx/cpp/Foo", "nativeCallJava", "()I");

    if (b)
    {
        //调用java非静态方法
        jint jRes = jm.env->CallIntMethod(jIns, jm.methodID);
        jm.env->CallVoidMethod(jIns, jm.methodID);
        //取得java方法返回值
        char name[16];
        sprintf(name, "return code:%d", jRes);

        m_tip_text->setString(name);
    }
#endif

#if CC_TARGET_PLATFORM==CC_PLATFORM_ANDROID
extern "C"
{
    /**
    * java调原生函数
    */
    void Java_org_cocos2dx_cpp_Foo_javaCallNative(JNIEnv* env, jobject thiz)
    {
        SimpleAudioEngine::getInstance()->stopBackgroundMusic();
    }
}
#endif
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值