合作咨询
我们的专家服务团队将竭诚为您提供专业的合作咨询服务
现象描述
快游戏加载大量资源时,使用qg.downloadFile接口远程下载服务端的zip压缩文件资源,无法正常下载、解压。
问题分析
无法正常下载、解压文件可能有如下原因:
filePath是选填参数,如果调用接口没有传入,文件存放于临时路径,需访问在success回调中获取的临时路径获取文件。
filePath的格式要求为:文件存放路径+文件名称
解决方法
success(res) {
let filePath = res.tempFilePath;
}qg.downloadFile({
url: "http://127.0.0.1:8080/docs/test.zip",
filePath:qg.env.USER_DATA_PATH +"/sdcard/Pictures/Screenshots/test.zip",
success() {
console.log("success");
},
fail(e) {
console.error(e.errMsg);
},
complete() {
console.log("complete");
}
});var filePath = res.filePath //获取的下载后的zip文件
var fileSystemManager = qg.getFileSystemManager();
fileSystemManager.unzip({
zipFilePath: filePath,
targetPath: qg.env.USER_DATA_PATH +"/test",
success(res) {
console.log("unzip success!");
},
fail(e) {
console.log("unzip fail :", e.errMsg);
}
});现象描述
laya游戏打包成华为快游戏后,出现游戏屏幕无法满屏的情况,如下图所示:

问题分析
出现此问题一般可能是打包前没有修改屏幕适配的代码,或者采用的适配方式没有根据屏幕灵活修改。
解决方法
首先确认当前游戏的屏幕设计模式scaleMode,一般打包前需要针对不同模式做一些全屏适配的操作。当前主流设计模式有exactfit,fixedwidth,fixedheight三种。
针对以上几种scaleMode,打包华为快游戏时,针对不同的laya版本分别有不同的屏幕适配方法。
在huawei-adapter.js中提供了适配方法,开发者只需要引入huawei-adapter.js,然后在游戏入口处code.js文件中Laya.init后面添加屏幕适配代码,重新定义游戏舞台和设计宽高。
window.getAdapterInfo = function (config) {
let scaleX = 1;
let scaleY = 1;
let vw = window.innerWidth;
let vh = window.innerHeight;
let w = config.width;
let h = config.height;
config.scaleMode = config.scaleMode.toLowerCase();
switch (config.scaleMode) {
case "exactfit":
scaleX = vw / w;
scaleY = vh / h;
break;
case "fixedwidth":
scaleX = scaleY = vw / w;
break;
}
return {
scaleX: scaleX,
scaleY: scaleY,
w: w,
h: h,
vw: vw,
vh: vh,
rw: w * scaleX,
rh: h * scaleY
};
};
Laya.init(600, 400, WebGL);// 600 400 需要修改成游戏的设计尺寸
Laya.stage.scaleMode = "exactfit";//exactfit只是示例值,需要修改为本身游戏中的值
//屏幕适配
if(typeof getAdapterInfo !== "undefined"){
var stage = Laya.stage;
var info = getAdapterInfo({width:600, height:400, scaleMode:"exactfit"});// 600 400 需要修改成游戏的设计尺寸
stage.designWidth = info.w;
stage.designHeight = info.h;
stage.width = info.rw;
stage.height = info.rh;
stage.scale(info.scaleX, info.scaleY);
}
//屏幕适配结束在bundle.js文件中程序入口后面添加屏幕适配代码,示例代码如下:
//程序入口
//根据IDE设置初始化引擎
if (window["Laya3D"]) Laya3D.init(GameConfig.width, GameConfig.height);
else Laya.init(GameConfig.width, GameConfig.height, Laya["WebGL"]);
Laya["Physics"] && Laya["Physics"].enable();
Laya["DebugPanel"] && Laya["DebugPanel"].enable();
Laya.stage.scaleMode = GameConfig.scaleMode;
Laya.stage.screenMode = GameConfig.screenMode;
Laya.stage.alignV = GameConfig.alignV;
Laya.stage.alignH = GameConfig.alignH;
//屏幕适配
if (typeof getAdapterInfo !== "undefined") {
var stage = Laya.stage;
var info = getAdapterInfo({ width: GameConfig.width, height: GameConfig.height, scaleMode: GameConfig.scaleMode });
//注意:其中 GameConfig.width 和 GameConfig.height 为该demo中设置游戏的宽和高,请根据实际项目填写
stage.designWidth = info.w;
stage.designHeight = info.h;
stage.width = info.rw;
stage.height = info.rh;
stage.scale(info.scaleX, info.scaleY);
}
//屏幕适配结束如果以上方式都无法适配游戏屏幕,在laya2.0以上版本可以通过开启视网膜画布适配方式来调整游戏屏幕适配,示例代码如下:
//程序入口
//根据IDE设置初始化引擎
if (window["Laya3D"]) Laya3D.init(GameConfig.width, GameConfig.height);
else Laya.init(GameConfig.width, GameConfig.height, Laya["WebGL"]);
Laya["Physics"] && Laya["Physics"].enable();
Laya["DebugPanel"] && Laya["DebugPanel"].enable();
Laya.stage.scaleMode = GameConfig.scaleMode;
Laya.stage.screenMode = GameConfig.screenMode;
Laya.stage.alignV = GameConfig.alignV;
Laya.stage.alignH = GameConfig.alignH;
//屏幕适配
if(typeof qg !== 'undefined'){
Laya.stage.useRetinalCanvas = true;
}
//屏幕适配结束 适配后,游戏正常全屏的效果如下:

