在cocos2dx中通过Jni实现Java与C++的互相调用(二)

发表于2018-05-10
评论0 1.9k浏览
jni详解介绍

JNI是JVM实现中的一部分,因此Native语言和Java代码都运行在JVM的宿主环境。JNI的出现使得开发者既可以利用Java语言跨平台、类库丰 富、开发便捷等特点,又可以利用Native语言的高效。

JNI是一个双向的接口:开发者不仅可以通过JNI在Java代码中访问Native模块,还可以在 Native代码中嵌入一个JVM,并通过JNI访问运行于其中的Java模块。可见,JNI担任了一个桥梁的角色,它将JVM与Native模块联系起来,从而实现了Java代码与Native代码的互访。如下图:

缺点:由于Native模块的使用,Java代码会丧失其原有的跨平台性和类型安全等特性。但是这不是我们应该担心的,不是吗?哈哈。也就是说,JNI是帮助游戏在Java代码中调用Native接口和在Native代码中调用Java接口。

方法一、基本使用

c++接口,一般来说,要在Native代码中访问Java对象,有如下几个步骤:
  1. 得到该Java对象的类定义。JNI定义了jclass 这个类型来表示Java的类的定义,并提供了FindClass接口,根据类的完整的包路径即可得到其jclass 。
  2. 根据jclass 创建相应的对象实体,即jobject 。在Java中,创建一个新对象只需要使用new 关键字即可,但在Native代码中创建一个对象则需要两步:首先通过JNI接口GetMethodID得到该类的构造函数,然后利用NewObject接口构造出该类的一个实例对象。
  3. 访问jobject 中的成员变量或方法。访问对象的方法是先得到方法的Method ID,然后使用CallMethod 接口调用,这里Type对应相应方法的返回值——返回值为基本类型的都有相对应的接口,如CallIntMethod;其他的返回值(包括String) 则为CallObjectMethod。可以看出,创建对象实质上是调用对象的一个特殊方法,即构造函数。访问成员变量的步骤一样:首先 GetFieldID得到成员变量的ID,然后Get/SetField读/写变量值。

方法二、jnihelper

2dx里面为我们提供了一个JniHelper类,来满足与Java层的数据交互,JniHelper可以很方便的调用java层的动静态方法。

C++调用Java

JniUtil.h
#pragma  once  
#include <string>  
using namespace std;  
namespace JniUtil  
{  
    string callJava_getAppVersion();  
    bool callJava_copyText(string copyText);  
    string callJava_getTestAllString(bool b,int i,float f,double d,string s);  
    void callJava_callNativeFunShowText(bool b,int i,float f,double d,string s);  
}   

JniUtil.cpp
#include "JniUtil.h"  
#include "cocos2d.h"  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
#include <Jni.h>  
#include "platform/android/jni/JniHelper.h"  
#endif  
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
#include "IosHelper.h"  
#endif  
#define JAVA_CLASSNAME  "org/cocos2dx/cpp/AppActivity"  
using namespace cocos2d;  
namespace JniUtil  
{  
    string callJava_getAppVersion()  
    {  
        string str = "";  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
        JniMethodInfo minfo;   
        //在org.cocos2dx.cpp.AppActivity文件中查找static String getAppVersion();这静态方法是否存在。  
        bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "getAppVersion", "()Ljava/lang/String;");  
        if (isHave)    
        {    
            jstring jVersion = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);   
            //使用jstring2string函数将返回的jstring类型的值转化为c++中的string类型  
            //string text = JniHelper::jstring2string(jVersion);  
            const char* version = minfo.env->GetStringUTFChars(jVersion,0);  
            str = version;  
            minfo.env->ReleaseStringUTFChars(jVersion, version);  
            minfo.env->DeleteLocalRef(minfo.classID);    
            cocos2d::log("JniFun call callJava_getAppVersion over!===%s",str.c_str());  
        }    
        else  
        {  
            cocos2d::log("JniFun call callJava_getAppVersion error!");  
        }  
#endif  
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
        //IosHelper::HuiPay(kStr.c_str());  
#endif  
        return str;  
    }  
    bool callJava_copyText(string copyText)  
    {  
        bool isSuccess = false;  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
        JniMethodInfo minfo;    
        bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "copyText", "(Ljava/lang/String;)Z");  
        if (isHave)    
        {    
            jstring jCopyText = minfo.env->NewStringUTF(copyText.c_str());  
            jboolean jIsSuccess= minfo.env->CallStaticBooleanMethod(minfo.classID, minfo.methodID,jCopyText);   
            isSuccess = jIsSuccess;  
            minfo.env->DeleteLocalRef(minfo.classID);    
            cocos2d::log("JniFun call callJava_copyText over!");  
        }    
        else  
        {  
            cocos2d::log("JniFun call callJava_copyText error!");  
        }  
#endif  
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
        //IosHelper::HuiPay(kStr.c_str());  
#endif  
        return isSuccess;  
    }  
    string callJava_getTestAllString(bool b,int i,float f,double d,string s)  
    {  
        string str = "";  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
        JniMethodInfo minfo;    
        bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "getTestAllString", "(ZIFDLjava/lang/String;)Ljava/lang/String;");  
        if (isHave)    
        {    
            jstring js = minfo.env->NewStringUTF(s.c_str());  
            jstring jRes = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID,b,i,f,d,js);   
            const char* res = minfo.env->GetStringUTFChars(jRes,0);  
            str = res;  
            minfo.env->ReleaseStringUTFChars(jRes, res);  
            minfo.env->DeleteLocalRef(js);  
            minfo.env->DeleteLocalRef(minfo.classID);    
            cocos2d::log("JniFun call callJava_getTestAllString over!==%s",str.c_str());  
        }    
        else  
        {  
            cocos2d::log("JniFun call callJava_getTestAllString error!");  
        }  
