zoukankan      html  css  js  c++  java
  • c++和java交互之jni

    为了了解jni,我们先来个简单的需求。在cocos2d-x 3.3的项目中添加一个退出的按钮。点击按钮调用java的方法,然后通过java方法再调用C++的方法实现游戏的退出(其实就是绕一大圈为了给大家说明一下jni)

    接下来我们找一张退出按钮的图:

    。就这一张了。命名为exit.png

    接下来我们创建一个按钮Menu,并添加点击调用事件:

    MenuItemImage *    imgClose = MenuItemImage::create( "exit.png", "exit.png", CC_CALLBACK_0( HelloWorld::GameCloseCallBack, this ) );
    Menu *    menuCLose = Menu::create( imgClose, NULL );
    menuCLose->setPosition( Vec2( 400, 200 ) );
    sprite->addChild( menuCLose );

    接下来我们写点击按钮后调用的方法HelloWorld::GameCloseCallBack,然后我们在方法里面调用CppInterface::GameCloseCallBack();

    void HelloWorld::GameCloseCallBack() {
        CppInterface::GameCloseCallBack();
    }

    接下来我们去写CppInterface::GameCloseCallBack()方法(也就是CppInterface的静态方法GameCloseCallBack())

    CppInterface.h

    #ifndef __CPP_INTERFACE_H__
    #define __CPP_INTERFACE_H__
    
    
    #define AndroidClassName "org/game/lib/CppInterface"
    
    class CppInterface
    {
    public:   
        // 退出游戏(调用java)
        static void GameCloseCallBack();
      // 退出游戏(真正的退出)
        static void ExitGame();
        
    private:
    };
    
    #endif // __HELLOWORLD_SCENE_H__

    CppInterface.cpp

    #include "CppInterface.h"
    #include
    <cocos2d.h> #if defined(ANDROID) #include <platform/android/jni/JniHelper.h> #endif using namespace cocos2d; /* ===================== CppInterface::GameCloseCallBack ===================== */ void CppInterface::GameCloseCallBack() {
    // android平台
    #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID JniMethodInfo methodInfo; if( JniHelper::getStaticMethodInfo( methodInfo, AndroidClassName,"GameBack","()V") ) { methodInfo.env->CallStaticVoidMethod( methodInfo.classID, methodInfo.methodID ); } #else Director::getInstance()->end(); #endif } /* ==================== CppInterface::ExitGame ==================== */ void CppInterface::ExitGame() { Director::getInstance()->end(); }

    我给大家讲解一下:CppInterface.h中,AndroidClassName里面放的是C++调用java方法所在的包名及类名(也就是告诉C++,你要调用的java方法在哪里),中间用"/"隔开。

    对于CppInterface.cpp中GameCloseCallBack()方法中

    JniHelper::getStaticMethodInfo( methodInfo, AndroidClassName,"GameBack","()V") )
    GameBack为C++调用java中的方法名,“()V”:这个参数说的是C++调用java方法传参以及返回值,括号中填写的是C++调用java方法依次传的参数类型,无传参则不写。V表示void,表示方法无返回值
    ExitGame(),这个方法预留的是java调用C++的接口。来做真正的游戏退出

    接下来我们去做java的方法。

    在android工程下创建类CppInterface.java,类所在包名org.game.lib,代码如下:

    package org.game.lib;
    
    public class CppInterface {
        // 退出游戏(供C++调用)
        public static void GameBack() {
            JavaInterface.GameBack();
        }
    
    }

    我们在同级目录下创建JavaInterface.java,代码如下:

    package org.game.lib;
    
    public class JavaInterface {
      // 调用C++退出游戏的方法
        public static native void GameBack();
        
    }

    接下来我们在回到C++这边。在Classes目录中创建文件JavaInterface.cpp(不用创建头文件JavaInterface.h).代码如下:

    #if defined(ANDROID)
    #include <platform/android/jni/JniHelper.h>
    #include "CppInterface.h"
    extern "C"
    {
        void Java_org_game_lib_JavaInterface_GameBack( JNIEnv* env, jobject thiz ){
         // 退出游戏 CppInterface::ExitGame(); } } #endif

    这里要特别注意静态方法多了个native,加了native的静态方法,才能进入C++中调用extern "C"{}中的方法,你们可以看C++的方法名。其实就是java调用C++的方法所在的包名,类名,方法名组合起来的(这里指的是java的包名。类名),中间用下划线隔开,格式必须这样,不然调用不到!!格式为Java_包名_类名_方法名

    OK,接下来仔细阅读代码,基本上我们已经绕了一圈回来了。jni的C++和java互调就是这样

    基本流程就是=>退出按钮调用CppInterface类的静态方法GameCloseCallBack()->调用org.game.lib包名下的CppInterface.java的静态方法GameBack()->调用JavaInterface.java的静态方法GameBack() ->调用JavaInterface.cpp中extern "C"{}里面的Java_org_game_lib_JavaInterface_GameBack方法->调用CppInterface的ExitGame()。

    对于java传递过来的参数,boolean=》bool和int=》int外,string传过来就是jstring了,记得要转换,转换方法为:

    比如有个方法

    java方法:

    // 设置版本号
    public static native void SetBatchversion( final String jBatchversion );

    C++:

    void Java_org_game_lib_JavaInterface_SetBatchversion( JNIEnv* env, jobject thiz, jstring jBatchversion ){

      // 转换参数
      const char* chBatchversion = env->GetStringUTFChars( jBatchversion, NULL );
    }

    C++=》java传参的类型的对于表:

    ------------------------------

    类型      符号

    bool          Z  

    byte           B  

    char         C  

    short         S  

    int            I 

    long             L  

    float            F  

    double         D

    void             V

    std::string   Ljava/lang/String;

    -------------------------------------

    如果C++调用java要传参,则bool和int不需要转换,直接传。

    void ypCppInterface::SetIsShowPayDialog( bool isShow ) {
    // android平台 #
    if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID JniMethodInfo methodInfo; if( JniHelper::getStaticMethodInfo(methodInfo, AndroidClassName, "ShowPayDialog", "(Z)V") ) { methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, isShow); } #endif }

    但是如果是str:string或者const char*,则需要转换。代码如下:

    void ypCppInterface::InitLabelText( std::string httpRet ) {
    // android平台 #
    if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID JniMethodInfo methodInfo; if( JniHelper::getStaticMethodInfo(methodInfo, AndroidClassName, "InitLabelText", "(Ljava/lang/String;)V") ) {
         // 转换后传给java jstring jHttpRet
    = methodInfo.env->NewStringUTF( httpRet.c_str() ); methodInfo.env->CallStaticVoidMethod( methodInfo.classID, methodInfo.methodID, jHttpRet ); } #endif }

    还有一种就是有返回值的。如:

    std::string ypCppInterface::JSONToString( const char* jsonString, const char* strName ) {
        std::string strRet = "0";
    
    #if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
        JniMethodInfo methodInfo;
        if( JniHelper::getStaticMethodInfo(methodInfo, AndroidClassName, "JSONToString", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;") ) {
         // 转换后传给java jstring jstrJsonString
    = methodInfo.env->NewStringUTF(jsonString); jstring jstrName = methodInfo.env->NewStringUTF(strName); // 调用java有返回值的方法,得到返回值 jstring jstrRet = (jstring)methodInfo.env->CallStaticObjectMethod(methodInfo.classID, methodInfo.methodID, jstrJsonString, jstrName);
         // 转换类型,方便C++使用
    const char* chRet = methodInfo.env->GetStringUTFChars(jstrRet, NULL); strRet = chRet; } #endif return strRet; }

     不过在java那边接受的参数是不需要转换的:

    // json解析
    public static String JSONToString( final String jsonString, final String strName ) {
      return MobileDataStatus.JsonToString( "code", "0", "data", jsonString, strName );
    }

    整个调用流程就是这样。。。  希望大家能看懂。。。 文笔不好。。。谅解!!!

    最后给大家提醒一下,在这里,一定不能把int换成Integer,否则运行的时候会报错,不支持对象类型

  • 相关阅读:
    leetcode 203. Remove Linked List Elements 删除链表中的某个值 ---------- java
    leetcode 202. Happy Number 判断一个数是否是“Happy Number” ---------- java
    leetcode 201. Bitwise AND of Numbers Range 求范围中,每一位都是1的数 ---------- java
    js获取Html元素的实际宽度高度
    jquery中this与$this的区别
    find()与children()方法的区别
    jquery创建动态的div
    兼容性问题
    bootstrap插件小记
    禁掉a链接的几种方法
  • 原文地址:https://www.cnblogs.com/Colored-Mr/p/4721269.html
Copyright © 2011-2022 走看看