iAd 冻结 Sprite Kit 应用
Posted
技术标签:
【中文标题】iAd 冻结 Sprite Kit 应用【英文标题】:iAd freezes Sprite Kit app 【发布时间】:2014-09-13 04:30:32 【问题描述】:我发现点击 iAd 可以在任何 Sprite Kit 游戏中冻结屏幕。这不仅仅是我的特定项目,因为库存的 Sprite Kit 示例项目也与 iAd 一起冻结。但这不会发生在模拟器中!我无法确定是因为模拟器运行的是 ios 8 而我的实际测试设备是 7.1,还是因为模拟器只是一个模拟器,所以它做的事情不同。
因此,如果您点击 iAd,然后单击 iAd 中的链接进入 safari(或此时手动切换到任何应用程序),然后切换回 Sprite Kit 应用程序,该应用程序将被冻结。 iAd 横幅仍然有效,它会按照应有的方式加载广告。但是应用程序的其余部分被冻结了。或者具体来说,它仍然接收触摸和东西(我可以从NSLog
s 看到)但节点的渲染被冻结。如果您通过点击再次打开 iAd,然后关闭 iAd,则应用程序会以某种方式恢复并且再次正常工作。
如果您好奇,以下是我对现有 Sprite Kit 示例项目所做的唯一修改:
// in GameViewController.h
#import <iAd/iAd.h>
@interface GameViewController : UIViewController <ADBannerViewDelegate>
@end
// in GameViewController.m
@interface GameViewController()
ADBannerView* iAdBanner;
NSLayoutConstraint* centerAd;
@end
@implementation GameViewController
- (void)viewDidLoad
[super viewDidLoad];
// Configure iAd
iAdBanner = [[ADBannerView alloc] initWithFrame:CGRectZero];
iAdBanner.alpha = 0.0;
iAdBanner.delegate = self;
centerAd = [NSLayoutConstraint constraintWithItem:iAdBanner
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
[self.view addSubview:iAdBanner];
[self.view addConstraint:centerAd];
// The rest of viewDidLoad is the stock code. I'm not pasting that in...
// iAd delegate methods
-(void) bannerViewDidLoadAd:(ADBannerView *)banner
// fade in iAd banner
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[banner setAlpha:1.0];
[UIView commitAnimations];
-(void) bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
NSLog(@"iAd error: %@", error.localizedDescription);
banner.alpha = 0.0;
另外我将部署目标设置为 7.1(并且显然在项目中包含 iAd 框架)。
如您所见,我没有对应用程序执行任何可能导致此崩溃的操作。我只需添加 iAd 横幅即可。所以问题不在我的代码中。这一定是苹果框架中的一个错误。
有人知道解决方法吗?我在互联网上找到了几个关于此的主题,但没有人能提出可行的解决方案。
编辑:
我发现我设备上的 iOS 7.1 在返回应用程序时调用了bannerViewActionDidFinish:
。然而,模拟器中的 iOS 8 会调用该方法在离开应用程序之前(确切地说是在您离开应用程序时)。这不会直接影响上面发布的代码,因为它没有实现此方法。但这确实表明 iOS 7.1 和 iOS 8 的 iAd 实现方式有所不同。
【问题讨论】:
返回应用时检查视图/场景或其他节点的暂停属性 不。 Sprite Kit 术语中没有任何暂停。既不是场景或视图,也不是任何节点。返回后,我尝试将所有可能事物的paused
属性设置为NO
,但没有成功。 iAd 没有 Sprite Kit 的概念,因此它不会以 Sprite Kit 方式暂停视图。
但如果你只是打开iAd,然后按顶部的X,它会返回应用程序,并正确取消暂停。仅当您在 iAd 打开时离开应用程序时才会发生冻结。然后当你回来时它无法恢复它。当您查看 iAd 时,iAd 会故意冻结屏幕以停止在后台呈现。它并没有完全将应用程序的暂停留给开发人员。我认为 Apple 试图确保 iAd 后面没有运行任何东西以节省资源。这会很好,但如果它没有无法恢复它暂停的内容。
我在问题的编辑部分所说的意思是 iAd 在离开 iOS 8 中的应用程序之前实际上将控制权返回给应用程序(取消暂停它)。在 iOS 7.x 中,iAd 只提供返回后控制回到应用程序。但是这种方式无法成功取消暂停应用程序。这绝对是 7.x 中 iAd 中的一个错误。
它不会暂停应用程序,应用程序会暂停(进入后台)。在后台模式下,只有应用程序的后台操作正在运行,除非您专门对其进行编程,否则您没有这些操作。我认为点击时应该关闭 iAd,但不是(可能需要手动完成?)或者 iAd 出于某种原因故意暂停视图控制器/视图。或者你进入后台的时候做,看viewcontroller对应的UIApplicationDelegate方法。
【参考方案1】:
--- EDIT 2 中的最终答案 ---
好吧,我之前确实读过这方面的内容,并且我确实尝试过,但我之前尝试过时似乎失败了。我又试了一次,现在可以了。
因此,您要做的是将视图控制器的canDisplayBannerAds
属性设置为YES
,然后使用originalContentView
属性而不是普通的view
属性来设置您的SKView
。或者,如果您想从场景内部访问您的视图,那就是:self.view.window.rootViewController.originalContentView
。所以基本上任何时候你需要对你的视图做一些特定于SKView
的事情(比如转换到一个场景),而不能用常规的UIView
完成的事情然后使用scene.view.window.rootViewController.originalContentView
而不仅仅是scene.view
。原因是当您在视图控制器中设置canDisplayBannerAds
属性时,iAd 以某种方式显式地将您的视图转换为UIView
,因此您不能再在视图上使用SKView
方法。 originalContentView
是解决此问题的方法。
这完全解决了我的问题,应用程序现在恢复正常状态。
编辑:
不,它没有解决我的问题。 :(
现在在广告打开时切换到另一个应用并返回不会冻结该应用。好的。但是现在只需打开和关闭一个广告,它就会以同样的方式冻结。这毫无意义……
所以如果我没有在我的视图控制器中设置canDisplayBannerAds
,那么当应用程序冻结时,离开应用程序并返回。但只是打开和关闭广告就可以了。但是如果我确实设置了canDisplayBannerAds
,那就相反了。
这真的没有意义。我现在很迷茫……
编辑2(实际解决方案):
终于解决了!但这并不容易,该死的...
所以问题出在视图层次结构中。如果我将ADBannerView
添加为我的主视图的子视图,那么它会冻结应用程序。这很奇怪,因为这是在屏幕上添加横幅的建议方法。
如果我不手动将横幅添加为子视图,它仍然会出现在屏幕上!我猜 iAd 的实现方式是,一旦初始化,无论如何它都会在屏幕上显示自己。不过看起来有点不同。如果它不是任何视图的子视图,那么它会从底部带有“向上滑动”动画,将所有内容调整为位于其上方的较小框。我猜这是 iAd 横幅的默认行为。所以这样它不会冻结屏幕,它工作得很好!但由于我想对横幅进行更多控制(比如自己制作动画,而不是留给横幅本身),所以我做了以下操作:
在我的视图控制器中,我创建了一个SKView
的实例(不是像往常一样将self.view
转换为SKView
,而是一个全新的实例)。然后我将其添加为self.view
的子视图。之后,我初始化ADBannerView
,并将其添加为self.view
的子视图。请注意,self.view
没有直接显示任何内容,我将其用作“容器”来容纳另外两个。视图层次结构如下所示:
self.view
/ \
SKView ADBannerView
这样ADBannerView
不是我的 SKView 的直接子视图或超级视图(这是我的游戏使用的主视图),因此它不能搞砸,因为它没有该视图的概念,因为它们都是同一视图的子视图。此时我不知道您是否需要在视图控制器中设置canDisplayBannerAds
。我已经设置好了,它可以工作。我没有尝试忽略它。
简而言之,我可以完全控制横幅视图以及我的游戏视图,并且它们不能相互混淆,因为它们不是子视图/超级视图关系。
这很难弄清楚,但你去吧。如果您对 iAd 和 Sprite Kit 也有问题,只需像这样组织您的视图。
【讨论】:
好答案。如果加一些代码sn-ps就更好了。 遗憾的是我已经没有这个项目了,我放弃了它,并删除了它:(所以我不能从中粘贴任何代码以上是关于iAd 冻结 Sprite Kit 应用的主要内容,如果未能解决你的问题,请参考以下文章