"minPlatformVersion": 1078
let bannerAd = qg.createBannerAd({
adUnitId: 'testw6vs28auh3',
style:{
top:20,
left:20,
height:57,
width:360
}
}) 其中width和height是广告图片本身的宽度与高度,单位dp,该值一般是固定且提前可以获取。top和left是banner广告左上角的坐标,是需要动态设置的值。
由于每个手机自身的屏幕尺寸和分辨率大小不同,所以需要使用getSystemInfoSync获取当前手机屏幕的高度和宽度。
通过qg.getSystemInfoSync接口获取safeArea,safeArea是object对象,safeArea.height是手机高度,数值大小是以dp为单位,正好和广告高度单位匹配,使用safeArea.height减去广告高度就等于要设置的top值。
createBannerAd() {
//获取手机详细参数
var sysInfo = qg.getSystemInfoSync();
console.log("on getSystemInfoSync: success =" + JSON.stringify(sysInfo));
//获取当前手机屏幕高度(dp)
let bannerTop = sysInfo.safeArea.height
let bannerAd = qg.createBannerAd({
adUnitId: 'testw6vs28auh3',
style:{
//top需要手机屏幕高度减去广告本身高度
top:bannerTop-57
left:0,
height:57,
width:360
}
});
setTimeout(function () {
bannerAd.show()
}, 1000);
} 使用3.2.1.300及以上版本的华为快应用加载器运行,最终效果图如下:

现象描述
快游戏调用qg.loadSubpackage接口下载rpk中的分包时报错,提示“run root entry script error”或“can not find root script”。
问题分析
解决方法
请排查以下几点:
现象描述
快游戏调用qg.loadSubpackage接口下载rpk中的分包后,调用onprogress监听下载进度,发现无法打印onprogress回调进度。引擎日志信息如下所示:

问题分析
关于分包无进度条回调,有以下三种情况:
如果manifest.json文件中没有声明subpackages字段,说明rpk未分包。则无分包下载过程,无进度条回调。
本地rpk没有拆包过程,分包代码存在于完整的rpk软件包中,无需进行分包下载,所以无进度条回调。
玩家在快应用中心首次打开的是rpk的主包,进入应用主界面。当进入不同场景时,会触发分包场景,下载当前场景对应的分包代码。
如果单个分包过小,网络环境良好时下载速度过快,在onProgressUpdate接口未回调成功前就下载完成,则不会触发进度条回调。
解决方法
按照要求分包,上架后由华为服务器进行拆包,且单个分包足够大(建议在1mb以上),则会正常触发进度条回调。引擎日志信息如下所示:

