本文接上篇:
但为了让本文也可以单独阅读,仍保留必要信息。
一、Cocos扩展介绍
Cocos扩展可以让Cocos Creator用户定制和扩展编辑器的功能。这些扩展以包(package)的形式进行加载。
Cocos Creator 的扩展包沿用了 Node.js 社区的包设计方式,通过 package.json 描述文件来定义扩展包的内容和注册信息。
需要注意的是,Cocos Creator 2.x 系列和 Cocos Creator 3.x 系列的扩展不兼容,位置也不同,所以开发教程也不同。本文讲的是 Cocos Creator 3.x 系列扩展开发教程,Cocos Creator 2.x 系列见上一篇。
官方开发教程在:扩展编辑器 · Cocos Creator
Cocos扩展的商店页面是 store.cocos.com/app ,可以在Cocos Creator IDE中直接打开。
注:上图的SmartAd试玩打包工具就是本文要讲的案例。
二、教程案例介绍
1. 案例背景
本案例介绍的扩展名叫**SmartAd试玩打包工具**,是一个Cocos打包试玩广告的扩展。
试玩广告是一种新兴广告类型,在近几年开始兴起。与传统广告格式(如图片和视频)不同,试玩广告对用户具有高度互动性,在广告展示时,可以与用户进行交互,使广告变得更丰富有趣。
这些广告能在 30 秒内吸引观众的注意力、展示游戏玩法并转化用户。即使在竞争激烈的市场中,它们也能提供低用户获取成本(CPI)、高转化率 (CVR) 和点击率 (CTR)。
试玩广告本质上是一个HTML网页,通过JS等技术响应用户操作,与用户产生互动。由于带宽和加载速度的原因,试玩广告一般对文件大小都有严格要求,大多数投放渠道的要求是不超过5M,且要求单文件,即所有资源都要在一个HTML中加载展示。
Cocos因为引擎的特性,非常适合用来制作试玩广告,但Cocos导出的工程是一个多文件目录,需要用专门的工具进行单文件打包,并接入各渠道的SDK,这是一个耗时耗力的过程。SmartAd平台开发了一个工具,可以一键完成Cocos工程导出试玩广告,为了更方便用户使用,因此需要开发一个Cocos Creator扩展,方便用户的使用。
关于试玩广告,如果你想了解更多可以阅读这篇文章:应用、游戏和品牌的新营销方式-试玩广告-帮助中心-SmartAd试玩广告制作平台
2. 扩展流程
本扩展的流程是:
3. 涉及到的知识点
- 扩展基本结构
- 多语言
- 扩展菜单添加
- 扩展面板UI编写
- UIKit的使用
- 扩展数据交互
- 文件上传
- 扩展打包上架
三、创建基本结构
在菜单上选择 扩展->创建扩展:
即可打开扩展模板面板:
这里我们选择 HTML面板,扩展名叫smartad_demo,创建位置选全局:
操作完成后,即可在扩展管理器(也可以在菜单中通过 扩展 -> 扩展管理器 打开)中看到我们创建的扩展:
上面的操作,会在用户目录生成一个目录,结构如下:
这几个文件作用如下:
1. @types
扩展环境,不用关注,也用不到
2. dist
因为src中是用ts编写的,在发布时需要编译为js文件,ts编译为js后,就存在这个目录中。
3. i18n
多语言文件
4. src
扩展源码,是ts语言,这里面比较关键的有两个文件,分别是:
(1)src/main.ts
src/main.ts 是扩展入口文件,在package.json中定义: `//@ts-ignore
import packageJSON from '../package.json';
/**
-
@en
-
@zh 为扩展的主进程的注册方法
*/
export const methods: { [key: string]: (...any: any) => any } = {
openPanel() {
Editor.Panel.open(packageJSON.name);
},
};
/**
-
@en Hooks triggered after extension loading is complete
-
@zh 扩展加载完成后触发的钩子
*/
export const load = function() { };
/**
-
@en Hooks triggered after extension uninstallation is complete
-
@zh 扩展卸载完成后触发的钩子
*/
export const unload = function() { };` 值分别表示:
- methods:为扩展的主进程的注册方法,这里只注册了openPanel方法
- load:扩展打开时调用
- unload:扩展关闭调用
(2)src/panels/default/index.js
这个是面板入口文件,也在package.json中定义: `import { readFileSync } from 'fs-extra';
import { join } from 'path';
/**
-
@zh 如果希望兼容 3.3 之前的版本可以使用下方的代码
-
@en You can add the code below if you want compatibility with versions prior to 3.3
*/
// Editor.Panel.define = Editor.Panel.define || function(options: any) { return options }
module.exports = Editor.Panel.define({
listeners: {
show() { console.log('show'); },
hide() { console.log('hide'); },
},
template: readFileSync(join(__dirname, '../../../static/template/default/index.html'), 'utf-8'),
style: readFileSync(join(__dirname, '../../../static/style/default/index.css'), 'utf-8'),
$: {
app: '#app',
},
methods: {
hello() {
if (this.$.app) {
this.$.app.innerHTML = 'hello';
console.log('[cocos-panel-html.default]: hello');
}
},
},
ready() {
if (this.$.app) {
this.$.app.innerHTML = 'Hello Cocos.';
}
},
beforeClose() { },
close() { },
});`
5. static
静态资源,如html,css等,当然也可以放js文件
6. package.json
package.json是扩展定义,文件内容如下: `{
"package_version": 2,
"version": "1.0.0",
"name": "smartad_demo",
"description": "i18n:smartad_demo.description",
"main": "./dist/main.js",
"dependencies": {
"fs-extra": "^10.0.0"
},
"devDependencies": {
"@types/node": "^16.0.1",
"@types/fs-extra": "^9.0.5",
"typescript": "^4.3.4"
},
"panels": {
"default": {
"title": "smartad_demo Default Panel",
"type": "dockable",
"main": "dist/panels/default",
"size": {
"min-width": 400,
"min-height": 300,
"width": 1024,
"height": 600
}
}
},
"contributions": {
"menu": [
{
"path": "i18n:menu.panel/smartad_demo",
"label": "i18n:smartad_demo.open_panel",
"message": "open-panel"
},
{
"path": "i18n:menu.develop/smartad_demo",
"label": "i18n:smartad_demo.send_to_panel",
"message": "send-to-panel"
}
],
"messages": {
"open-panel": {
"methods": [
"openPanel"
]
},
"send-to-panel": {
"methods": [
"default.hello"
]
}
}
},
"author": "Cocos Creator",
"editor": ">=3.4.2",
"scripts": {
"build": "tsc -b",
"watch": "tsc -w"
}
}`
四、多语言
1、方案
Cocos Creator编辑器扩展系统中内置了多语言方案,即目录下的 i18n 文件夹,你可以为每种语言添加一个相应的 JavaScript 文件,作为键值映射数据。数据文件名应该和语言的代号一致,如 en.js 对应英语映射数据。
如: `// en.js
"use strict";
module.exports = {
open_panel: "Default Panel",
send_to_panel: "Send message to Default Panel",
description: "Extension with a panel"
};
// zh.js
"use strict";
module.exports={
open_panel:"默认面板",
send_to_panel:"发送消息给面板",
description:"含有一个面板的扩展"
};`
2、在脚本中使用
在 TypeScript 或者 JavaScript 脚本中,可通过 Editor.I18n.t 接口获取当前语言对应的翻译后的文本:
`// NOTE: my package name is "smartad_demo"
let str = Editor.I18n.t('smartad_demo.open_panel');`
3、在HTML模板中使用
在 HTML 模版里需要翻译的话可以使用 ui-label 元素进行翻译:
<ui-label value="i18n: smartad_demo.open_panel"></ui-label>
4、在JSON文件中使用
例如在扩展包的 package.json 中注册菜单路径时,只要这个字段支持 i18n 格式的路径,该路径就可以用 i18n:${key} 的形式实现多语言翻译功能:
`{
"menu": [
{
"path": "i18n:menu.panel/smartad_demo",
"label": "i18n:smartad_demo. smartad_demo",
"message": "open-panel"
},
{
"path": "i18n:menu.develop/smartad_demo",
"label": "i18n:smartad_demo.send_to_panel",
"message": "send-to-panel"
}
],
}`
五、扩展菜单添加
Cocos Creator 的主菜单是可以自由扩展的。扩展方法是在 package.json 文件中的 contributions 下面的menu 字段里,加入自己的菜单路径和菜单设置选项。
我们这里只需要一个,所以配置如下: `{
"contributions": {
"menu": [
{
"path": "i18n:menu.panel/smartad_demo",
"label": "i18n:smartad_demo.smartad_demo",
"message": "open-panel"
}
],
"messages": {
"open-panel": {
"methods": [
"openPanel"
]
}
}
},
}`
效果如图:
这里的 message 调用的是 main.ts中的openPanel方法。
六、扩展面板UI编写
1. 原型图
面板原型图如图:
2. 结构优化
为了让代码更具可读性,我们把面板分为html和css及js的方式,具体做法是在panel目录下创建index.html、index.css文件,并在index.js中引用。
目录如下:
3. 具体实现
index.css:
`#app {
padding:20px;
color: #fff;
}
a {
color:#fff;
margin: 5px;
}
h2 {
color: #fff;
text-align: center;
}
p {
font-size: 16px;
}
.btn_group {
text-align: center;
margin-top: 20px;
}
.button-item {
padding:10px 20px;
border-radius: 5px;
color: #fff;
}
#msg {
color: white;
padding: 10px;
margin-top: 20px;
font-size: 20px;
line-height: 24px;
border-radius: 5px;
word-break: break-all;
background: #000;
} `
4. 运行效果
效果如图所示
七、UIKit的使用
1. UIKit介绍
Cocos Creator 为开发者提供了非常丰富的界面元素,称为UIKit,帮助开发者快速地开发面板界面。
目前常见的界面元素包括:
- ui-button
- ui-checkbox
- ui-color
- ui-input
- ui-select
- ui-slider
- ui-text-area
全部元素见:掌握 UI Kit · Cocos Creator
2. UIKit的使用
我们这里只用 ui-button 做演示,在html中的取消和打包按钮分别如下: `取消
打包`
3. UIKit元素的获取
在面板上定义了uikit后,在js中通过$进行绑定:
`$: {
cancel_btn: '#cancel_btn',
pack_btn: '#pack_btn'
}`
使用时直接用 this.$cancel_btn即可。
八、扩展数据交互
按照第2步中的流程,接下来的操作就是用户点击“打包”按钮,开始检测构建文件,并压缩上传。
1. 事件监听
我们先来绑定按钮的点击事件,通过 addEventListener方法即可给元素添加事件:
`ready() {
this..cancel_btn && this..cancel_btn.addEventListener('click', () => {
Editor.Panel.close('smartad');
});
this..pack_btn && this..pack_btn.addEventListener('click', () => {
});
this..help_link && this..help_link.addEventListener('click', () => {
smartAd.openDefaultBrowser('www.smartad.pro/help')
});
},`
如上面的代码,我们分别给“取消”、“打包”和帮助文字添加了点击事件。
2. 调用其他模块
为了让代码更好地组织和阅读,我们把主要的逻辑写在扩展的 static/src/smartAd.js 中,这里实现了扩展的所有流程。
在面板的js中我们可以通过下面的方式对smartAd.js进行引用:
const smartAd = require(join(__dirname, '../../../static/script/smartAd'));
在“打包”按钮中进行引用:
`const _self = this;
this..pack_btn && this..pack_btn.addEventListener('click', () => {
try {
console.log("begin");
// let token = this.$token.value;
smartAd.main(function msgCallback(msg: string) {
console.log("msgCallback", msg);
if (_self.$.msg){
_self.$.msg.innerHTML = msg;
}
});
} catch (e) {
console.log(e);
}
});`
九、文件上传
文件上传使用标准的HTTP POST请求就可以实现。
1. 构建form表单
我们这里先读取文件,放在header的boundary,构建一个form-data,示例如下: `function writeBinaryPostData(req, filepath) {
var fs = require('fs'),
data = fs.readFileSync(filepath);
var crlf = "\r\n",
boundaryKey = Math.random().toString(16),
boundary = --${boundaryKey},
delimeter = ${crlf}--${boundary},
headers = [
'Content-Disposition: form-data; name="zip"; filename="cocos_zip.zip"' + crlf
],
closeDelimeter = ${delimeter}--,
multipartBody;
multipartBody = Buffer.concat([
new Buffer(delimeter + crlf + headers.join('') + crlf),
data,
new Buffer(closeDelimeter)]
);
req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
req.setHeader('Content-Length', multipartBody.length);
req.write(multipartBody);
return req;
}`
2. 发送POST请求
这里用的是node自带的https库,代码如下:
`function request_i(params, callback) {
let headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Content-type': 'application/json'
}
const url_host = config.host.replace('https://', "").replace('http://', "");
const url_path = params.url;
const options = {
hostname: url_host,
port: 443,
path: url_path,
method: 'POST',
headers: headers,
};
let req = https.request(options, res => {
console.log(statusCode: ${res.statusCode});
res.on('data', d => {
console.log(data: ${d});
callback(d);
});
});
req.on('error', error => {
console.error("error:", error);
});
req = writeBinaryPostData(req,params.zip_file)
req.end();
}`
十、打包
1. 最终的代码
最终的目录结构如下:
2. 第三方库
因为我们用到了压缩,所以需要引入第三方压缩库archiver,在package.json中引入:
`{
"dependencies": {
"fs-extra": "^10.0.0",
"archiver": "^5.3.0"
},
"devDependencies": {
"@types/node": "^16.0.1",
"@types/fs-extra": "^9.0.5",
"typescript": "^4.3.4"
},
}`
然后通过 npm install 进行安装
3. 打包
通过npm run build进行构建,会把ts文件编译成js文件,放在dist目录中。
最后把如下目录(包含node_modules)压缩为ZIP格式,并命名为扩展名称,即可。
十一、上架
1. 注册Cocos开发者账号
访问 Cocos 开发者中心 注册账号并登录
2. 填写扩展信息
- 进入 商店 栏目,点击右上方的发布新资源;
- 然后进入资源类别页面,填写名称和类别 ,勾选已阅读协议;
- 在 资源介绍 页面填写相关信息;
- 在 定价 页面设置插件的售价,包括 CNY 和 USD 两种,如果免费请填写 0;
- 在 上传资源 页面上传插件扩展包资源并填写相关信息;
3. 提交审核
填写完以上信息后,在 提交审核 页面点击 提交审核 按钮即可,一般3个工作日会有结果。
更详细的信息请参考:提交插件到商店 · Cocos Creator
十二、结束
好了,以上就是Cocos Creator 3.x 版扩展开发的相关内容,欢迎留言交流。