Egret社区
本帖最后由 落幕夜未央 于 2018-2-6 15:29 编辑

我们在网上找的第三方库,因为库的作者可能要兼容不同的环境,比如node,和浏览器环境,同时浏览器中还分了多种库的加载规范,比如commonjs,amd,cmd等等。
但就是因为这些兼容处理,在微信小游戏中会出问题。
新建一个h5工程,然后发布成微信小游戏工程,在微信开发者工具中打开,然后再微信开发者工具的控制台中依次测试以下变量或者表达式:
window,global,__global,this,self,define,define.cmd,module,module.exports
输出的结果我们可以 看到,window,this,self都有值且相等,global是一个空的Object对象,__global有值切不等于window,self,this,global。define有定义,但是define.cmd未定义。module和module.exports都是undefined。
1.png
知道了这些就好说了。我们别管那么多兼容的,h5和微信小游戏中我们只要保证想要的内容定义在window上就行,那么这个库就能同时兼容h5和微信小游戏。下面这些库的修改也就是围绕着一点展开的。

注意:以下各个库要在第三方库工程目录下修改源码,然后调用egret build,然后到h5工程去执行egret clean。然后再执行egret publish -target wxgame。不要直接修改微信小游戏工程目录下的相关文件。否则再次发布,相关修改会被覆盖。

zlib
zlib库是从https://github.com/imaya/zlib.js找的。进入这个github地址,然后在bin目录下找到zlib.min.js。用文本编辑器打开zlib.min.js,可以看到最后一行,自执行传入的参数是this,直接给替换成window。代码里面的用法不变。

JSZIP
jszip我原来用的是白鹭第三方库的github仓库里面的。但是我js功底还是太薄了,改来改去,jszip还是一直在微信小游戏里面报错。。。无赖,换个zip解压缩库。
我换的是uzip(游戏中很少有压缩需求吧,一般都是解压缩zip,所以只用unzip)地址:https://github.com/imaya/zlib.js,还是找到bin/unzip.min.js,用文本编辑器打开unzip.min.js,可以看到最后一行,自执行传入的参数是this,直接给替换成window。
假设有个configs.zip,在资源配置文件中的name是configs,configs.zip中的文件是包含在configs目录下的。记得设置configs.zip的加载类型为bin类型。。。
原来用jszip解压缩一个压缩包的相关代码如下:
[JavaScript] 纯文本查看 复制代码
//configs.zip解析
let configsZip: JSZip = new JSZip(RES.getRes("configs"));
let zipFiles: Array<JSZipObject> = configsZip.file(/configs/);
let fileShortName: string;
let zipFile: JSZipObject = null;
for (zipFile of zipFiles) {
     console.log(zipFile.asText());//zipFile.asText,zipFile.asJson
}

换成unzip解压缩这个zip的代码如下:
[JavaScript] 纯文本查看 复制代码
//临时用unzip来解析
let zipFileMap: Object = UnzipHelper.parseZipSubFiles(RES.getRes("configs"));
for (let zipFileName in zipFileMap) {
      let fileShortName = this.parseZipFileShortName(zipFileName);
      Resource.saveRes(fileShortName, zipFileMap[zipFileName]);
}

其中UnzipHelper是一个小工具函数:
[JavaScript] 纯文本查看 复制代码
/**
 * @User: liuliqianxiao
 * @Date: 2018/2/2
 * @Time: 下午3:15
 * @Desc: uzip的辅助工具类
 **/
class UnzipHelper {

    /**
     *
     * @param {ArrayBuffer} originalData
     * @param {"json" | "txt"} format 是要把内容解析成txt还是解析成json
     * @returns {Object}
     */
    public static parseZipSubFiles(originalData: ArrayBuffer, format: "json" | "txt" = "txt"): Object {
        let result: Object = {};
        let originalBytes: Uint8Array = new Uint8Array(originalData);
        let configZip: Zlib.Unzip = new Zlib.Unzip(originalBytes, {verify: false});
        let fileNames: Array<string> = configZip.getFilenames();
        fileNames.forEach((fileName) => {
            let fileData: Uint8Array = configZip.decompress(fileName) as Uint8Array;
            let byteArray: egret.ByteArray = new egret.ByteArray(fileData);
            let fileStr: string = byteArray.readUTFBytes(byteArray.bytesAvailable);
            switch (format) {
                case "json":
                    result[fileName] = JSON.parse(fileStr);
                    break;
                default:
                    result[fileName] = fileStr;
                    break;
            }
        });
        return result;
    }

}


