Hide/Show iAds in Spritekit - ios

I've been trying to figure out how to hide and show iAds in my Spritekit Scenes. Currently I have it setup like this:
ViewController.h
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#import <iAd/iAD.h>
#interface ViewController : UIViewController <ADBannerViewDelegate> {
ADBannerView *adView;
}
-(void)showsBanner;
-(void)hidesBanner;
#end
ViewController.m
#import "ViewController.h"
#import <UIKit/UIKit.h>
#import <iAd/iAD.h>
#import "MyScene.h"
#import <SpriteKit/SpriteKit.h>
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
self.canDisplayBannerAds = YES;
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.frame = CGRectOffset(adView.frame, 0, 0.0f);
adView.delegate=self;
[self.view addSubview:adView];
self.bannerIsVisible=NO;
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
if (!self.bannerIsVisible) {
[UIView beginAnimations:#"animatedAdBannerOn" context:NULL];
banner.frame = CGRectOffset(banner.frame, 0.0, 0.0);
[UIView commitAnimations];
self.bannerIsVisible = YES;
}}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
if (!self.bannerIsVisible) {
[UIView beginAnimations:#"animatedAdBannerOff" context:NULL];
banner.frame = CGRectOffset(banner.frame, 0.0, 0.0);
[adView setAlpha:0];
[UIView commitAnimations];
self.bannerIsVisible = NO;
}
}
-(void)hidesBanner {
NSLog(#"HIDING BANNER");
[adView setAlpha:0];
self.bannerIsVisible = NO;
}
-(void)showsBanner {
NSLog(#"SHOWING BANNER");
[adView setAlpha:1];
self.bannerIsVisible = YES;
}
etc...
#end
Then in my scene I grab my viewcontroller with a pointer:
ViewController *controller;
controller = [[ViewController alloc] init];
[controller hidesBanner];
My nslog runs in the console so I know it's going through. But the banner won't hide. Any thoughts? I'm pretty new with objective c so I have a feeling I'm just doing something dumb.

Like Huygamer said, you're creating a new instance of a view controller so when you call your method [controller hidesBanner]; you're referring to another object.
The best approach here is to use NSNotificationCenter: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html
And send a message to your viewcontroller whenever you want to hide or show your ad:
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Add view controller as observer
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"hideAd" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"showAd" object:nil];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = NO;
skView.showsNodeCount = NO;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
self.canDisplayBannerAds = YES;
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.frame = CGRectOffset(adView.frame, 0, 0.0f);
adView.delegate=self;
[self.view addSubview:adView];
self.bannerIsVisible=NO;
}
//Handle Notification
- (void)handleNotification:(NSNotification *)notification
{
if ([notification.name isEqualToString:#"hideAd"]) {
[self hidesBanner];
}else if ([notification.name isEqualToString:#"showAd"]) {
[self showBanner];
}
}
And in your scene:
[[NSNotificationCenter defaultCenter] postNotificationName:#"showAd" object:nil]; //Sends message to viewcontroller to show ad.
[[NSNotificationCenter defaultCenter] postNotificationName:#"hideAd" object:nil]; //Sends message to viewcontroller to hide ad.

Of course, there are 2 object and why you think it can do?
If you want to access the parent of skscene just do this
UIViewController *vc = self.view.window.rootViewController;
You can access the parent of this skscene and you can do hideBanner at the parent of this scene. Simple?

Here is what I did to make it work with SpriteKit Scenes (Xcode 6.1 and iOS 8.1 on iPhone 6):
Step 1- Add #import <"iAd/iAd.h"> in MyScene.h header file
Step 2- Make sure you declare your MyScene class to implement protocol in MyScene.h header file.
Step 3- Add the following code lines in your MyScene.m file inside -(Void)didMoveToView:(SKView *)view function.
ADBannerView* banner=[[ADBannerView alloc]initWithFrame:CGRectZero];
CGRect bannerFrame =CGRectMake(0, 667, self.view.frame.size.width, 0);
banner.frame=bannerFrame;
[self.view addSubview:banner];
banner.delegate=self;
Step 4- Implement the two methods of iAd
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
CGRect bannerFrame =CGRectMake(0, 667-50, self.view.frame.size.width, 0);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
banner.frame=bannerFrame;
[UIView commitAnimations];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
CGRect bannerFrame =CGRectMake(0, 667, self.view.frame.size.width, 0);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
banner.frame=bannerFrame;
[UIView commitAnimations];
}
The above code will move the Ad frame to scene when there is an Ad and will remove the frame if no Ad by animating the movement. Note that the last number in the frame rect is 0. It doesn't matter what you put there, the banner hight is fixed and doesn't change (50 pt).
Step 5- Respond to Ad actions by this code:
-(void)bannerViewActionDidFinish:(ADBannerView *)banner
{
[self startTimer];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
[gameTimer invalidate];
return YES;
}
This code will stop the game timer when a user clicks on the banner and resumes the game timer after the user returns back to the game. You can add your own code for saving and retrieving game data here.
Hope this helps.

Related

iAD size is portrait in landscape

I want to implement an iAd at the bottom of my screen. My app runs in landscape mode only, but the iAd is in portrait mode, its too big and I want it correct.
I instantiate it with this :
ADBannerView *adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 50, 480, 32)];
[self.view addSubview:adView];
So i give it 480 x 32 but it is in 360x 50.
That makes no sense to me and I don't know what to do. In the other topic I read I have to disable Auto Layout, but it is disabled.
thanks for any help!
edit: even if I add the iAd via storyboard to the view in landscape format, it shows it in portrait format when i run the app.
edit: I think I don't have a ADBannerView Appdelegate method.
All I have for my iAd is :
GameViewcontroller.h
#interface GameViewController : UIViewController<ADBannerViewDelegate>
GameViewcontroller.m
#interface GameViewController ()
{
BOOL _bannerIsVisible;
ADBannerView *_adBanner;
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
_adBanner = [[ADBannerView alloc] initWithFrame:CGRectMake((self.view.frame.size.width /2) - 180, self.view.frame.size.height, 480, 32)];
_adBanner.delegate = self;
[self.view addSubview:_adBanner];
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
if (!_bannerIsVisible)
{
// If banner isn't part of view hierarchy, add it
if (_adBanner.superview == nil)
{
[self.view addSubview:_adBanner];
}
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// Assumes the banner view is just off the bottom of the screen.
banner.frame = CGRectOffset(banner.frame, 0, - banner.frame.size.height);
[UIView commitAnimations];
_bannerIsVisible = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError: (NSError *)error
{
NSLog(#"Failed to retrieve ad");
if (_bannerIsVisible)
{
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
// Assumes the banner view is placed at the bottom of the screen.
banner.frame = CGRectOffset(banner.frame, 0, banner.frame.size.height);
[UIView commitAnimations];
_bannerIsVisible = NO;
}
}

Load and Unload iAd view

How can I load/unload an iAd when a button is tapped? In other words I want to be able to load a iAd banner when a button is tapped and unload it when another button is tapped.
With the following code I'm able to load and display the banner when the loadBanner button is tapped, the issue starts when I tap the unloadBanner button, it actually unloads the banner but if I click the loadBanner button again it doesn't re-load the banner, which is essentially what I want.
How can i re-load the banner after being removed?
.h file
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#interface ViewController : UIViewController <ADBannerViewDelegate>
- (IBAction)loadBanner:(id)sender;
- (IBAction)unloadBanner:(id)sender;
#end
.m file
#interface ViewController ()
{
BOOL _bannerIsVisible;
ADBannerView *_adBanner;
}
- (IBAction)loadBanner:(id)sender {
// iADBanner
_adBanner = [[ADBannerView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height, self.view.frame.size.width, 66)];
_adBanner.delegate = self;
}
- (IBAction)unloadBanner:(id)sender {
[_adBanner removeFromSuperview];
_adBanner.delegate = nil;
}
// ===================================
// ********* BANNER ****************
// ===================================
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
if (!_bannerIsVisible)
{
if (_adBanner.superview == nil)
{
[self.view addSubview:_adBanner];
}
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
// Assumes the banner view is just off the bottom of the screen.
banner.frame = CGRectOffset(banner.frame, 0, -banner.frame.size.height);
[UIView commitAnimations];
_bannerIsVisible = YES;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
if (_bannerIsVisible)
{
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
// Assumes the banner view is placed at the bottom of the screen.
banner.frame = CGRectOffset(banner.frame, 0, banner.frame.size.height);
[UIView commitAnimations];
_bannerIsVisible = NO;
}
}
Thanks a lot

Hide iAd bannerview in spritekit scene

I am trying to add iads to my new sprite kit game. The problem is that i do not need the ad to be on all the scenes. I've started to create an ADBannerView in the mainstoryboard. After that i'm trying to use NSNotification to hide and show the ads in different scenes, but its not working. the ad is still showing even though i've added into Menu.m(scene):
[[NSNotificationCenter defaultCenter] postNotificationName:#"hideAd" object:nil];
ViewController.m
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
//skView.showsFPS = YES;
//skView.showsNodeCount = YES;
//skView.showsPhysics = YES;
if (!skView.scene) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"hideAd" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleNotification:) name:#"showAd" object:nil];
SKScene * scene = [Menu sceneWithSize:skView.bounds.size];
NSLog(#"%#", scene);
// Present the scene.
[skView presentScene:scene];
}
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];
}
- (void)handleNotification:(NSNotification *)notification
{
if ([notification.name isEqualToString:#"hideAd"]) {
[self hidesBanner];
}else if ([notification.name isEqualToString:#"showAd"]) {
[self showsBanner];
}
}
-(void)hidesBanner {
NSLog(#"HIDING BANNER");
[adView setAlpha:0];
}
-(void)showsBanner {
NSLog(#"SHOWING BANNER");
[adView setAlpha:1];
}
It is not good to create an iAd if you do not intend to show it.
According to Apple's Banner View Best Practices:
• Only create a banner view when you intend to display it to the user. Otherwise, it may cycle through ads and deplete the list of available advertising for your app.
• If the user navigates from a screen of content with a banner view to a screen that does not have a banner view, and you expect them to be on that screen for a long period of time, remove the banner view from the view hierarchy, set its delegate to nil and release it before transitioning to the new screen of content. More generally, avoid keeping a banner view around when it is invisible to the user.
I remember reading about a hidden property a while back but looking at the iAd Framework Reference, I cannot find any such property. I recommend you follow Apple's guidelines if you do not want to display an ad in a specific scene.

How to recognize tapping on the whole oscillating SubView to perform interactive animation

In the code below, the subview (cloud) oscillates on the location given.
On tapping that subview while oscillation, it moves out of the bounds to the right side, then moves in from the left.
But the tap gesture is not working on the whole subview, it works only on the right-side end of the oscillating subView.
I want slide out and in of cloud to work, whenever the whole subview of cloud is tapped.
Below is code of .h and .m file respectively.
File : OscillatingCloudsViewController.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface OscillatingCloudsViewController : UIViewController
{
IBOutlet UIView *movingCloud1;
UIImage *cldImg;
}
- (IBAction)animateCloud;
- (IBAction)animateCloudBegin;
#end
File : OscillatingCloudsViewController.m
#import "OscillatingCloudsViewController.h"
#implementation OscillatingCloudsViewController
- (void) viewWillAppear:(BOOL)animated
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureAnimateCloud)];
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
tapGesture.cancelsTouchesInView = YES;
[movingCloud1 addGestureRecognizer:tapGesture];
movingCloud1.userInteractionEnabled = YES;
[super viewWillAppear:
animated];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self animateCloud];
}
- (IBAction) animateCloud
{
cldImg = [UIImage imageNamed:#"cloud1.png"];
movingCloud1=[[UIView alloc]initWithFrame:CGRectMake(50, 50, cldImg.size.width, cldImg.size.height)];
[movingCloud1 setBackgroundColor:[UIColor colorWithPatternImage:cldImg]];
[self.view addSubview:movingCloud1];
movingCloud1.userInteractionEnabled = YES;
[self viewWillAppear:YES];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:5];
[UIView setAnimationRepeatCount:HUGE_VALF];
[UIView setAnimationRepeatAutoreverses:YES];
CGPoint pos = movingCloud1.center;
pos.x = 220.0f;
movingCloud1.center = pos;
[UIView commitAnimations];
}
- (void) animateCloudHidden
{
[movingCloud1 setHidden:YES];
}
- (IBAction)animateCloudBegin
{
movingCloud1.frame = CGRectMake(-100, 50, cldImg.size.width, cldImg.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
CGPoint pos = movingCloud1.center;
pos.x = cldImg.size.width;
movingCloud1.center = pos;
[UIView commitAnimations];
}
- (IBAction) tapGestureAnimateCloud
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:2];
[UIView setAnimationRepeatCount:1];
[UIView setAnimationRepeatAutoreverses:NO];
movingCloud1.center = CGPointMake(1100.0f, 81.5f);
[UIView commitAnimations];
[self performSelector:#selector(animateCloudBegin) withObject:nil afterDelay:2.0f];
[self performSelector:#selector(animateCloudHidden) withObject:nil afterDelay:3.0f];
[self performSelector:#selector(animateCloud) withObject:nil afterDelay:3.0f];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
I have understood your problem. In viewwillApper you are assing the Gesture and in inside animateCloud method your allocating your movingCloud1 UIView.
For implementing this you need to fallow the bello steps.
In ViewdidLoad you need to allocate and add the movingCloud1 view to you self.view.
After add the Gesture to movingCloud1 view.
Your tapGesture will work now. So inside your tapgesture method just you need to set the animation for your movingCloud1 view

Adding iAds to Sprite Kit Landscape

I have the following code in my View Controller:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
if (!skView.scene) {
skView.showsFPS = NO;
skView.showsNodeCount = NO;
skView.showsDrawCount = NO;
// Create and configure the scene.
SKScene * scene = [MenuScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
self.canDisplayBannerAds = YES;
// Present the scene.
[skView presentScene:scene];
}
}
When I run the application it crashes immediately. I get the following error message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView scene]: unrecognized selector sent to instance
I can't use SKView *skView = (SKView *)self.originalContentView; because the app is in landscape mode. Is there a way to display iAds in a Landscap Sprite Kit game?
EDIT:
I just added this code to the view controller, but I get the same results..
#pragma mark iAd Delegate Methods
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];
}
I ran into this issue and solved it via creating an ABBannerView property and adding that as a subView.
In my ViewController class :
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.delegate = self;
[adView setFrame:CGRectMake(0, 0, 1024, 768)]; // set to your screen dimensions
[self.view addSubview:adView];
Important to NOT set the canDisplayBannerAds property of your view controller.
I believe what is happening is that if you do set the canDisplayBannerAds property to true, the view is modified and is no longer compatible with a SKView, and no longer has a scene property.
I did have to set the frame, so that the dimensions were correct otherwise it was portrait.
You can solve this without having to manually configure the ad banner. You do still have to use the original content view, but making it work correctly is just a matter of putting everything together in the right stages of the view controller's life cycle. All you have to do is enable canDisplayBannerAds: in awakeFromNib. Then set the SKView you create to either the view controller's view or originalContentView depending on the existence of the original content view.
- (void)awakeFromNib
{
[super awakeFromNib];
[self setCanDisplayBannerAds:YES];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
SKView *skView = nil;
if (self.originalContentView) {
skView = (SKView *)self.originalContentView;
}else{
skView = (SKView *)self.view;
}
[skView setShowsDrawCount:YES];
[skView setShowsFPS:YES];
[skView setShowsNodeCount:YES];
SKScene *scene = [MyScene sceneWithSize:skView.bounds.size];
[scene setScaleMode:SKSceneScaleModeFill];
[skView presentScene:scene];
}
None of the above answers works for me. Below code is tested in iOS 7 and 8 and works just fine.
Add below lines in header file
#import <iAd/iAd.h>
#interface GameViewController : UIViewController<ADBannerViewDelegate>{
//iAd
ADBannerView *adView;
}
In Implementation file .m add below code
#import "GameViewController.h"
#import "GameScene.h"
#implementation GameViewController
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
SKView *skView;
if (self.originalContentView) {
skView = (SKView *)self.originalContentView;
}
if (!skView.scene) {
//[skView setShowsDrawCount:YES];
//[skView setShowsFPS:YES];
//[skView setShowsNodeCount:YES];
//Improve Performance
skView.ignoresSiblingOrder = YES;
GameScene *scene = [GameScene sceneWithSize:skView.bounds.size];
[scene setScaleMode:SKSceneScaleModeFill];
[skView presentScene:scene];
}
}
- (void)awakeFromNib{
[super awakeFromNib];
CGRect screenRect = [[UIScreen mainScreen] bounds];
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.frame = CGRectMake(0, 0, screenRect.size.width, adView.frame.size.height);
adView.delegate=self;
[self.view addSubview:adView];
}
//iAd
-(void)bannerViewDidLoadAd:(ADBannerView *)banner {
[adView setAlpha:1.0];
NSLog(#"Show Ad");
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[adView setAlpha:0];
NSLog(#"Hide Ad");
}
//
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskAll;
}
}
-(BOOL)prefersStatusBarHidden{
return YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#end

Resources