JniHelper调用java静态和非静态方法总结(即cocos2dx中调用android平台下显示第三方广告)

简介: 调用非静态方法首先就是调用的静态方法得到要调用的java的类对象然后通过调用minfo.env->CallVoidMethod(activityObj, minfo.
调用非静态方法首先就是调用的静态方法得到要调用的java的类对象然后通过调用
minfo.env->CallVoidMethod(activityObj, minfo.methodID);方法把对象和要调用的方法以及参数(如果有


)传递个java类对象中的非静态方法;


java类:


// c++中調用的方法
    public static Object rtnActivity() {
        System.out.println("----------rtnActivity");
        return mainActivity;
    }

public void showAD() {
Log.i("test", "jnihelper do ...show ad");
// ad
// 展示插播广告,可以不调用loadSpot独立使用
SpotManager.getInstance(MainActivity.this).showSpotAds(
MainActivity.this, new SpotDialogListener() {
@Override
public void onShowSuccess() {
Log.i("SpotAd", "展示成功");
}


@Override
public void onShowFailed() {
Log.i("SpotAd", "展示失败");
}


});

}
红色部分替换成你要展示的广告即可

c++调用cpp:


//判断当前是否为Android平台;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 

//定义Jni函数信息结构体;
JniMethodInfo minfo;
//返回一个bool值表示是否找到此函数;
bool isHave = JniHelper::getStaticMethodInfo


(minfo,"org/cocos2dx/hellocpp/MainActivity","rtnActivity", "()Ljava/lang/Object;");
jobject activityObj;
if (isHave) {
//CallStaticObjectMethod调用java函数,并把返回值赋值给activityObj
activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
}


//2. 查找displayWebView接口,获取其函数信息,并用jobj调用;
//定义Jni函数信息结构体;
isHave = JniHelper::getMethodInfo(minfo,"org/cocos2dx/hellocpp/MainActivity","showAD", 


"()V"); 


if (!isHave)
{
CCLog("jni:showAD 函数不存在;");
}
else
{
//调用displayWebView函数,并传入参数
minfo.env->CallVoidMethod(activityObj, minfo.methodID);
}

#endif





对于要调用带参数的java非静态方法的可参见分割线一下部分

-----------------华丽的分割线---------------------------------------------


主体思路
通过JNI获取java虚拟机,再获取当前程序的JNI环境,通过JNI环境获取需要调用的java类信息,再获取需要调用的java类中的函数信息。再通过JNI环境调用,使用类信息、函数信息,调用对应的java函数。
看起来好像有点复杂,but不用担心,cocos2d-x中有一个JniHelper类(头文件的copyright为:cocos2d-x.org,是Google提供的还是cocos2d-x小组自己封装的我就不清楚了),它已经把这些工作封装好了。




JniHelper类的使用
加入如下头文件:


#include "platform/android/jni/JniHelper.h"
需要使用的接口如下:


static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
static bool getMethodInfo(JniMethodInfo &methodinfo, const char *className, const char *methodName, const char *paramCode);
实现上我们只需要使用上面这两个接口,就可以获取java类的所有函数信息了。JNI环境的获取、各种错误处理都已经在这两个接口实现中封装好了。
先上代码,再来依次讲解每个参数的意义和使用方法:


    //函数信息结构体
    JniMethodInfo minfo;
    bool isHave = JniHelper::getStaticMethodInfo(minfo,/*JniMethodInfo的引用*/
                                                 "com/omega/MyApp",/*类的路径*/
                                                 "getJavaActivity",/*函数名*/
                                                 "()Ljava/lang/Object;");/*函数类型简写*/
    jobject activityObj;
    if (isHave)
    {
        //CallStaticObjectMethod调用java函数,并把返回值赋值给activityObj
        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
    }
OK,很简单。上面的代码,就是使用JNI在C++中调用java类静态函数的典型使用方法。只有两步:


1. 获取java函数的信息,classid、methodid等等
2. 选择JNIEnv中的接口,进行函数调用
getStaticMethodInfo参数详解
两个接口的参数一样,意义也相同,详解如下:
JniMethodInfo &methodinfo JniMethodInfo对象的引用,函数执行中会把jniEvn、classid、methodid写入到引用中。
const char *className 类的路径,把类的完整包名写全,用法如以上代码。
const char *methodName 函数名,函数名写上就行了。


const char *paramCode 函数类型简写
这个参数需要单独介绍,它的格式为:(参数)返回类型。
例如:无参数,void返回类型函数,其简写为 ()V
java中的类型对应的简写如下:


参数类型 参数简写
boolean Z
byte B
char C
short S
int I
long J
float F
double D
void V
Object Ljava/lang/String; L用/分割类的完整路径
Array [Ljava/lang/String; [签名 [I
多参数的函数
如果函数有多个参数,直接把简写并列即可。注意Object与Array型参数简写结尾的分号,示例:
IIII //4个int型参数的函数
ILjava/lang/String;I //整形,string类型,整形组合 (int x, String a, int y)


通过JNIEnv进行函数调用
JNIEvn有一系列的CallStatic[返回类型]Method、Call[返回类型]Method接口,需要针对不同的函数返回类型选择调用。
[返回类型]以函数返回类型的不同,对应不同的函数名。
例如:
CallStaticVoidMethod ———void
CallVoidMethod ———void
其对应关系如下:


函数名 函数返回值类型
Void void
Object jobject
Boolean jboolean
Byte jbyte
Char jchar
Short jshort
Int jint
Long jlong
Float jfloat
Double jdouble
参数传递
调用有参数的java函数时,需要把对应的参数传递进去。需要把参数按顺序加入到classid、methodid后面,并且需要做类型转换。例如:


jint jX = 10;
jint jY = 10;
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jX, jY);
参数类型转换关系如下:


C++类型 JAVA类型
boolean jboolean
byte jbyte
char jchar
short jshort
int jint
long jlong
float jfloat
double jdouble
Object jobject
Class jclass
String jstring
Object[] jobjectArray
boolean[] jbooleanArray
byte[] jbyteArray
char[] jcharArray
short[] jshortArray
int[] jintArray
long[] jlongArray
float[] jfloatArray
double[] jdoubleArray
string类型的转换
实际上我们最常用的参数类型,主要是内建的数据类型、string字符串类型。数据类型可以直接转为j类型,但是string类型需要做如下处理:


jstring jmsg = minfo.env->NewStringUTF("http://www.baidu.com");
minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jmsg);
非静态函数的调用
非静态函数的调用与静态函数的调用类型,但是需要通过一个静态函数获取java类对象。
示例:


//C++代码
    //1. 获取activity静态对象
    JniMethodInfo minfo;
    bool isHave = JniHelper::getStaticMethodInfo(minfo,
                                                 "com/omega/MyApp",
                                                 "getJavaActivity",
                                                 "()Ljava/lang/Object;");
    jobject activityObj;
    if (isHave)
    {
        //调用静态函数getJavaActivity,获取java类对象。
        activityObj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID);
    }


    //2. 查找displayWebView接口,获取其函数信息,并用jobj调用
    isHave = JniHelper::getMethodInfo(minfo,"com/omega/MyApp","displayWebView", "(IIII)V"); 


    if (!isHave)
    {
        CCLog("jni:displayWebView 函数不存在");
    }
    else
    {
        //调用此函数
        jint jX = (int)tlX;
        jint jY = (int)tlY;
        jint jWidth = (int)webWidth;
        jint jHeight = (int)webHeight;
        //调用displayWebView函数,并传入参数
        minfo.env->CallVoidMethod(activityObj, minfo.methodID, jX, jY, jWidth, jHeight);
    }
详尽的示例代码
最后,放一块比较详细的JNI使用代码,基本上覆盖了的全部使用情况。


    JniMethodInfo minfo;//JniHelper   


    /* 测试用方法 */ 
    /*bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","loginGree", "()V"); //
     if (isHave) {
     //CCLog("有showText ");
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID);
     }else
     {
     //CCLog("没有方法showText");
     }*/


    /* 分享 */
    /*//将c++中的string转换成java中的string
     //char str[] = "test";
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","shareSina", "(Ljava/lang/String;Ljava/lang/String;)V"); //
     if (isHave) {
     //CCLog("有share ");
     jstring jstr = minfo.env->NewStringUTF("test1 share");
     jstring jst = minfo.env->NewStringUTF("/data/data/com.cocoa/cy.png"); 
     //jstring jst = minfo.env->NewStringUTF("");
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,jstr,jst);
     }else
     {
     //CCLog("没有方法share");
     }*/
    /* 设置高分 */
    /*jint ind = 0;
     jlong lsre = 2202l;
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","setHighScore", "(IJ)V"); 
     if (isHave) {
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,ind,lsre);            
     }*/
    /* 成就解锁 */
    /*jint aind = 0;
     bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","unLock", "(I)V"); 
     if (isHave) {
     minfo.env -> CallStaticVoidMethod(minfo.classID,minfo.methodID,aind);            
     }*/
    /* 测试用方法 */ 
    bool isHave = JniHelper::getStaticMethodInfo(minfo,"com/cocoa/HiWorld","rtnActivity","()Ljava/lang/Object;");
    jobject jobj;
    if (isHave) { 
        jobj = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID); 
    }       
    //CCLog(" jobj存在"); 
    /* 测试用方法,非静态无参数无返回值方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "()V"); 
     if (isHave) {
     minfo.env -> CallVoidMethod(jobj,minfo.methodID);
     }*/
    /* 测试用方法,非静态有java类型的String参数无返回值方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;)V"); 
     if (isHave) {
     jstring jmsg = minfo.env->NewStringUTF("msg okey!");
     minfo.env -> CallVoidMethod(jobj,minfo.methodID,jmsg);
     }*/
    /* 测试用方法,返回java类型的String,有java类型的String和int参数方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "(Ljava/lang/String;I)Ljava/lang/String;"); 
     if (isHave) {
     jstring jmsg = minfo.env->NewStringUTF("msg okey! return string");
     jint index = 0;
     minfo.env -> CallObjectMethod(jobj,minfo.methodID,jmsg,index);
     }*/
    /* 测试用方法,返回java类型的String[],有java类型的String[]和int参数方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","showText", "([Ljava/lang/String;I)[Ljava/lang/String;"); 
     if (isHave) {
     jobjectArray args = 0;
     jstring str;
     jsize len = 5;
     const char* sa[] = {"Hi,","World!","JNI ","is ","fun"};
     int i = 0;
     args = minfo.env->NewObjectArray(len,minfo.env->FindClass("java/lang/String"),0);
     for(i=0;iNewStringUTF(sa[i]);
     minfo.env->SetObjectArrayElement(args,i,str);
     }
     //minfo.env->GetStringArrayRegion(args,0,10,buf);
     //jintArray jmsg = {1,2,3};
     //minfo.env->NewStringUTF("msg okey! return string");
     jint index = 0;
     minfo.env -> CallObjectMethod(jobj,minfo.methodID,args,index);
     }*/
    /* 测试用方法,无返回类型,有java类型的int[]和int参数方法 */
    /*isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([II)V"); 
     if (isHave) {
     jint buf[]={7,5,8,9,3};
     jintArray jintArr; //定义jint数组
     jintArr = minfo.env->NewIntArray(5);
     minfo.env->SetIntArrayRegion(jintArr,0,5,buf);
     jint index = 0;
     minfo.env -> CallVoidMethod(jobj,minfo.methodID,jintArr,index);
     }*/
    /* 测试用方法,无返回类型,有java类型的byte[]和int参数方法 */
    isHave = JniHelper::getMethodInfo(minfo,"com/cocoa/HiWorld","testArr", "([BI)V"); 
    if (isHave) {
        jbyte buf[]={7,5,8,9,3};
        jbyteArray jbyteArr; //定义jbyte数组
        jbyteArr = minfo.env->NewByteArray(5);
        minfo.env->SetByteArrayRegion(jbyteArr,0,5,buf);
        jint index = 0;
        minfo.env -> CallVoidMethod(jobj,minfo.methodID,jbyteArr,index);
    }
