ios环境下加载远程资源时抛出SecurityError的解决

背景:

        最近对一个旧项目做引擎升级,该项目是一个cocos creator做的小游戏,被另一个项目(cocos2dx搭配原生)当作子功能打开。

        之前小游戏中加载远程资源的过程是:发送请求至原生层,原生层下载远程资源并缓存后将缓存后的文件名回传给小游戏,小游戏使用cc.loader.load(cc.url.raw("resources/" + path))读取设备本地的缓存资源使用。但由于引擎升级(2.0.1 >> 2.4.9),上述接口被淘汰,resources更是一个内置bundle的名字导致加载失败。而新端上线也没有强更的打算所以需要小游戏内做兼容。

        android下兼容比较方便,直接使用cc.assetManager.loadRemote的方式下载远程资源,但这种方式在ios下加载远程的图片url时会抛出 SecurityError ,由于安全政策导致图片加载失败。

解决:

        查询一番后确定方向决定使用类似网页前端的方式使用base64加载远程图片url。参考链接

ps:链接中answer的评论里有人提出可以使用 Buffer.from(response, 'base64').toString('base64')的方式来得到下文中的content,然鹅这种方式需要Node的支持。

new Promise<boolean>(resolve => {
    const xhr = cc.loader.getXMLHttpRequest(), errInfo = "Load binary data failed: " + url;
    xhr.open("GET", url, true);
    xhr.responseType = "arraybuffer";
    xhr.onload = async function () {
        const response = xhr.response;
        if (response) {
            try {
                let binary = "";
                const bytes = new Uint8Array(response);
                for (let i = 0; i < bytes.byteLength; i++) {
                    binary += String.fromCharCode(bytes[i]);
                }
                const content = window.btoa(binary);
                const base64str = `data:image/png;base64,` + content;
                const str = Base64Decode(content);
                const wh = ToolsUtil.getPngWidthAndHeight(str);
                const texture = await ToolsUtil.loadTextureFromCache(base64str, wh[0], wh[1]);
                if (texture && cc.isValid(sprite)) {
                    sprite.spriteFrame = new cc.SpriteFrame(texture);
                }

                resolve(true);
            } catch (error) {
                console.info("=== 文件下载成功但解析报错: ", error);
                resolve(false);
            }
        }
        else {
            console.info("=== 文件下载失败111");
            resolve(false);
        }
    };
    xhr.onerror = function () {
        console.info("=== 文件下载失败222");
        resolve(false);
    };
    xhr.ontimeout = function () {
        console.info("=== 文件下载失败333");
        resolve(false);
    };
    xhr.send(null);
});

加载后此时还不能在cocos中直接使用,需要生成cc.Texture对象。

//    获取图片尺寸
private static getPngWidthAndHeight(content: any): number[] {
        const paddingZero = (str: String) => {
            while (str.length < 8) {
                str = '0' + str;
            }

            return str;
        };

        let widthString = "",
            heightString = "";
        for (let i = 0; i < 4; i++) {
            widthString += paddingZero(content[16 + i].charCodeAt().toString(2));
            heightString += paddingZero(content[20 + i].charCodeAt().toString(2));
        }

        let width = parseInt(widthString, 2);
        let height = parseInt(heightString, 2);
        return [width, height];
    }

//    使用类似document的方式生成cc.Texture
private static loadTextureFromCache(pngContent: any, width: number, height: number) {
        return new Promise<cc.Texture2D>((resolve) => {
            const texture = new cc.Texture2D();
            const imgElement = new Image();
            imgElement.src = pngContent;

            imgElement.onload = () => {
                texture.initWithElement(imgElement);
                texture.handleLoadedTexture();
                texture.width = width;
                texture.height = height;
                resolve(texture);
            };
        });
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值