当前位置: 首页 > article >正文

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本: 3.8.1

语言: JavaScript/TypeScript、C++、Java

环境:Window

参考:Java原生反射机制

您好,我是鹤九日!



回顾


在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。

我们简单讲解了UnityAds跨平台接入,关于JavaScript/TypeScript和Java的交互,鉴于篇幅的缘故,只有寥寥数笔。

本篇文章的主题便是跨平台交互相关,主要内容:

一、JavaScript/TypeScript 调用 Java 接口

二、Java调用JavaScript



开始之前


正式开始之前,稍微对语言说明下,有助于我们对跨平台交互的理解!

Cocos引擎,无论是Cocos2d-x还是CocosCreator,在不同平台下使用的语言大致如下:

一、Cocos2d-x:C++、Lua、Java、Object-C

二、CocosCreator: C++、JavaScript、TypeScript、Java、Object-C

简单的理解:

一、C++构建游戏引擎的基础,可以想象下为什么求职面试必问C++?

二、Java、Object-C多数同SDK相关,算是第三方交互的延伸

三、Lua、JavaScript、TypeScript等等,这些脚本资源则划分到资源中,用于热更新等。

这样的理解有失偏颇,但我们只需懂得:Cocos引擎在跨平台交互方面,离不开C++语言的支撑。

注:可以理解为不同语言的交互:C++是纽带、桥梁!

我很早的时候写过一篇文章,讲解的是 cocos2d-x Android平台与Lua的交互!

里面其实就三点:

一、交互的方法通过:callStaticMethod

二、C++封装了LuaJavaBridge的接口

三、交互的大致步骤:

  1. Lua调用Java: Lua --> C++ --> Java

  2. Java调用Lua: Java --> C++ --> Lua

如果放到CocosCreator中,相信您已经想到我想要表达什么了。



Creator跨平台封装


就如上面所言:Creator引擎对于JavaScript同Java、Object-C的交互同样是以C++为纽带进行封装的。

调用的方法接口一如既往的还是:callStaticMethod

注:这一点也体现出,为什么会有些人认为Creator是2dx的衍生版本,因为太相似了!

在引擎源码中搜索下,如下图:

请添加图片描述

我们可以看到这样的信息:

一、JavaScript同Java的交互,使用的类接口:JavaScriptJavaBridge

二、JavaScript同Object-C的交互,使用的类接口: JavaScriptObjCBridge

// C++封装的JavaScript和Java之间的桥接函数
static bool JavaScriptJavaBridge_callStaticMethod(se::State &s) {...}
// C++封装的JavaScript和Object-C之间的桥接函数
static bool JavaScriptObjCBridge_callStaticMethod(se::State &s) {...}

相信到这里,你已经明白交互的流程。

TypeScript经过编译器转换为JavaScript,JavaScript调用C++封装的桥接函数,调用Java来实现SDK相关!

简言之:JavaScript–> C++ --> Java



CallStaticMethod


CallStaticMethod的被封装在模块nativereflection中, 主要定义如下:

import { native } from 'cc'; 
// 用于调用Java的静态方法
var o = native.reflection.callStaticMethod(className,                 // string, Java的类名,以/分割,不能是.methodName,                // string, Java类的方法名methodSignature,           // string, Java方法签名parameters...              // any, Java方法的参数
)// 调用Objective-C的静态方法
var result = native.reflection.callStaticMethod(className, methodName, arg1, arg2, .....         // 直接传参即可,无需签名
);

调用的Java、Objective-C方法一定为静态方法,这样的好处有:

  • 无需实例化,便可直接调用

  • 便于组织和管理,不依赖于类的实例状态,减少依赖调用更快

  • 兼容性高

注:最早期的cocos2d-x版本有非静态方法的使用,但废弃掉了!

以Android平台下的UnityAds的广告SDK为例,可以这样编写:

public showRewardAd() {// 检测平台是否为原生平台if (!sys.isNative) return;if (sys.os == sys.OS.ANDROID) {// Andriodconst className = "com/cocos/demo/UnityAdsManager";const methodName = "showRewardAd";const signature = "()V";native.reflection.callStaticMethod(className, methodName, signature);} else if (sys.os == sys.OS.IOS) {// ios}
}

建议:针对于SDK交互相关,可创建一个单例管理类NativeManger,方便维护处理!



Java的方法签名


使用callStaticMethod,传入的参数注意:

一、Java的类名字符串,应以/间隔,而不是.

二、方法名字符串,在java中为static方法

三、签名和参数是相对应的,目前Cocos Creator支持的Java类型主要有:

Java类型签名类型说明
intI整数类型,是大写的i
floatF浮点类型
booleanZ布尔类型
StringLjava/lang/String;字符串类型,别漏了;

签名参数,这一点很重要,原因在于Java支持函数重载。

使用签名是为了方便我们能够正确的调用到对应的方法。

签名参数的格式很简单:(参数类型)返回值类型

简单的示例:

const reflection = native.reflection;
// "()V" 表示没有参数,没有返回值
reflection.callStaticMethod(..., "()V");
// "(I)Z" 表示单个整形参数,返回整形数值
let value:boolean = reflection.callStaticMethod(..., "(I)I", 3);
// "(II)I" 表示两个整形参数,返回整形数值
let value:number = reflection.callStaticMethod(..., "(II)I", 3, 7);
// "(IILjava/lang/String;)Z" 表示两个整形、一个字符串,返回布尔数值
let value:boolean = reflection.callStaticMethod(..., "(IILjava/lang/String;)Z", 3, 7, "str");
// "(Ljava/lang/String;)Ljava/lang/String;" 表示一个整形参数,返回字符串
let value:string = reflection.callStaticMethod(..., "(Ljava/lang/String;)Ljava/lang/String;", "content");