现象描述
在测试华为托管支付接口时,已成功购买,但是调用obtainOwnedPurchases查询已购商品信息时,返回结果中inAppPurchaseDataList参数为空,没有购买信息。
问题代码如下:
function obtainOwnedPurchases (){
var priceType = document.getElementById("priceType")
var params = { ownedPurchasesReq: {"priceType": 0,"applicationID": "100798021",
"publicKey":"XXX"}}
HwFastappObject.obtainOwnedPurchases(JSON.stringify(params));
} 接口返回信息如下:
onObtainOwnedPurchasesResult:{"code":0,"data":"{\"returnCode\":0,\"inAppSignature\":[],\"inAppPurchaseDataList\":[],\"errMsg\":\"success\",\"itemList\":[\"Product1\"]}"}
问题分析
该接口是返回用户已经购买的商品信息,若没有返回,则肯定是入参错误。检查obtainOwnedPurchases接口的参数。
解决方法
检查参数是否传递错误,尤其是publicKey值,可参见“开通应用内支付服务”中的“使用支付3.0接口” 获取正确的publicKey。
当参数传递正确时,接口调用成功,返回信息如下:
onObtainOwnedPurchasesResult:{"code":0,"data":"{\"returnCode\":0,\"inAppSignature\":[\"KDCZHaie/+UMFS8etxpP8igrEvZWCCYRdO+luu0f1n95WzAjBMDj1IRWkYqqRVPcGlKik/9JM+etjW/4wca0Z+kvr0QkRnUhJIGSyOPlK3H0BCROk+D4HCBxIfYOm3pcS35pXcuaiT8i9oSpuYaL2ttgCkQ7EqlOFR1WUwhQppkmnm6eHwy9i9lFLOc54QNubOmZpHh5DjOiMcdaRKaJ5VHRkj/LA11CILY1IvTnsfkurzlyhEYrS9CfkyL08HJJGBGVjabBETdbyuDkBGSWC8R0XpHjHh59gtcFAhJ4jOI1+7Tzb4s1MAdExrZ5dfoOQPFVgGRIk2TSMuWCE5W+pyOMdolMPDWsqwynDfyrgT+7+8WRo7SmASl8lROhywm5ZHayfTFylGc+mm49tOh0QbSeRv2jvvpVUvVD6qpGrxQZ5sVlytSOT8yUSVRd5ZlX1CLW+41k5+5/n2K7nDis4NsxAl596PeNg0B8NtM+xuJUWrxgYulaVkXXwgKoRcL5\"],\"inAppPurchaseDataList\":[\"{\\\"autoRenewing\\\":false,\\\"orderId\\\":\\\"20210531100004617f8e860501.100798021\\\",\\\"packageName\\\":\\\"com.huawei.fastapp.dev\\\",\\\"applicationId\\\":100798021,\\\"kind\\\":0,\\\"productId\\\":\\\"Product1\\\",\\\"productName\\\":\\\"gold\\\",\\\"purchaseTime\\\":1622426407000,\\\"purchaseTimeMillis\\\":1622426407000,\\\"purchaseState\\\":0,\\\"developerPayload\\\":\\\"testPurchase\\\",\\\"purchaseToken\\\":\\\"00000179c02651167921efb13f3ee6d5adf42045c55a0427313b53a168c045ae459661f8ccdc8280x434e.1.100798021\\\",\\\"consumptionState\\\":0,\\\"confirmed\\\":0,\\\"purchaseType\\\":0,\\\"currency\\\":\\\"CNY\\\",\\\"price\\\":100,\\\"country\\\":\\\"CN\\\",\\\"payOrderId\\\":\\\"sandbox20210531100007156C0B6B9\\\",\\\"payType\\\":\\\"31\\\",\\\"sdkChannel\\\":\\\"1\\\"}\"],\"errMsg\":\"success\",\"itemList\":[\"Product1\"]}"}
现象描述
使用egret打包开发的快游戏,不使用华为分包加载时,游戏正常运行;使用分包加载时,游戏无法加载资源。
分包代码如下:
console.log("开始加载分包代码");
var sysInfo = qg.getSystemInfoSync();
var obj = {};
if (typeof qg.loadSubpackage == "function") {
var subTask2 = qg.loadSubpackage({
// manifest.json中配置的子包包名
subpackage: "stage2",
// 子包加载成功回调
success: function () {
console.log("加载分包2成功!");
},
fail: function () {
console.log("加载分包2失败"), callback2(false);
}
})
subTask2.onprogress = function callback(res) {
console.log("进入onprogress,function",progback);
if (typeof progback == "function") {
console.log("onprogress2" + JSON.stringify(res));
progback(res, 2);
}
}
setTimeout(() => {
var subTask1 = qg.loadSubpackage({
// manifest.json中配置的子包包名
subpackage: "stage1",
// 子包加载成功回调
success: function (res) {
console.log("加载分包1成功!");
},
fail: function (res) {
console.log("加载分包1失败"), callback2(false);
}
})
subTask1.onprogress = function callback(res) {
if (typeof progback == "function") {
console.log("onprogress1" + JSON.stringify(res));
progback(res, 1);
}
}
}, 200);
} 下载分包完成后,加载分包内资源代码如下:
else if (this.currDate.type == LoadingType.TYPE_6) {//加载皮肤
let theme = new eui.Theme(this.currDate.url,LoadingManager.$stage);
theme.addEventListener(eui.UIEvent.COMPLETE,this.__onThemeLoadComplete,this);
} 游戏运行现象和日志显示:分包代码下载成功,加载分包内资源没有进入成功回调,无法加载资源。
07-06 16:31:08.508 I/jsLog ( 9097): enter---subpackage 07-06 16:31:08.510 I/jsLog ( 9097): 5 0 undefined 07-06 16:31:08.558 I/jsLog ( 9097): _onLoadSubpackageFinished 07-06 16:31:08.558 I/jsLog ( 9097): 加载分包2成功! 07-06 16:31:08.721 I/jsLog ( 9097): enter---subpackage 07-06 16:31:08.773 I/jsLog ( 9097): _onLoadSubpackageFinished 07-06 16:31:08.774 I/jsLog ( 9097): 加载分包1成功! 07-06 16:31:08.924 I/jsLog ( 9097): enter---subpackage 07-06 16:31:08.977 I/jsLog ( 9097): _onLoadSubpackageFinished 07-06 16:31:08.977 I/jsLog ( 9097): 加载分包3成功! 07-06 16:31:09.124 I/jsLog ( 9097): enter---subpackage 07-06 16:31:09.175 I/jsLog ( 9097): _onLoadSubpackageFinished 07-06 16:31:09.175 I/jsLog ( 9097): 加载分包4成功! 07-06 16:31:09.317 I/jsLog ( 9097): enter---subpackage 07-06 16:31:09.375 I/jsLog ( 9097): _onLoadSubpackageFinished 07-06 16:31:09.375 I/jsLog ( 9097): 加载分包5成功! 07-06 16:31:09.375 I/jsLog ( 9097): 加载代码完成 07-06 16:31:09.376 I/jsLog ( 9097): ---------加载皮肤----------------- [object Object] 07-06 16:31:09.380 I/jsLog ( 9097): ---------加载皮肤currData----------------- resource/default.thm.json 07-06 16:31:09.380 I/jsLog ( 9097): ---------加载皮肤LoadingManager.$stage----------------- [object Object] 07-06 16:31:09.380 I/jsLog ( 9097): 6 3 undefined
问题分析
如下日志显示:分包下载的js代码均不在app的包里,后面又出现“filePath is invalid”,据此猜测系统进程没有读取到这些js代码,初步判断加载失败和引用代码路径有关。