#endif  
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
        //IosHelper::HuiPay(kStr.c_str());  
#endif  
        return str;  
    }  
    void callJava_callNativeFunShowText(bool b,int i,float f,double d,string s)  
    {  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
        JniMethodInfo minfo;    
        bool isHave = JniHelper::getStaticMethodInfo(minfo,JAVA_CLASSNAME, "callNativeFunShowText", "(ZIFDLjava/lang/String;)V");  
        if (isHave)    
        {    
            jstring js = minfo.env->NewStringUTF(s.c_str());  
            jstring jRes = (jstring)minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID,b,i,f,d,js);   
            const char* res = minfo.env->GetStringUTFChars(jRes,0);  
            string str = res;  
            minfo.env->ReleaseStringUTFChars(jRes, res);  
            minfo.env->DeleteLocalRef(js);  
            minfo.env->DeleteLocalRef(minfo.classID);    
            cocos2d::log("JniFun call callJava_callNativeFunShowText over!==%s",str.c_str());  
        }    
        else  
        {  
            cocos2d::log("JniFun call callJava_callNativeFunShowText error!");  
        }  
#endif  
#if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
        //IosHelper::HuiPay(kStr.c_str());  
#endif  
    }  
}  

Java调用C++

AppActivity.java
package org.cocos2dx.cpp;  
import org.cocos2dx.lib.Cocos2dxActivity;  
import org.cocos2dx.lib.Cocos2dxHelper;  
import android.content.ClipData;  
import android.content.ClipboardManager;  
import android.content.pm.PackageInfo;  
import android.os.Bundle;  
import android.util.AndroidException;  
import android.view.WindowManager;  
public class AppActivity extends Cocos2dxActivity   
//public class AppActivity extends Cocos2dxHelper   
{  
    //在java类中定义一个方法,用于提供给java调用C++  
    public static native void NativeFunShowText(String text);  
    private static AppActivity appActivity = null;  
    //剪切板管理工具类  
    private static ClipboardManager mClipboardManager;  
    //剪切板Data对象  
    private static ClipData mClipData;  
    @Override  
    protected void onCreate(Bundle savedInstanceState)   
    {  
        super.onCreate(savedInstanceState);  
        appActivity = this;  
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);  
        mClipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);  
    }  
    public static String getAppVersion() throws AndroidException  
    {  
        PackageInfo pInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);  
        String version = pInfo.versionName +" "+ pInfo.versionCode;  
        return version;  
    }  
    public static boolean copyText(String copyTxt)  
    {  
        //创建一个新的文本clip对象  
        mClipData = ClipData.newPlainText("Simple test", copyTxt);  
        //把clip对象放在剪贴板中  
        mClipboardManager.setPrimaryClip(mClipData);  
        return true;  
    }  
    public static String getTestAllString(boolean b,int i,float f,double d,String s)  
    {  
        final String str = "bool:"+ b + " int:" + i + " float:" + f + " double:" + d + " String:" + s;  
        System.out.println("----getTestAll----out runOnUiThread-----"+str);  
        //添加到主线程  
        appActivity.runOnUiThread(new Runnable(){  
            public void run(){  
                System.out.println("----getTestAll----in runOnUiThread-----"+str);                
            }  
        });  
        return str;  
    }  
    public static void callNativeFunShowText(boolean b,int i,float f,double d,String s)  
    {  
        final String str = "bool:"+ b + " int:" + i + " float:" + f + " double:" + d + " String:" + s;  
        System.out.println("----callNativeFunShowText----out runOnGLThread-----"+str);  
        //想从java代码来改变cocos2dxUI界面,需要在GL线程中运行,否则会崩溃  
        appActivity.runOnGLThread(new Runnable(){  
            public void run(){  
                System.out.println("----callNativeFunShowText----in runOnGLThread-----"+str);  
                NativeFunShowText(str);  
            }  
        });  
    }     
}  

JniCallback.h
#pragma  once  
namespace JniCallback  
{  
}  

JniCallback.cpp
#include "JniCallback.h"  
#include "cocos2d.h"  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
#include <Jni.h>  
#include "platform/android/jni/JniHelper.h"  
#endif  
using namespace cocos2d;  
namespace JniCallback  
{  
    extern "C"   
    {  
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
        //Java_:是格式,必须加的  
        //org_cocos2dx_cpp_AppActivity_NativeFunShowText:是包名+类名+方法名       
        JNIEXPORT void JNICALL Java_org_cocos2dx_cpp_AppActivity_NativeFunShowText (JNIEnv* env, jclass method, jstring param)  
        {  
            const char* data = env->GetStringUTFChars(param, 0);  
            cocos2d::log("Java_org_cocos2dx_cpp_AppActivity_NativeFunShowText---- :%s",data);  
            //do cocosUI something  
            env->ReleaseStringUTFChars(param, data);  
        }  
#endif  
    }  
}   

跟jni相关的C++代码文件放在proj.android\jni\hellocpp目录下,每加一个cpp文件,都需在proj.android\jni的Andriod.mk文件中添加:
LOCAL_SRC_FILES := hellocpp/main.cpp \  
             hellocpp/test.cpp \    <--为新添加的  
来自:https://blog.csdn.net/shimazhuge/article/details/72825665

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引