oc中广告sdk的原生oc的回调函数调用cocos没问题,而cocos调用oc,oc当场调回cocos就有问题

cocos调用ios中广告平台的的oc代码,比如显示广告,很正常。当广告播放完毕,用户关闭广告,那么广告相关的函数会被回调原生oc代码,oc代码再调用cocos函数function1,funtion1会包含一些界面处理比如隐藏loading。

这些都没问题。

但是如果某个广告sdk的oc代码准备显示广告时,发现之前加载失败,那么此时不会调用广告sdk的方法,而是直接调用cocos方法funtion1,而cocos的function1会隐藏loading,但这个情况,对于admob或穿山甲会有问题,function1中隐藏loading的语句失效,其它语句正常。

也就是说oc中广告sdk的原生oc的回调函数调用cocos没问题,而cocos调用oc,oc当场调回cocos就有问题。

试了定时器,都没解决,哪位有碰到过吗?

问了ai,给了多个解决方法,有一个方法有效
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
JsbBridge* m = [JsbBridge sharedInstance];
[m sendToScript:@“iosAdmobCallback” arg1:@“2”];
});

1赞

你这个场景我遇到过,本质是广告 SDK 在"加载失败直接回调"和"播放完毕正常回调"两条路径上,回到 Cocos 时的引擎状态不一样。

正常播放完毕的回调,Cocos 侧的渲染循环和节点树是稳定的,所以 function1 里隐藏 loading 没问题。但加载失败那条路径,广告 SDK 可能在 Cocos 还没完全准备好(比如场景刚切换、节点还没挂载完)的时候就触发了回调,这时候 function1 里涉及 UI 节点操作的语句就会失效,其他非 UI 的语句正常执行——跟你描述的现象一致。

你用的 dispatch_after 0.5 秒是有效的,因为它给了 Cocos 引擎一个完整的帧周期去稳定状态。不过 0.5 秒用户可能会看到 loading 多停留半秒,体验上稍有感知。如果想更精细,可以试试两个方向:

1.把延迟缩短到 0.1–0.2 秒,大部分情况下一个帧周期就够了,不用等太久。
2.在 Cocos 侧加一个状态标记,比如 isLoadingScene,OC 回调时先检查这个标记,如果 Cocos 还没准备好就把回调缓存起来,等 Cocos 侧主动来取。这样既不需要延迟,也不会丢回调。

另外 AdMob 和穿山甲都有这个问题,说明不是某一家 SDK 的 bug,而是 Cocos 和原生 OC 之间回调时机不一致的通用问题。不同 SDK 的失败回调线程策略不一样,统一用主线程 + 短延迟的方式处理会比较稳。

试了0.2秒,优量汇有时不行,我还是改为0.5秒了

0.5 秒能稳就先用 0.5 秒,这个决定没毛病。0.2 秒在个别源上翻车,基本可以确认是"回调到达时 Cocos 那一帧还没走完"的竞态:失败回调这条路径上,有的 SDK 是在 show 调用里同步就回掉的,回到 JS 时场景和节点树可能还没稳定,UI 操作就被吞了;不同源回得早晚不一样,所以固定一个短延迟总有一款源会踩空,0.5 秒只是把最坏情况盖住了。

想把多等的那半秒省掉、又不想为每家源调秒数,可以换个思路:不猜延迟,改成"立即发一次+幂等补发"。OC 侧收到回调后立刻 sendToScript 一次,同时再排一个 0.5 秒的补发;JS 侧把隐藏 loading 写成幂等的(可见才隐藏,已隐藏直接 return)。这样正常路径用户看不到额外 loading,失败路径就算第一次被吞,补发那次也兜得住,而且不用关心是哪家源、回得多早。

再往上就是状态方案:JS 侧维护 isLoadingScene 标记,没准备好就把事件缓存住,场景 onLoad 后再 flush。这个最干净,但要维护队列和 flush 时机,代码量比 dispatch_after 大。如果 0.5 秒目前体验能接受,建议先上"立即+幂等补发"这一档,状态方案留到真被这半秒卡住再说。