分包体如下图:

分包入口game.js代码如下图:

最终问题定位为game.js中代码引用路径出错。
解决方法
game.js在引入分包的其他js文件时,js路径需从当前根目录算起。
例如:项目目录下stage1分包里有game.js和main.js,那么game.js引入main.js时,需写成require('stage1/main.js')。
建议与总结
分包问题,我们可以从分包代码qg.loadSubpackage、分包本身资源文件、加载分包代码和其引用代码来分析。结合相应报错日志,从而一步步找到出错点。
现象描述
使用Cocos引擎工具远程加载图片时,以jpg,png等结尾的图片地址均可以正常加载,但是图片地址没有后缀时加载报错,手动加上其他后缀又请求不到图片。
问题分析
当前的 Cocos Creator 支持加载远程资源,开发者可以直接使用 cc.assetManager.loadRemote 方法。具体可参见官网中loadRemote方法的详细介绍。
该接口有三个参数,url是String类型的远程资源的地址,options是可选的对象参数,用于手动指定加载资源的类型,onComplete是加载完成后触发的回调函数。
解决方法
加载报错,可能是传参问题,建议使用如下代码加载图片资源:
loadPics(){
var remoteUrl= "https://sf6-be-pack.pglstatp-toutiao.com/obj/ad.union.api/06d885572f1c64092678bf6cbadb281b"
cc.assetManager.loadRemote(remoteUrl,{ext:".png"},(err, texture)=>{
console.log("err"+err);
var spriteFrame=new cc.SpriteFrame(texture);
this.sprite_node.getComponent(cc.Sprite).spriteFrame=spriteFrame;
this.sprite_node.active=true;
});
}, 现象描述
广告审核驳回原因:原生广告中存在多余请求。
问题分析
广告存在多余请求,一般是广告日志中广告请求数量多于界面中广告显示数量。
解决方法
通过查看广告日志来比较广告请求数量和广告显示数量。
广告日志中,request data是广告请求消息。在日志中搜索clientAdRequestId(广告请求ID)可查看具体请求数量,然后重点关注reqPurpose(广告请求目的),该字段取值有2种情况:
大部分广告是请求后需要立即展示,因此可以拿这个数量和应用或游戏界面的广告具体数量做比较。
即adtype(请求广告类型,8--banner, 7--激励视频,3--原生,1--开屏,12--插屏)为7或者12时,才会查看reqPurpose为2的情况。