private static HiWorld hiWorld = null;
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    hiWorld = this;
    if (detectOpenGLES20()) {
        // get the packageName,it's used to set the resource path
        String packageName = getApplication().getPackageName();
        super.setPackageName(packageName);
        // set content
        setContentView(R.layout.game_demo);
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
                                  R.layout.window_title);


        mGLView = (Cocos2dxGLSurfaceView) findViewById(R.id.game_gl_surfaceview);
        mGLView.setTextField((Cocos2dxEditText) findViewById(R.id.textField));
        mGLView.setEGLContextClientVersion(2);
        mGLView.setCocos2dxRenderer(new Cocos2dxRenderer());
        task = new TimerTask() {
            @Override
            public void run() {
                // HiWorld.shoot(hiWorld);
                Log.e("-------------------", "-------------------");
                // 调用c++中的方法
                System.out.println("------------------------"
                                   + stringZjy1());
            }
        };
        timer = new Timer();
        timer.schedule(task, 5000);
    } else {
        Log.d("activity", "don't support gles2.0");
        finish();
    }


    static {
        System.loadLibrary("game");
    }


    // c++中調用的方法
    public static Object rtnActivity() {
        System.out.println("----------rtnActivity");
        return hiWorld;
    }


    // c++中調用的方法,传String类型
    public void showText(final String msg) { 
        // 添加到主线程
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------msg:"+msg);
            }
        });
    }
    //c++中調用的方法,传String类型和int类型
    public String showText(final String msg,final int index) { 
        // 添加到主线程
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------msg:"+msg+"; index="+index);
            }
        });
        return "okey String showText(final String msg,final int index)";
    }
    //c++中調用的方法,传String[]类型和int类型
    public String[] showText(final String[] msg,final int index) { 
        String[] strArr = {"1","2","3","4","5"};
        // 添加到主线程
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                for(String _str:msg){
                    System.out.println("----------String[] msg:"+_str+"; index="+index);
                }
            }
        });
        return strArr;
    }
    //c++中調用的方法,传int[]类型和int类型
    public void testArr(final int msg[],final int index) { 
        // 添加到主线程
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------int[] msg len:"+msg.length);
                for(int _bl:msg){
                    System.out.println("----------int[] msg:"+_bl+"; index="+index);
                }
            }
        });
    }
    //c++中調用的方法,传int[]类型和int类型
    public void testArr(final byte msg[],final int index) { 
        // 添加到主线程
        hiWorld.runOnUiThread(new Runnable() {
            public void run() { 
                System.out.println("----------byte[] msg len:"+msg.length);
                for(int _bl:msg){
                    System.out.println("----------byte[] msg:"+_bl+"; index="+index);
                }
            }
        });
    }

