調用非靜態方法首先就是調用的靜態方法得到要調用的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);
}
}
});
}