• cocos2d 中使用jni C++ 调用 Java 方法


    1.简单数据类型样例

    如果我们Java中有这么一个open的静态方法,它没有參数,有一个int的返回值。怎么在C++中调用它呢?


    package cb.CbCCBLE;
    public class CbCCBLECentralManager {
        public static final String TAG = "CbCCBLECentralManager Android";
        public static int open()
        {
        	Log.d(TAG,"open");
        	return 1;
        }
    }


    以下就是以下详细的调用方法,难点主要就是getStaticMethodInfo方法的传入參数。

    注意到cb/CbCCBLE/CbCCBLECentralManager。就是安卓的详细包名加上class名字,用中间都加'/'。

    "open"就是方法的名字。最后一个是传入參数和输出參数,比較全然匹配才干找到这个java方法,括号内是输入參数,右边跟着返回值。

    #if defined(ANDROID)
    #include "platform/android/jni/JniHelper.h"
    #include <jni.h>
    int CbCCBLECentralManager::open()
    {
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "open", "()I");
        if (! isHave)
        {
            CCLOG("FAIL: CbCCBLECentralManager - open");
            return 0;
        }
        
        int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID);
    
        return result;
    }
    #endif
    


    參数和返回值都会用特殊简写来取代,不是int,比方I代表int。完整的參数对于例如以下:

    參数类型參数简写
    booleanZ
    byteB
    charC
    shortS
    intI
    longJ
    floatF
    doubleD
    voidV

    表格中提到的简单类型如果是多个的话用比方是:


    public class CbCCBLECentralManager {
        public static final String TAG = "CbCCBLECentralManager Android";
        public static int open(int a, int b)
        {
        	Log.d(TAG,"open");
        	return 1;
        }
    }


    C++调用就例如以下了:


    JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "open", "()II");

    注意下CallStaticIntMethod。由于我们调用的是静态的返回int的方法,所以用了这个。要依据调用的方法不同而使用不同的东西,详细參考:  http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp2556


    2.看一个字符串的样例,字符串会有点麻烦:


    Java:


    public static int scanPeripheralWithName(String name, long duration)
        {
        	Log.d(TAG,"scanPeripheralWithName name:" + name + " duration:" + duration);
        	return 1;
        }

    C++


    int CbCCBLECentralManager::scanPeripheralWithName(std::string name, long duration)
    {
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "scanPeripheralWithName", "(Ljava/lang/String;J)I");
        if (! isHave)
        {
            CCLOG("FAIL: CbCCBLECentralManager - scanPeripheralWithName");
            return 0;
        }
        jstring jname = minfo.env->NewStringUTF(name.c_str());
        jlong jDuration = (long)duration;
        int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID,jname, jDuration);
        
        return result;
    }

    string是一个jobject。jobject要加L作为前缀,由于java中的string类完整+包名就是java/lang/String.所以string的完整就是 Ljava/lang/String。由于是jobject,所以用';'作为结束。

    要注意的是CallStaticIntMethod的最后2个參数。我们传进去了一个jstring和一个jlong。什么是jstring呢?是这种:

    jni有自己的数据类型,通常是j开头,用它们作为java 和 c++的中间媒体。


    JNI TypesJava Type
    voidvoid
    jbooleanboolean
    jbytebyte
    jcharchar
    jshortshort
    jintint
    jlonglong
    jfloatfloat
    jdoubledouble
    jobjectAll Java objects
    jclassjava.lang.Class objects
    jstringjava.lang.String objects
    jobjectArrayArray of objects
    jbooleanArrayArray of booleans
    jbyteArrayArray of bytes
    jshortArrayArray of shorts
    jintArrayArray of integers
    jlongArrayArray of longs
    jfloatArrayArray of floats
    jdoubleArrayArray of doubles


    3.看一个数组样例

    返回字符串的样例:

     public static String[] getAllPeripherals()
        {
            Log.d(TAG,"getAllPeripherals");
            String[] resultArray = {"testPeripheral1", "testPeripheral2"}; //just for test
            return resultArray;
        }

    std::vector<std::string> CbCCBLECentralManager::getAllPeripherals()
    {
        std::vector<std::string> stdResult;
        
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "getAllPeripherals", "()[Ljava/lang/String;");
        if (! isHave)
        {
            CCLOG("FAIL: CbCCBLECentralManager - getAllPeripherals");
            //return stdResult;
            return stdResult;
        }
        
        jobjectArray jResult = static_cast<jobjectArray>(minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID));
    
        jsize resultSize = minfo.env->GetArrayLength(jResult);
        
        jsize index = 0;
        while(index < resultSize)
        {
            jstring eachElement = (jstring)minfo.env->GetObjectArrayElement(jResult, index);
            std::string stdString = JniHelper::jstring2string(eachElement);
            stdResult.push_back(stdString);
            ++index;
        }
        
        return stdResult;
    
    }
    

    数组前面要加上一个'[', 这里还用了些其它方法,像得到数组长度,依据index得到数组内容。


    传入字符串的样例:

    public static int scanPeripheralWithServiceUUIDs(String[] serviceUUIDs, long duration)
        {
           Log.d(TAG,"scanPeripheralWithServiceUUIDs:" + duration);
        }

    int CbCCBLECentralManager::scanPeripheralWithServiceUUIDs(std::vector<std::string>serviceUUIDs,long duration){
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "scanPeripheralWithServiceUUIDs", "([Ljava/lang/String;J)I");
        if (! isHave)
        {
            CCLOG("FAIL: CbCCBLECentralManager - scanPeripheralWithServiceUUIDs");
            return 0;
        }
        jint size = serviceUUIDs.size();
        jclass StringObject = minfo.env->FindClass("java/lang/String");
        jobjectArray jServiceUUIDsArray = minfo.env->NewObjectArray( size, StringObject, NULL);
        jlong jDuration = (long)duration;
        for(int i = 0; i < serviceUUIDs.size(); i++)
        {
            jstring serviceUUID = minfo.env->NewStringUTF(serviceUUIDs[i].c_str());
            minfo.env->SetObjectArrayElement(jServiceUUIDsArray, i, serviceUUID);
        }
        int result = minfo.env->CallStaticIntMethod(minfo.classID, minfo.methodID, jServiceUUIDsArray, jDuration);
        
        return result;
    }


    4.看一个自己定义class的样例


    package OurBLE;
    
    
    public class OurBlePeripheralAdvertisementData
    {
        public String deviceName;
    public String getDeviceName(){
        	return deviceName;
        }
    }
    
    
    

    比方说有这么一个class作为jni怎样传递呢?事实上跟那个string相似。


     public static OurBlePeripheralAdvertisementData getPeripheralAdvertisementData(String peripheralId)
        {
            Log.d(TAG,"getPeripheralAdvertisementData");
            OurBlePeripheralAdvertisementData result = new OurBlePeripheralAdvertisementData();
            result.deviceName = "deviceName1";
            return result;
        }

    CbCCBLEPeripheralAdvertisementData CbCCBLECentralManager::getPeripheralAdvertisementData(std::string peripheralId)
    {
        CbCCBLEPeripheralAdvertisementData data = CbCCBLEPeripheralAdvertisementData();
        JniMethodInfo minfo;
        bool isHave = JniHelper::getStaticMethodInfo(minfo, "cb/CbCCBLE/CbCCBLECentralManager", "getPeripheralAdvertisementData", "(Ljava/lang/String;)LOurBLE/OurBlePeripheralAdvertisementData;");
        if (! isHave)
        {
            CCLOG("FAIL: CbCCBLECentralManager - getPeripheralAdvertisementData");
            return data;
        }
        jstring jPeripheralId = minfo.env->NewStringUTF(peripheralId.c_str());
        jobject result = minfo.env->CallStaticObjectMethod(minfo.classID, minfo.methodID, jPeripheralId);
        
        jclass CbCCBLEPeripheralAdvertisementDataClass = minfo.env->FindClass("OurBLE/OurBlePeripheralAdvertisementData");
        jmethodID deviceNameMId = minfo.env->GetMethodID(CbCCBLEPeripheralAdvertisementDataClass, "getDeviceName", "()Ljava/lang/String;");  
        jstring jDeviceName = (jstring)minfo.env->CallObjectMethod(result, deviceNameMId);
        
        //deviceName
        data.deviceName = JniHelper::jstring2string(jDeviceName);
    
        return data;
    }
    


    主要这里还用了些FindClass。GetMethodID, CallObjectMethod API,这样class就能传递了。

    jni真的是无所不能啊。 《cocos2d 中使用jni Java 调用 C++ 方法》

    http://www.waitingfy.com/archives/1648

  • 相关阅读:
    Python开发之路-多进程、进程队列、事件驱动模型、IO模型前戏
    Python开发之路
    cookies,sessionstorage,localstorage的区别?
    Linux的nmon监控结果分析文件中网络分析NET
    长字符串写法
    go中语句为什么不用加分号;结束
    %v的使用
    设计模式--装饰器模式
    第一类值VS第二类值
    闭包
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6702915.html
Copyright © 2020-2023  润新知