相关文章
|
25天前
|
SQL 监控 数据可视化
完全开源!国内首个完全开源JAVA企业级低代码平台
JeeLowCode 是一款专为企业打造的 Java 企业级低代码开发平台,通过五大核心引擎(SQL、功能、模板、图表、切面)和四大服务体系(开发、设计、图表、模版),简化开发流程,降低技术门槛,提高研发效率。平台支持多端适配、国际化、事件绑定与动态交互等功能,广泛适用于 OA、ERP、IoT 等多种管理信息系统,帮助企业加速数字化转型。
|
2月前
|
Java Android开发 Swift
安卓与iOS开发对比:平台选择对项目成功的影响
【10月更文挑战第4天】在移动应用开发的世界中,选择合适的平台是至关重要的。本文将深入探讨安卓和iOS两大主流平台的开发环境、用户基础、市场份额和开发成本等方面的差异,并分析这些差异如何影响项目的最终成果。通过比较这两个平台的优势与挑战,开发者可以更好地决定哪个平台更适合他们的项目需求。
118 1
|
3月前
|
IDE Android开发 iOS开发
探索Android与iOS开发的差异:平台选择对项目成功的影响
【9月更文挑战第27天】在移动应用开发的世界中,Android和iOS是两个主要的操作系统平台。每个系统都有其独特的开发环境、工具和用户群体。本文将深入探讨这两个平台的关键差异点,并分析这些差异如何影响应用的性能、用户体验和最终的市场表现。通过对比分析,我们将揭示选择正确的开发平台对于确保项目成功的重要作用。
|
20天前
|
人工智能 监控 数据可视化
Java智慧工地信息管理平台源码 智慧工地信息化解决方案SaaS源码 支持二次开发
智慧工地系统是依托物联网、互联网、AI、可视化建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。围绕施工现场管理的人、机、料、法、环五大维度,以及施工过程管理的进度、质量、安全三大体系为基础应用,实现全面高效的工程管理需求,满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效,为监管平台提供数据支撑。
34 3
|
1月前
|
SQL 监控 数据可视化
完全开源!国内首个完全开源JAVA企业级低代码平台
JeeLowCode 是一款专为企业打造的 Java 企业级低代码开发平台,通过五大核心引擎(SQL、功能、模板、图表、切面)和四大服务体系(开发、设计、图表、模版),简化开发流程,降低技术门槛,提高研发效率。平台支持多端适配、国际化、事件绑定与动态交互等功能,广泛适用于 OA、ERP、IoT 等多种管理信息系统,帮助企业加速数字化转型。
完全开源!国内首个完全开源JAVA企业级低代码平台
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
98 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
3月前
|
监控 Android开发 iOS开发
深入探索安卓与iOS的系统架构差异:理解两大移动平台的技术根基在移动技术日新月异的今天,安卓和iOS作为市场上最为流行的两个操作系统,各自拥有独特的技术特性和庞大的用户基础。本文将深入探讨这两个平台的系统架构差异,揭示它们如何支撑起各自的生态系统,并影响着全球数亿用户的使用体验。
本文通过对比分析安卓和iOS的系统架构,揭示了这两个平台在设计理念、安全性、用户体验和技术生态上的根本区别。不同于常规的技术综述,本文以深入浅出的方式,带领读者理解这些差异是如何影响应用开发、用户选择和市场趋势的。通过梳理历史脉络和未来展望,本文旨在为开发者、用户以及行业分析师提供有价值的见解,帮助大家更好地把握移动技术发展的脉络。
99 6
|
3月前
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
146 1
|
3月前
|
开发工具 Android开发 iOS开发
安卓与iOS开发环境对比:选择适合你的平台
【9月更文挑战第26天】在移动应用开发的广阔天地中,安卓和iOS是两大巨头。它们各自拥有独特的优势和挑战,影响着开发者的选择和决策。本文将深入探讨这两个平台的开发环境,帮助你理解它们的核心差异,并指导你根据个人或项目需求做出明智的选择。无论你是初学者还是资深开发者,了解这些平台的异同都至关重要。让我们一起探索,找到最适合你的那片开发天地。
|
3月前
|
Android开发 开发者
Android平台无纸化同屏如何实现实时录像功能
Android平台无纸化同屏,如果需要本地录像的话,实现难度不大,只要复用之前开发的录像模块的就可以,对我们来说,同屏采集这块,只是数据源不同而已,如果是自采集的其他数据,我们一样可以编码录像。