注:如果需要传入复杂对象,可借助JSON.stringify转换为字符串



Java调用JavaScript


SDK的接入,使用callStaticMethod 并不能完全满足需求。比如:

支付的接入,没有反馈,我们不知道支付的成功或失败。

广告的播放,没有反馈,我们不知道广告能否正常播放、是否正常播放结束。

还好,CocosCreator引擎提供了Java调用JavaScript的机制。主要实现有两部分:

Java部分

Java部分主要有两个接口:

一、通过CocosHelper.runOnGameThread获取执行中的GL线程。

注:GL 线程指的是引擎下JavaScript运行的特定线程,它负责处理渲染和JavaScript的逻辑。

为了确保线程安全,所有与 JavaScript 引擎交互的操作都必须在这个线程中执行;否则,无法保证线程安全。

二、在GL线程中执行CocosJavascriptJavaBridge.evalString 调用JavaScript中的脚本代码。

evalString接口内的参数是JavaScript中的方法,但往往是window环境全局对象下的方法。

虽为字符串形式,但同样支持JavaScript参数的传递,只不过只支持string, number 和 bool三种基础类型。

简单的示例:

import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;// 方式1: 使用匿名内部类实现,无参数传递
CocosHelper.runOnGameThread(new Runnable() {@Overridepublic void run() {CocosJavascriptJavaBridge.evalString("window.nativeEmpty()");}
});// 方式2: 使用Lambda表达式,传递字符串、整数和布尔类型
CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString("window.nativeParam('test',1,true)"));

注:使用window全局对象,java中的"window.callByNative()" 也可为"callByNative()"

注:两种方式等价,只不过后者更简洁、易读些


JavaScript/TypeScript部分

Java部分要调用JavaScript的方法,必须保证对象绑定在window环境全局对象中。主要原因有:

一、确保方法能够在全局作用域中访问

二、window对象是JavaScript的全局命名空间,避免复杂项目的命名冲突

三、确保代码在不同JavaScript环境中具有良好的兼容性和可移植性。

对应Java部分,TypeScript处可以这样编写:

window.nativeEmpty = function(){//to do
}window.nativeParam = function(a:string, b:number, c:bool){//to do
}

当然了,也可以创建单例对象类,并借助window注册为全局管理类。

export class NativeMgr{private static _inst:NativeMgr;public static get inst():NativeMgr{if(!this._inst){this._inst = new NativeMgr();}return this._inst;}public static nativeEmpty(){//to do}public static nativeParam(a:string, b:number, c:bool){//to do}
}//将 NativeMgr 注册为全局类,否则无法在 Java 中被调用
window.NativeMgr = NativeMgr;

使用管理类,在Java部分evalString传递参数的时候,可以这样编写:

String jsCall = "NativeMgr.inst.callByNative('test',1,true)";
CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString(jsCall));


UnityAds实战


这里呢,我们以UnityAds奖励广告的播放为例,它可能会出现这样的情况:

一、广告平台未初始化成功或不支持当前平台导致显示失败

二、广告为正常播放结束或者已经正常播放结束

Java中UnityAdsManager部分:

import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;// 显示奖励广告
public static void showRewardAd() {getInstance().loadRewardAd();
}// 加载显示奖励广告
private void loadRewardAd() {boolean isSupport = isSupport();boolean isInit = isInitialized();if (!isSupport || !isInit) {String content = "广告失败, isSupport: " + isSupport + " isInit:" + isInit;String jsCall = "NativeMgr.inst.onRewardAdFailed(" + content + ")";CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString(jsCall));return;}// 调用广告实例this.rewardedAd.loadRewardedAd();
}

Java中UnityAdsRewardedAd监听广告显示完成部分:

public void onUnityAdsShowComplete(String placementId, UnityAds.UnityAdsShowCompletionState state) {if (state.equals(UnityAds.UnityAdsShowCompletionState.COMPLETED)) {// Reward the user for watching the ad to completionString jsCall = "NativeMgr.inst.onRewardAdComplete(" + true + ")";CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString(jsCall));} else {// Do not reward the user for skipping the adString jsCall = "NativeMgr.inst.onRewardAdComplete(" + false + ")";CocosHelper.runOnGameThread(() -> CocosJavascriptJavaBridge.evalString(jsCall));}
}

JavaScript部分

export class NativeMgr{private static _inst:NativeMgr;public static get inst():NativeMgr{if(!this._inst){this._inst = new NativeMgr();}return this._inst;}public static onRewardAdFailed(err: string){console.log("UnityAds Error:", err);}public static onRewardAdComplete(sucess: boolean){const content = sucess ? "成功" : "失败"console.log(content);}
}
window.NativeMgr = NativeMgr;


最后


今天的文章到结束就结束了,可能理解有误,给您带来不便,期待您的反馈!

简单汇总下:

一、JavaScript同Java的交互,Cocos2dx和CocosCreator有相似之处,C++是纽带

二、JavaScript调用Java的静态方法使用的是callStaticMethod

三、callStaticMethod参数支持int、float、boolean、string类型,必须对应指定的(参数)返回值签名字符串

四、Java调用JavaScript方法,借助CocosHelper.runOnGameThread运行到指定的GL流程中,然后再调用CocosJavascriptJavaBridge.evalString

五、evalString调用的JavaScript对象必须在window全局环境中,参数传递支持int、bool、string类型。

如果觉得文章不错,期待您的点赞和留言,感谢!

我是鹤九日,祝您生活愉快!

相关文章:

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

【单片机期末】单片机系统设计

主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...