CryptoJS
加密解密库:https://github.com/brix/crypto-js。按需找出你需要的库文件,然后按照白鹭的第三方库规范做成自己的库工程。
在h5工程的scripts/wxgame/wxgame.ts中修改onFile函数如下:
[AppleScript] 纯文本查看 复制代码
if (filename == 'libs/modules/egret/egret.js' || filename == 'libs/modules/egret/egret.min.js') {
                let content = file.contents.toString();
                content += `;window.egret = egret;`;
                content = content.replace(/definition = __global/, "definition = window");
                file.contents = new Buffer(content);
            }
            else if(filename == 'libs/modules/encrypt/encrypt.js' || filename == 'libs/modules/encrypt/encrypt.min.js'){
                let content = file.contents.toString();
                content = "var egret = window.egret;" + content;
                content += ";window.CryptoJS = CryptoJS;";
                file.contents = new Buffer(content);
            }
            else {.....}

其中else if(filename == 'libs/modules/encrypt/encrypt.js' || filename == 'libs/modules/encrypt/encrypt.min.js'){
这个分支的代码就是我们处理加密解密库的,文件名/路径换成你自己的即可

greensock
白鹭第三方库合集的github上就有这个,地址我就不贴了。
greensock这个库的报错主要是因为在微信小游戏上,所有的类比如TweenLite,TweenMax都是定义在global对象上。这就尴尬了。我们需要把这些东西重新定义在window对象上,就不需要修改任何游戏逻辑代码了。
还是修改我们的发布插件吧,在h5工程的scripts/wxgame/wxgame.ts中修改onFile函数最后一个else分支如下:
[JavaScript] 纯文本查看 复制代码
else {
                let content = file.contents.toString();
                if (
                    filename == "libs/modules/res/res.js" ||
                    filename == 'libs/modules/res/res.min.js' ||
                    filename == 'libs/modules/assetsmanager/assetsmanager.min.js' ||
                    filename == 'libs/modules/assetsmanager/assetsmanager.js'
                ) {
                    content += ";window.RES = RES;"
                }
                if (filename == "libs/modules/eui/eui.js" || filename == 'libs/modules/eui/eui.min.js') {
                    content += ";window.eui = eui;"
                }
                if (filename == 'libs/modules/dragonBones/dragonBones.js' || filename == 'libs/modules/dragonBones/dragonBones.min.js') {
                    content += ';window.dragonBones = dragonBones';
                }
                //greensock对象定义位置修改
                if(filename == 'libs/modules/greensock/greensock.js' || filename == 'libs/modules/greensock/greensock.min.js'){
                    content += ';Object.assign(window,window.global);';
                }
                content = "var egret = window.egret;" + content;
                if (filename == 'main.js') {
                    content += ";window.Main = Main;";
                }
                file.contents = new Buffer(content);
            }

注释位置下面的那个if分支就是处理greensock的。注意,吧global对象上定义的TweenLite相关转移到window对象上之后,你不能window.global=undefined;
再最开头,我们测试过,即使没有引入greensock,global也是存在的。。。

ProtoBuf
protobuf库没啥好说的,换官方新出的那个pb-egret吧。。代码暴增,进一步让使用了protobuf协议的中大型游戏转成微信小游戏成为不可能。
原来在h5中我们可以直接加载*.proto协议源文件,然后调用pb库通过反射机制来处理。而现在必须通过硬代码的方式,代码能不暴涨吗。
但是我们可以适当优化一下pbjs生成的协议代码的。(这已经不是库适配问题了。。属于优化相关的内容。。)
现在官方默认生成的协议代码包含了很多无用的函数,这部分我们其实可以删掉的,不是手动删,而是有方法的,且听我慢慢说。。
假设你已经按照pb-egret库说的步骤,安装了protobuf6.8,pb-egret等等。。
第一步:打开一个终端,输入pbjs,拖到最下面,是不是发现有如下一些控制参数,是不是很惊喜……
2.png
几个参数的英文应该是简单明了的,对比一下你生成的pb协议代码文件,一下子就明白了。
第二步:我们得对我们的游戏逻辑代码做一些修改,尽量只调用encode编码,decode解码这两个函数,其他的verify(这个只是为了验证数据合法性的),fromObject等等都没必要调用。。
第三步:找到你自己的pb-egret 这个node模块的安装目录,在protobuf/out下打开index.js编辑源码:
找到generate函数,修改case 14:这个分支如下:
[JavaScript] 纯文本查看 复制代码
case 14:
                    _a.sent();
                    args = ['-t', 'static', '-p', protoRoot, protoList.join(" "), '-o', tempfile];
                    if (pbconfig.options['no-create']) {
                        args.unshift('--no-create');
                    }
                    if (pbconfig.options['no-verify']) {
                        args.unshift('--no-verify');
                    }
                    if (pbconfig.options['no-convert']) {
                        args.unshift('--no-convert');
                    }
                    if (pbconfig.options['no-delimited']) {
                        args.unshift('--no-delimited');
                    }
if (pbconfig.options['no-encode']) {
args.unshift('--no-encode');
}
if (pbconfig.options['no-decode']) {
args.unshift('--no-decode');
}
                    return [4 /*yield*/, shell('pbjs', args)];

pbjs还有两个参数是--no-beautify和--no-comments这两个是控制输出样式以及注释的。实际我们发布的时候第三方库压缩混淆的时候会自动处理
第四步:H5项目/protobuf/pbconfig.json中修改options如下:
[JavaScript] 纯文本查看 复制代码
"options": {
    "no-create": true,
    "no-verify": true,
    "no-convert": true,
    "no-delimited": true,
    "no-encode": false,
    "no-decode": false
  },

第三步中修改pb-egret的源码就是为了这里多增加的几个参数能传递到pg-egret中去,进一步控制pbjs的调用。
根据你自己的项目需要,自行调整上述options中的相关开关参数。对比一下生成的协议js代码,看看是不是能优化掉一部分代码呢。

//追更==============================================================================================
JSZIP上面jszip库终于找到原汁原味的解决方式了,不用替换成unzip来解压缩zip了。
用ide打开jszip.min.js,看上面一大段适配各种环境的代码:
[JavaScript] 纯文本查看 复制代码
if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof __global?b=__global:"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.JSZip=a()}}

这个逻辑按说是合理的,但是发布成微信小游戏之后,逻辑貌似不对。
不用想太多,暴力删除上面一大段代码,改成window.JSZip=a();发布小游戏,jszip终于能正常使用了。
其他类似的库在参照官方做法吧定义暴露到全局之后如果还有问题,不妨参考下我这种处理。

【大提示】
某些第三方库的修改方式仅仅只照顾到了h5和微信小游戏的,并不能兼容所有,算是暴力解决方式。


假期将近,我心飞扬~完全不想写代码。。。





分享到 :
28 人收藏

32 个回复

倒序浏览
jet66  圆转纯熟 | 2018-2-6 10:51:16



官方不知道搞什么飞机,都没个好的方案吗????????????????


就这么一直放着等小游戏开放才急起来吗????????????????


有些很无语
wllinger  登堂入室 | 2018-3-21 15:06:31

果断收藏
落幕夜未央  圆转纯熟 | 2018-3-21 15:10:32

这么好的贴,官方小哥哥也不来给人家加精。。弄得我都想手动@App小王子了
app小王子  社区管理员 | 2018-3-22 10:37:43
落幕夜未央 发表于 2018-3-21 15:10
这么好的贴,官方小哥哥也不来给人家加精。。弄得我都想手动@App小王子了 ...

你说加,那就加一个。。。这个确实很给力
xjn9854262  登堂入室 | 2018-3-23 18:14:48
不错 赞一个
skybearr  圆转纯熟 | 2018-4-4 10:58:33
JSZIP上面jszip库终于找到原汁原味的解决方式了,不用替换成unzip来解压缩zip了。
用ide打开jszip.min.js,看上面一大段适配各种环境的代码:

这个应该是jszip.js里的第一个方法
李英俊是大可爱  登堂入室 | 2018-4-4 12:24:23
skybearr 发表于 2018-4-4 10:58
JSZIP上面jszip库终于找到原汁原味的解决方式了,不用替换成unzip来解压缩zip了。
用ide打开jszip.min.js, ...

什么意思呀 ,具体怎么弄呢
落幕夜未央  圆转纯熟 | 2018-4-4 19:55:41
李英俊是大可爱 发表于 2018-4-4 12:24
什么意思呀 ,具体怎么弄呢

本篇最后有详细说明呀
李英俊是大可爱  登堂入室 | 2018-4-9 17:44:12
落幕夜未央 发表于 2018-4-4 19:55
本篇最后有详细说明呀

谢谢,很给力
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|京网文[2014]0791-191号|京ICP证150115号|Egret社区 ( 京ICP备14025619号

Powered by Discuz! X3.2 © 2001-2019 Comsenz Inc.

返回顶部