当广告存在多余请求时,我们一般比较日志中reqPurpose的数量和应用或游戏界面中原生、banner等广告展示的数量。可以在每个场景中去对比数量,快速找出问题点,从而迅速修复。可能出现以下三种情况:
需要修改为立即展示。
正常情况下不管是成功还是失败都不要再次发起请求。
不要在onHide里写请求广告的方法,只在onShow中请求广告。
现象描述
广告审核驳回原因:有原生广告展示,但是存在多余的上报曝光事件。
问题分析
广告存在多余上报曝光,一般是广告日志中广告上报曝光数量多于界面中广告显示数量。
解决方法
通过查看广告日志来比较广告上报曝光数量和广告显示数量。
在广告日志中搜索关键字“addEventToCache, event:imp”。
需要注意的是,原生广告只要展示一次,就需要上报曝光一次。但是banner如果设置了自动刷新(比如30s,如下图红框所示),导致的周期性上报曝光不算重复曝光事件。

面对广告存在多余上报曝光时,我们一般比较日志中addEventToCache, event:imp的数量和应用或游戏界面中原生、banner等广告展示的数量。可以在每个场景中去对比数量,快速找出问题点,从而迅速修复。
可检查以下场景是否按照要求正确上报曝光事件:
现象描述
快游戏加载资源场景,运行时出现如下错误信息:
initWithImageFile:/storage/emulated/0/Android/data/com.huawei.fastapp.dev/files/fastappEngine/games/xxx.jpg failed!
问题分析
报错是由于手机目录 /Android/data/com.huawei.fastapp.dev/files/fastappEngine/games 下不存在该图片,而此手机目录 /Android/data/com.huawei.fastapp.dev/files/fastappEngine 中以游戏包名命名的文件夹下出现该图片资源,将该图片放到games下对应文件夹内,游戏运行正常。
这是因为在账号登录前,游戏预加载了下一个场景的资源,资源存放在目录 /Android/data/com.huawei.fastapp.dev/files/fastappEngine/“游戏包名” 下;登录之后,资源会存在 /Android/data/com.huawei.fastapp.dev/files/fastappEngine/games 下。
解决方法
游戏打包时,首屏资源要打在rpk包里,不要预加载下一个场景资源,也不要加载远程资源,账号登录后再加载。
建议与总结
该案例对临时缓存数据也适用。
手机目录Android/data/com.huawei.fastapp.dev/cache/fastappEngine下存放游戏临时缓存数据。
华为账号登录也会在临时数据中做数据隔离处理,具体存放位置是在fastappEngine下,如果文件夹是以“包名”命名的文件夹则是登录前的数据,如果是games文件夹则是登录后的数据,相互之间不能访问。
现象描述
在华为开发者联盟的管理中心配置支付回调地址时,点击“支付”卡片进入产品列表,列表中不显示已创建的快游戏。
问题分析
可能是该游戏没有开通应用内支付服务。
解决方法
登录 AppGallery Connect ,选择“我的项目”,打开应用内支付服务开关,开通之后联盟后台即可显示该游戏信息。
快游戏从打开到更新的流程如下:
用户从华为手机应用市场或者桌面图标等入口启动快游戏时,会启动进程。
每次打开任何一个快应用,快应用中心都会查询该应用是否为首次打开,非首次打开的应用需要检查是否存在新版本。
如果返回应用的最新版本信息,则立即标记该应用为优先更新。
如下是在拉起快游戏,进入游戏的过程中出现的版本更新提示框,玩家必须选择新版本才可以进入游戏。

