import * as CryptoJS from "./aes.js" import { hmacSha256 } from "./hmacSha256" /** * 工具类 */ export class Utils { public constructor() { } /** * 打乱数组 * @param arr 要打乱的数组 * @returns 打乱后的数组 */ static Shuffle(arr: Array): Array { var len = arr.length; for (var i = len - 1; i >= 0; i--) { var j = Math.floor(Math.random() * len); var temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } return arr; } /** * 获取固定长度字符串 用于太长名字截断 * @param str 原字符串 * @param len 取字符长度 * @returns 返回的字符串 */ public static cutstr(str: string, len: number): string { var str_length = 0; var str_len = 0; let str_cut = ""; str_len = str.length; for (var i = 0; i < str_len; i++) { let a = str.charAt(i); str_length++; if (escape(a).length > 4) { //中文字符的长度经编码之后大于4 str_length++; } str_cut = str_cut.concat(a); if (str_length >= len) { str_cut = str_cut.concat("..."); return str_cut; } } //如果给定字符串小于指定长度,则返回源字符串; if (str_length < len) { return str; } } /** * 取一个区间内随机整数 * @param n 开始位置 * @param m 结束位置 * @returns 返回的随机整数 */ public static rnd(n, m): number { var random = Math.floor(Math.random() * (m - n + 1) + n); return random; } static _hasOwnProperty = Object.prototype.hasOwnProperty; /** * 一个对象是否有prop属性 * @param obj 对象 * @param prop 属性 * @returns 返回是否有 */ static has(obj: any, prop: any) { return Utils._hasOwnProperty.call(obj, prop); } /** * 对比两个对象的大小 * @param a 对象a * @param b 对象b * @returns 返回值 a < b : -1, a == b : 0, a > b : 1 */ static defaultCompare(a: T, b: T): number { if (a < b) { return -1; } else if (a === b) { return 0; } else { return 1; } } /** * 将一个对象转为字符串 * @param item 传入对象 * @returns 返回值 字符串 */ static defaultToString(item: any): string { if (item === null) { return 'COLLECTION_NULL'; } else if (Utils.isUndefined(item)) { return 'COLLECTION_UNDEFINED'; } else if (Utils.isString(item)) { return '$s ' + item; } else { return '$o ' + item.toString(); } } /** * 将所有属性用字符串格式拼接起来 * @param item 要拼接属性的对象 * @param join 拼接字符 * @returns 返回值 */ static makeString(item: T, join: string = ','): string { if (item === null) { return 'COLLECTION_NULL'; } else if (Utils.isUndefined(item)) { return 'COLLECTION_UNDEFINED'; } else if (Utils.isString(item)) { return item.toString(); } else { let toret = '{'; let first = true; for (const prop in item) { if (Utils.has(item, prop)) { if (first) { first = false; } else { toret = toret + join; } toret = toret + prop + ':' + (item)[prop]; } } return toret + '}'; } } /** * 检查func是否是一个函数 * @param func 传入的参数 * @returns 返回值 bool */ static isFunction(func: any): boolean { return (typeof func) === 'function'; } /** * 检查obj是否是undefined * @param obj 传入参数 * @returns 返回值 bool */ static isUndefined(obj: any): boolean { return (typeof obj) === 'undefined'; } /** * 检查一个对象是否是字符串 * @param obj 要检查的对象 * @param 返回值 true : 是, false : 不是 */ static isString(obj: any): boolean { return Object.prototype.toString.call(obj) === '[object String]'; } /** 计算两点之间距离 */ static dis(x1, y1, x2, y2): number { return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); } /** 每角度对应弧度 */ static radian: number = Math.PI / 180; /**设置数组显示 科学计数法 */ static strShow(num: number): string { num = Math.floor(num); //最大数值保护 if (num >= 18446744073700000000) { num = 18446744073700000000 } let str = String(num); let str1 = str let len = str.length; let len1 = 0 // console.log('strShow ', str) if (len > 3 && len < 6) { str1 = str len1 = str1.length str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) } else if (len >= 6 && len < 10) { str1 = str.substr(0, len - 4) len1 = str1.length if (len1 > 3) { str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) } str1 += '万' // str = str.substr(0, len - 3) + 'K'; } else if (len >= 10 && len < 14) { str1 = str.substr(0, len - 8) len1 = str1.length if (len1 > 3) { str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) } str1 += '亿' // str = str.substr(0, len - 6) + 'B'; } else if (len >= 14 && len < 18) { str1 = str.substr(0, len - 12) len1 = str1.length if (len1 > 3) { str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) } str1 += '兆' // str = str.substr(0, len - 9) + 'KB'; } else if (len >= 18 && len < 22) { str1 = str.substr(0, len - 16) len1 = str1.length if (len1 > 3) { str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) } str1 += '万兆' // str = str.substr(0, len - 12) + 'MB'; } // else if (len >= 18 && len < 21) { // str1 = str.substr(0, len - 15) // len1 = str1.length // if (len1 > 3) { // str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) // } // str1 += 'GB' // // str = str.substr(0, len - 15) + 'GB'; // } else if (len >= 21 && len < 24) { // str1 = str.substr(0, len - 18) // len1 = str1.length // if (len1 > 3) { // str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) // } // str1 += 'TB' // // str = str.substr(0, len - 18) + 'TB'; // } else if (len >= 24 && len < 27) { // str1 = str.substr(0, len - 21) // len1 = str1.length // if (len1 > 3) { // str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) // } // str1 += 'AB' // // str = str.substr(0, len - 18) + 'TB'; // } else if (len >= 27 && len < 30) { // str1 = str.substr(0, len - 24) // len1 = str1.length // if (len1 > 3) { // str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) // } // str1 += 'BB' // // str = str.substr(0, len - 18) + 'TB'; // } else if (len >= 30 && len < 33) { // str1 = str.substr(0, len - 27) // len1 = str1.length // if (len1 > 3) { // str1 = str1.substr(0, len1 - 3) + ',' + str1.substr(len1 - 3) // } // str1 += 'CB' // // str = str.substr(0, len - 18) + 'TB'; // } //console.log("STR:" + str1); return str1; } /** * 倒计时转换为时间格式(h:m:s) ,可自定义 * @param t 秒 * @param f 格式 */ public static ParseTime2Format(t: number, f: string = "h:m:s"): string { var d: number = Math.floor(t / 24 / 3600); var h: number = Math.floor((t / 3600) % 24); var m: number = Math.floor((t % 3600) / 60); var s: number = (t % 3600) % 60; function parse_format(t: number): string { var s: string = t.toString(); if (t < 10) { s = "0" + t; } return s; } if (f.indexOf("d") != -1) { f = f.replace(/d/g, parse_format(d)); } else { h += d * 24; } if (f.indexOf("h") != -1) { f = f.replace(/h/g, parse_format(h)); } else { m += h * 60; } if (f.indexOf("m") != -1) { f = f.replace(/m/g, parse_format(m)); } else { if (f.indexOf("h") != -1) { s += m * 60; } else { s = t; } } if (f.indexOf("s") != -1) { f = f.replace(/s/g, parse_format(s)); } return f; } // 随机生成32位字符串 static randomString(len = 32) { let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' let maxPos = $chars.length let pwd = '' for (let i = 0; i < len; i++) { pwd += $chars.charAt(Math.floor(Math.random() * maxPos)) } return pwd } //说明: // 1.如果加密解密涉及到前端和后端,则这里的key要保持和后端的key一致 // 2.AES的算法模式有好几种(ECB,CBC,CFB,OFB),所以也要和后端保持一致 // 3.AES的补码方式有两种(PKS5,PKS7),所以也要和后端保持一致 // 4.AES的密钥长度有三种(128,192,256,默认是128),所以也要和后端保持一致 // 5.AES的加密结果编码方式有两种(base64和十六进制),具体怎么选择由自己定,但是加密和解密的编码方式要统一 //十六位十六进制数作为秘钥 // private static key = fun_aes.CryptoJS.enc.Utf8.parse("3454345434543454"); //十六位十六进制数作为秘钥偏移量 // private static iv = fun_aes.CryptoJS.enc.Utf8.parse('6666666666666666'); /**aes加密 * @param state true 存包长 false /r/n */ static Encrypt(word, tkey, appid, state = true) { let tiv = tkey.substr(0, 16) // n = Base64.Instance.encode(n) //明文拼接 let newStr = '' if (state) { // let n = this.pack(word.length) // newStr = tiv + n + word + appid newStr = tiv + word + appid // console.log('明文拼接 ', word.length, " n ", n) } else { newStr = tiv + word + '\r\n' + appid } //加密后 let key = CryptoJS.enc.Utf8.parse(tkey); let iv = CryptoJS.enc.Utf8.parse(tiv); newStr = CryptoJS.enc.Utf8.parse(newStr); var encrypted = CryptoJS.AES.encrypt(newStr, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); encrypted = encrypted.toString() // console.log('加密后 ', encrypted) let mac = hmacSha256.Instance.hex_hmac_sha256(tkey, encrypted) // console.log('----------------------------- ') // console.log('key ', tkey) // console.log('iv ', tiv) // console.log('mac ', mac) // console.log('encode ', encrypted) let newStrTwo = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(tiv + encrypted + mac)); // console.log('最终密文 ', newStrTwo) return newStrTwo } /** aes解密 * @param state true 存包长 false /r/n */ static Decrypt(word, tkey, appid, state = true) { let en = CryptoJS.enc.Base64.parse(word).toString(CryptoJS.enc.Utf8); let newStrOne = en.substr(16) let temp = newStrOne.substr(0, newStrOne.length - 64) let de = temp let key = CryptoJS.enc.Utf8.parse(tkey); let iv = CryptoJS.enc.Utf8.parse(tkey.substr(0, 16)); var decrypt = CryptoJS.AES.decrypt(de, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); var decryptedStr = CryptoJS.enc.Utf8.stringify(decrypt) decryptedStr = decryptedStr.toString() // console.log('decryptedStr ', decryptedStr) let newStrThree = '' if (state) { newStrThree = decryptedStr.slice(16).replace(new RegExp("(.*)" + appid), '$1') } else { newStrThree = decryptedStr.slice(16).split('\r\n')[0] } return newStrThree } /** for php pack( N , length ) */ static pack(len: number) { var buf: ArrayBuffer = new ArrayBuffer(4); var dataView = new DataView(buf); dataView.setUint32(0, len) // console.log('dataView ', dataView) let str2 = this.ab2str(buf) // let utf8decoder = new TextDecoder(); // let str2 = utf8decoder.decode(buf) // console.log('str2 ', str2) // let utf8encoder = new TextEncoder(); // let str3 = utf8encoder.encode(str2) // console.log("str3:", str3) // let str4 = utf8decoder.decode(str3) // console.log('str4 ', str4) // let aa = fun_aes.CryptoJS.enc.Utf8.parse(str2) // console.log('aa ', aa) return str2 } static Utf8ArrayToStr(array) { var out, i, len, c; var char2, char3; out = ""; len = array.length; i = 0; while (i < len) { c = array[i++]; switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx out += String.fromCharCode(c); break; case 12: case 13: // 110x xxxx 10xx xxxx char2 = array[i++]; out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: // 1110 xxxx 10xx xxxx 10xx xxxx char2 = array[i++]; char3 = array[i++]; out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break; } } return out; } //UTF-16转UTF-8 static utf16ToUtf8(s) { if (!s) { return; } var i, code, ret = [], len = s.length; for (i = 0; i < len; i++) { code = s.charCodeAt(i); if (code > 0x0 && code <= 0x7f) { //单字节 //UTF-16 0000 - 007F //UTF-8 0xxxxxxx ret.push(s.charAt(i)); } else if (code >= 0x80 && code <= 0x7ff) { //双字节 //UTF-16 0080 - 07FF //UTF-8 110xxxxx 10xxxxxx ret.push( //110xxxxx String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)), //10xxxxxx String.fromCharCode(0x80 | (code & 0x3f)) ); } else if (code >= 0x800 && code <= 0xffff) { //三字节 //UTF-16 0800 - FFFF //UTF-8 1110xxxx 10xxxxxx 10xxxxxx ret.push( //1110xxxx String.fromCharCode(0xe0 | ((code >> 12) & 0xf)), //10xxxxxx String.fromCharCode(0x80 | ((code >> 6) & 0x3f)), //10xxxxxx String.fromCharCode(0x80 | (code & 0x3f)) ); } } return ret.join(''); } //UTF-8转UTF-16 static utf8ToUtf16(s) { if (!s) { return; } var i, codes, bytes, ret = [], len = s.length; for (i = 0; i < len; i++) { codes = []; codes.push(s.charCodeAt(i)); if (((codes[0] >> 7) & 0xff) == 0x0) { //单字节 0xxxxxxx ret.push(s.charAt(i)); } else if (((codes[0] >> 5) & 0xff) == 0x6) { //双字节 110xxxxx 10xxxxxx codes.push(s.charCodeAt(++i)); bytes = []; bytes.push(codes[0] & 0x1f); bytes.push(codes[1] & 0x3f); ret.push(String.fromCharCode((bytes[0] << 6) | bytes[1])); } else if (((codes[0] >> 4) & 0xff) == 0xe) { //三字节 1110xxxx 10xxxxxx 10xxxxxx codes.push(s.charCodeAt(++i)); codes.push(s.charCodeAt(++i)); bytes = []; bytes.push((codes[0] << 4) | ((codes[1] >> 2) & 0xf)); bytes.push(((codes[1] & 0x3) << 6) | (codes[2] & 0x3f)); ret.push(String.fromCharCode((bytes[0] << 8) | bytes[1])); } } return ret.join(''); } // ArrayBuffer转为字符串,参数为ArrayBuffer对象 static ab2str(buf: ArrayBuffer) { return String.fromCharCode.apply(null, new Uint8Array(buf)); } static Uint8ArrayToString(fileData) { var dataString = ""; for (var i = 0; i < fileData.length; i++) { dataString += String.fromCharCode(fileData[i]); } return dataString } static stringToUint8Array(str) { var arr = []; for (var i = 0, j = str.length; i < j; ++i) { arr.push(str.charCodeAt(i)); } var tmpUint8Array = new Uint8Array(arr); return tmpUint8Array } // 字符串转为ArrayBuffer对象,参数为字符串 static str2ab(str) { var buf = new ArrayBuffer(str.length); // 每个字符占用2个字节 var bufView = new Uint8Array(buf); for (var i = 0, strLen = str.length; i < strLen; i++) { bufView[i] = str.charCodeAt(i); } return buf; } private static options = { default_key_size: 2048, default_public_exponent: new Uint8Array([0x01, 0x00, 0x01]) } /*rsa加密*/ static RSAEncrypt(word) { // console.log(window['JSEncrypt']) let jsb = new window['JSEncrypt'](this.options) //公钥 var publicString = '-----BEGIN PUBLIC KEY-----\n' + 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwz5V8wt525dMS+A9wOd\n' + 'NAjvKgxdyoXYuZSlAJEXLhvJlaXwFCKEsUg/qBBeo4nrRnwaFAjG7ItqbCWR9Ozv\n' + '6oY5tMYQnFFK82XkMGbKm1gG0z9vYKhcNYgHZHi+QKAw4tLLWXWO/QBTGelEXptD\n' + 'azlNmdM+8wHOknTcMuIyjc9Yo5qCoNsCJpA465vnREiBezBbKB3rSw+LmrRcZcFk\n' + 's8hmGtjpabcQ8sCxco7mRzVh6/DomNWfNm7hUP6shrrJirwjQtaS51grlScj8KhN\n' + 'h+kBoiI4Ad0Xz0GHasK5hAMf3sXDsN61r0An8KTfa/nsYSJDwogPIKkeKAsmw9Df\n' + 'EQIDAQAB\n' + '-----END PUBLIC KEY-----' jsb.setPublicKey(publicString) // 加密内容 let encrypted = jsb.encrypt(word) return encrypted } /*rsa解密*/ // static RSADecrypt(word) { // // console.log(window['JSEncrypt']) // let jsb = new JSEncrypt(this.options) // //私钥 // var privateString = '-----BEGIN RSA PRIVATE KEY-----\n' + // 'MIIEowIBAAKCAQEAuwz5V8wt525dMS+A9wOdNAjvKgxdyoXYuZSlAJEXLhvJlaXw\n' + // 'FCKEsUg/qBBeo4nrRnwaFAjG7ItqbCWR9Ozv6oY5tMYQnFFK82XkMGbKm1gG0z9v\n' + // 'YKhcNYgHZHi+QKAw4tLLWXWO/QBTGelEXptDazlNmdM+8wHOknTcMuIyjc9Yo5qC\n' + // 'oNsCJpA465vnREiBezBbKB3rSw+LmrRcZcFks8hmGtjpabcQ8sCxco7mRzVh6/Do\n' + // 'mNWfNm7hUP6shrrJirwjQtaS51grlScj8KhNh+kBoiI4Ad0Xz0GHasK5hAMf3sXD\n' + // 'sN61r0An8KTfa/nsYSJDwogPIKkeKAsmw9DfEQIDAQABAoIBAFonN6pkY5+O5uXE\n' + // '8pCbslIZGESY7z+kYT+Y8CokxBpaFD/HWb4qoO/dVakIMsT5vWcce2k6jb4GuAVl\n' + // '2kJFTKEpjnidmfXtjIVhj6jwciiLNcbtZR4eJ0s5w+5d77ywOL+qP45fhcpVNLhh\n' + // 'YK2EgesVFFzWnxl6vniCUHtJ4HnOKHJCnLNP8Jv7v8yWqRhdPv+OSnXc/f8M5Nq4\n' + // 'zXIjZIf84sQdI9MAZ4IUv3yUnhQIGCX/ilLiOb+u8Z02DnImpwrSurm4SWOl/W7F\n' + // 'jz1LHonOnFNvoICwJUlwmSHVbSxOG4dHSxs45dSHizCxIbPyHNW0sF/u5EHz2cmw\n' + // 'ZIrtmh0CgYEA91DZBmRS8f6ELIPTozOd9c9OOiW0Mn0njG2Hf59tRkUNcAVnrdT6\n' + // '1v0ziD1tnprBCQr7NKzJiU3ds4qR/Vfza2F9M894CIX3HZLZomrP+Kr0xqeogxfy\n' + // 'IVQ3n6aCIR2lKG2zBuxJJCp3UhGjS1NOOvcVqK9F+0Py6LHRG7SAoMsCgYEAwZ5l\n' + // 'Q2x/V9vDf3KMsQf/5noaPrxgoTH9py4JgCwK6ab9M8BtAsAZ4xs6RUd6XEMeGsv4\n' + // 'rLKKZhR0vMNnec/wHb3tNEFMihKsGkgCrycl4sJQIJsNX30bungrrC2XZUEAqN9g\n' + // '1IbDKAiq6l+0YQVC+742FZ6t7IgjrgV/lj7g0BMCgYEAkSeZiT/e0vvAFeR1lecY\n' + // 'wgofbs9sWOnOCYTLr2MiHskunt39QTCs3PwVf9QV/63yuF0CnaMAUp8qDVO6Zch2\n' + // 'LUM12e/eEpqWNHxZUhOA5wFn0yTaKb8nNNqaHxD6dXdR1U21cs3CDAEEsV16yx4k\n' + // '30TgKHZfC5+Q9XRQOAOUL0sCgYBcq/u78cphuwYvkhxU/4c0QW0eafu2K79ErXxO\n' + // 'pMX0X8EBbDDBCEFbukSBtFyUnGtkWAyGXE5x3YiicMSuQSCkm6tVP4vq6lUFn0Hp\n' + // 'o8s2ZdsEQDJ+adtDvRDqMEguZpZyPbiTAI2YM83asEQdy+7rn3czkeedNuwc9vTC\n' + // 'bQYdkQKBgAqApiDmh84iMQUv5DQ2ks4Ddv/jpuYp/wELTN59n+IvP7BfdkOVBcYR\n' + // 'Z1MZNo9fAIdF700ijKQKKgR1r5iOHiBo4A4DybxN3FHyS348BDbuh/dg2Z6307iS\n' + // 'cNCq6ajhNeTtMy2E14DEdinp/7l2o87OpAR2cGRFBEi+f2RRQ2p0\n' + // '-----END RSA PRIVATE KEY-----' // jsb.setPrivateKey(privateString) // // 解密内容 // let encrypted = jsb.decrypt(word) // return encrypted // } static getLocalTime(nS) { return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/, ' '); } /** 遍历打印obj属性值 * @param name 名称 * @param obj 要遍历的对象 */ static logObject(name, obj) { let description = '' for (var i in obj) { var property = obj[i]; description += i + " = " + property + "\n"; } console.log(name + ' \n' + description) } /** 版本对比 */ static versionCompareHandle(versionA, versionB) { console.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB); var vA = versionA.split('.'); var vB = versionB.split('.'); for (var i = 0; i < vA.length; ++i) { var a = parseInt(vA[i]); var b = parseInt(vB[i] || 0); if (a === b) { continue; } else { return a - b; } } if (vB.length > vA.length) { return -1; } else { return 0; } } /** 是否有apk安装包 */ static checkHasApk(fileName) { var fullPath = jsb.fileUtils.getWritablePath() + fileName if (jsb.fileUtils.isFileExist(fullPath)) { return fullPath } else { return '' } } /** 下载文件 * @param url 下载地址 * @param fileName 存储文件名称 * @param successCb 成功回调 * @param failCb 失败回调 * @param progressCb 下载进度回调 */ static downFile2Local(url, fileName, successCb, failCb, progressCb): any { var fullPath = jsb.fileUtils.getWritablePath() + fileName // showModelLoadingDialog();//显示加载中模态框 if (jsb) { var downloader = new jsb.Downloader(); downloader.setOnFileTaskSuccess(function () { // removeModelLoadingDialog();//删除加载中模态框 console.log("DownLoadM setOnFileTaskSuccess", "") if (successCb) { console.log("DownLoadM result... ", jsb.fileUtils.isFileExist(fullPath)) console.log("DownLoadM setOnFileTaskSuccess fullPath...", fullPath) successCb(fullPath); // AdM.installApp() } }); downloader.setOnTaskError(function (task: any, errorCode: number, errorCodeInternal: number, errorStr: string) { // removeModelLoadingDialog(); // showTips("文件下载失败!!!"); console.log("DownLoadM setOnTaskError", errorCode + " ; " + errorCodeInternal + " ; " + errorStr) if (failCb) { failCb(fullPath); } }); downloader.setOnTaskProgress(function (task: any, bytesReceived: number, totalBytesReceived: number, totalBytesExpected: number) { // removeModelLoadingDialog(); // showTips("文件下载失败!!!"); console.log("DownLoadM", bytesReceived + " ; " + totalBytesReceived + " ; " + totalBytesExpected) if (progressCb) { progressCb(bytesReceived, totalBytesReceived, totalBytesExpected) } }); downloader.createDownloadFileTask(url, fullPath);//创建下载任务 return downloader } } static loadResPromise(url, type: any = cc.Prefab) { return new Promise((resolve: (data) => void, reject) => { cc.loader.loadRes(url, type, (error, data): void => { if (error) { reject(); } else { resolve(data); } }); }); } }