Cocos Creator 3.x WebView通信全攻略:从传参到回调的完整解决方案
在移动游戏开发中,内嵌网页(WebView)功能正变得越来越常见,无论是用于展示活动公告、用户协议,还是集成一个完整的H5小游戏。Cocos Creator 3.x 提供了强大的 WebView 组件,但很多开发者在实际使用中,尤其是在需要与内嵌网页进行双向通信时,总会遇到各种“坑”:参数传过去了但网页收不到、回调函数莫名失效、打包后功能异常等等。这些问题往往不是引擎的Bug,而是对通信机制的理解不够深入,或是忽略了某些关键的执行时机。这篇文章,我将结合自己多次“踩坑”的经验,为你梳理出一套从参数传递到回调处理的完整、稳定的解决方案,让你彻底告别WebView通信的烦恼。
1. 理解Cocos Creator WebView的通信基石
在开始写代码之前,我们必须先搞清楚Cocos Creator的WebView组件是如何与内嵌网页进行“对话”的。这不像两个独立的应用程序通过网络API通信,它更像是一个“主人”(Cocos游戏)与一个被“圈养”在特定区域内的“客人”(网页)之间的互动,互动方式受到平台和引擎的双重限制。
核心通信模型主要基于两种机制:
- URL与查询参数(Query String):这是最基础、最稳定的单向数据传递方式。Cocos端通过设置
webview.url属性,在URL后面附加参数(如?token=abc123&userId=456),网页端通过JavaScript的URLSearchParams或解析window.location.search来获取。这种方式简单直接,兼容性极佳,是传递初始化数据(如用户令牌、配置信息)的首选。 - JavaScript接口(Javascript Interface):这是实现双向通信的关键。Cocos端可以主动执行网页内的JavaScript代码(
evaluateJS),而网页端也可以通过触发特定格式的URL跳转,来“回调”通知Cocos端。后者需要Cocos端预先设置一个“关键词”(Scheme)来监听。
很多开发者遇到的第一个困惑就是:这两种方式该用哪种?我的经验是,将URL传参视为“初始化配置”,将JavaScript接口视为“运行时交互”。把稳定的、一次性的数据放在URL里;把动态的、需要反复调用的操作交给接口。
注意:WebView通信的细节在iOS和Android原生平台上可能略有不同,但Cocos Creator已经做了很好的封装。本文讨论的方案在两大平台的主流WebView内核(如WKWebView, Chrome WebView)上均经过验证。
2. 稳定传递参数:避开evaluateJS的时机陷阱
让我们先解决最常见的问题:如何把游戏里的用户Token安全地传给内嵌的网页?原始代码中尝试了多种方法,这恰恰反映了寻找稳定时机的过程。
2.1 首选方案:通过URL查询参数传递
这是最推荐、最不易出错的方式。它的原理是在加载网页时,直接将参数拼接在URL中。
Cocos端(TypeScript)示例:
// 假设这是你的WebView组件脚本
import { _decorator, Component, WebView } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('GameWebView')
export class GameWebView extends Component {
@property(WebView)
webview: WebView = null!;
// 打开WebView并传递参数的方法
openWebView(hostUrl: string, accessToken: string) {
// 将token作为查询参数拼接到URL中
const urlWithParams = `${hostUrl}?token=${encodeURIComponent(accessToken)}&platform=game`;
this.webview.url = urlWithParams;
this.webview.node.active = true;
}
}
网页端(JavaScript)示例:
// 在网页的初始化脚本中(例如main.js或第一个<script>标签内)
function initFromUrlParams() {
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
const platform = urlParams.get('platform');
if (token) {
console.log('成功接收到Token:', token);
// 将token存储到全局变量或状态管理器中,供后续API请求使用
window.APP_CONFIG = {
token: token,
platform: platform || 'web'
};
// 或者调用一个预先定义好的全局函数
if (typeof window.setToken === 'function') {
window.setToken(token);
}
} else {
console.warn('未从URL中找到Token参数');
}
}
// 在DOM加载完成后或适当时机调用
document.addEventListener('DOMContentLoaded', initFromUrlParams);
这种方式的优势非常明显:
- 时机绝对可靠:参数随着网页的首次HTTP请求一起发出,网页在加载时就能获取到。
- 无需等待:避免了寻找执行JavaScript时机的麻烦。
- 兼容性最好:是所有WebView都支持的标准HTTP行为。
2.2 备选方案:使用evaluateJS及其正确时机
有时,我们需要在网页加载后动态地传递数据,这时就需要用到 webview.evaluateJS 方法。原始代码中遇到的“找不到方法”或“执行不稳定”问题,根本原因在于调用时机不对。
关键点:必须在网页的JavaScript环境完全准备就绪后,才能调用 evaluateJS。 仅仅监听 WebView.EventType.LOADED 事件可能还不够,因为这个事件只代表网页框架(HTML)加载完毕,其中的脚本可能尚未执行。
一个更稳健的做法是,结合 LOADED 事件和一个小延迟,或者让网页主动通知Cocos端它已准备就绪。
改进后的Cocos端代码:
this.webview.node.on(WebView.EventType.LOADED, () => {
console.log('WebView页面框架加载完毕');
// 方法一:使用一个短暂的延时(经验值,通常500ms-1000ms足够)
this.scheduleOnce(() =&


145

被折叠的 条评论
为什么被折叠?