现象描述
在未登录华为账号的手机上用快应用加载器打开游戏,弹出华为账号登录界面,不登录账号直接点击左上角返回游戏,回到游戏界面后无法在游戏内再次拉起登录界面、无法进入游戏或无法退出游戏。
问题分析
用户点击返回时设置的返回页面错误,同时缺少可以再次拉起登录界面的按钮。
解决方法
当用户不登录账号点击返回时需要回到游戏初始界面,同时提供可以再次拉起登录界面的登录按钮(不可以反复自动拉起登录界面),点击登录后调用如下示例代码,直到用户登录成功才可以跳转页面进入正式的游戏界面。
gamelogin() {
console.log("Sign-in");
qg.gameLoginWithReal({
forceLogin: 1,
appid: applicationID,
success: function (data) {
// 登录成功后,可以存储账号信息。
console.log(" game login with real success:" + JSON.stringify(data));
// 用户登录成功才可进入真正游戏界面
cc.director.loadScene("game");
},
fail: function (data, code) {
console.log("game login with real fail:" + data + ", code:" + code);
//根据状态码处理游戏的逻辑。
//状态码为7004或者2012,表示玩家取消登录。
//此时,建议返回游戏界面,可以让玩家重新进行登录操作。
if (code == 7004 || code == 2012) {
//此错误码为上述有问题场景返回的错误码。
console.log("玩家取消登录,返回游戏界面让玩家重新登录。");
}
//状态码为7021表示玩家取消实名认证。
//在中国大陆的情况下,此时需要禁止玩家进入游戏。
if (code == 7021) {
console.log(
"The player has canceled identity verification. Forbid the player from entering the game."
);
}
},
});
}