编程设计:cosos2d-x之C++与Java混编通用接口

本文介绍了一种简化Cocos2d-x游戏开发中JNI接口编写的方法,通过C++和Java之间的调用示例展示了如何高效地进行跨语言交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相信所有使用cocos2d-x开发Android游戏的小伙伴们都遇过这样的问题:我们游戏逻辑在c++原生代码实现,但接入各类平台sdk时,却是java版本,于是写JNI接口占去了sdk接入的大部分时间。

背景交待完毕,进入正题。我们使用一个简单接口来使用JNI。以下接口实现比较粗糙,仅提供一个思路,实际操作中请结合自己项目灵活实现。

以下代码引入了c++11特性支持。

此功能主要涉及以下3个文件:

AndroidJNI.h

AndroidJNI.cpp

com.sample.x.AndroidJNI.java

 

// AndroidJNI.h

#pragma once #include <string> #include <functional> #include <map> namespace AndroidJNI { void callJNI(std::string name, std::string info, std::function<void (std::string)> onCallback); void setKeptCallbacks(std::string name, std::function<void(std::string)> onCallback); }

 

// AndroidJNI.cpp
#include "AndroidJNI.h"
#include "platform/android/jni/JniHelper.h"
#include "cocos2d.h"

using namespace cocos2d;

namespace AndroidJNI {
	std::function<void (std::string)> popCallbacks(std::string name);
	std::function<void (std::string)> getKeptCallbacks(std::string name);
}

void AndroidJNI::callJNI(std::string name, std::string data, std::function<void (std::string)> onCallback)
{
	mOnCallbacks[name] = onCallback;

	JniMethodInfo m;

	bool isHave = JniHelper::getStaticMethodInfo(m, "com/sample/x/AndroidJNI", "Call", "(Ljava/lang/String;Ljava/lang/String;)V");

	if(!isHave) throw "java method not found";

	auto jname = m.env->NewStringUTF(name.data());
	auto jdata = m.env->NewStringUTF(data.data());

	m.env->CallStaticVoidMethod(m.classID, m.methodID, jname, jdata);

	m.env->DeleteLocalRef(jname);
	m.env->DeleteLocalRef(jdata);
}

void AndroidJNI::setKeptCallbacks(std::string name, std::function<void(std::string)> onCallback)
{
	if(onCallback == nullptr)
	{
		mKeptCallbacks.erase(name);
	}
	else
	{
		mKeptCallbacks[name] = onCallback;
	}
}

std::function<void (std::string)> AndroidJNI::popCallbacks(std::string name)
{
	auto iter = mOnCallbacks.find(name);
	if(iter == mOnCallbacks.end()) return nullptr;
	auto func = iter->second;
	mOnCallbacks.erase(iter);
	return func;
}

std::function<void (std::string)> AndroidJNI::getKeptCallbacks(std::string name)
{
	auto iter = mKeptCallbacks.find(name);
	if(iter == mKeptCallbacks.end()) return nullptr;
	auto func = iter->second;
	return func;
}

extern "C" {
	void Java_com_sample_x_AndroidJNI_OnResult(JNIEnv *env, jobject obj, jstring jname, jstring jdata)
	{
		std::string name = jname ? env->GetStringUTFChars(jname, nullptr) : "";
		std::string data = jdata ? env->GetStringUTFChars(jdata, nullptr) : "";

		auto func = AndroidJNI::popCallbacks(name);
		if(!func)
		{
			func = AndroidJNI::getKeptCallbacks(name);
		}

		if(func)
		{
			Director::getInstance()->getScheduler()->performFunctionInCocosThread([func, data]() {
				func(data);
			});
		}
		else
		{
			// log error
		}
	}
}

 

// com.sample.x.AndroidJNI.java
package com.sample.x; public class AndroidJNI { native private static void OnResult(final String name, final String data); static public void Call(final String name, final String data) { MainStatic.RunInUI(new Runnable() { //@Override public void run() { if (name.equals("test")) { // Do any thing OnResult("test", "result:ok"); } } }); } }

 

在c++中通过callJNI方法来调用java接口,参数name为接口名称,info为接口参数,这两个值将传递到 java代码中的 Call(final String name, final String data)。java中根据调用的name,来作相关的操作。若需要传递多个参数可依需求将data改为c++中的std::vector<std::string>和java里的String[]相对应。当然也可对这里的string进行格式化来实现多个参数的传递。

callJNI最后一个参数是一个回调函数,java部分执行完工作后将结果通过回调函数传递回来。Java的OnResult方法的name参数与Call的name参数(即c++ callJNI的name参数)一致。

另一个c++方法是setKeptCallbacks,它设定一个回调函数,用来接收java端发起的通知。在c++端设定名称为name的回调后,java端可随时主动调用OnResult方法来将data传递到c++的name所对应的函数中。回调函数的string参数与OnResult的data参数相对应。

 

接下来在编写c++代码时,我们可以不用再考虑jni的东西了。另外如果需要在windows或mac下开发,可以实现一个AndroidJNI.cpp的windows版或iOS版,在其它平台上进行c++代码(包含android分发内容)的调试。

 

示例:

// c++

AndroidJNI::callJNI("getArgCount", "arg1\narg2\narg3", [](std::string res) { // 简单用换行分隔多个参数,需要保证每个参数不包含换行符

printf("the count is %s", res.data());

});

 // Java

package com.sample.x;


public class AndroidJNI
{

	native private static void OnResult(final String name, final String data);
	
	static public void Call(final String name, final String data)
	{
		MainStatic.RunInUI(new Runnable() {
			//@Override
			public void run()
			{
				if (name.equals("getArgCount"))
				{
// 这块代码可使用一个代理类接口来处理,如此一来这个文件就不需要再修改了
					String[] args = data.split("\n");
					OnResult("test", "result:" + args == null? 0 : args.length);
				}
			}
		});
	}
}

 

转载于:https://www.cnblogs.com/leaving/p/6905265.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值