I am using SpriteBuilder (which integrates with Cocos2d v3.0). I built an app and now I want to put in an iAd at the very top that pops up when I call it, and hides when I tell it to. What's the simplest way to do this?
Keep in mind I am using SpriteBuilder with Cocos2d. And just because I am using SpriteBuilder does not mean I am not using Xcode 5 as well. I am fully involved in Xcode as well. SpriteBuilder does not write the code for me, I do that.
Add iAd framework to your dependencies.
In your header file for your game scene, add the ADBannerViewDelegate, for instance:
#interface MainScene : CCNode <CCPhysicsCollisionDelegate, ADBannerViewDelegate>
In your implementation file, add the instance variable _bannerView:
#implementation MainScene {
ADBannerView *_bannerView;
}
And finally, insert the the iAD code (with some cocos2d tweaks). Here's my implementation for a game in portrait mode with a top banner. There's no hide method, but it's pretty easy to implement.
# pragma mark - iAd code
-(id)init
{
if( (self= [super init]) )
{
// On iOS 6 ADBannerView introduces a new initializer, use it when available.
if ([ADBannerView instancesRespondToSelector:#selector(initWithAdType:)]) {
_adView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
} else {
_adView = [[ADBannerView alloc] init];
}
_adView.requiredContentSizeIdentifiers = [NSSet setWithObject:ADBannerContentSizeIdentifierPortrait];
_adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
[[[CCDirector sharedDirector]view]addSubview:_adView];
[_adView setBackgroundColor:[UIColor clearColor]];
[[[CCDirector sharedDirector]view]addSubview:_adView];
_adView.delegate = self;
}
[self layoutAnimated:YES];
return self;
}
- (void)layoutAnimated:(BOOL)animated
{
// As of iOS 6.0, the banner will automatically resize itself based on its width.
// To support iOS 5.0 however, we continue to set the currentContentSizeIdentifier appropriately.
CGRect contentFrame = [CCDirector sharedDirector].view.bounds;
if (contentFrame.size.width < contentFrame.size.height) {
_bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
} else {
_bannerView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
}
CGRect bannerFrame = _bannerView.frame;
if (_bannerView.bannerLoaded) {
contentFrame.size.height -= _bannerView.frame.size.height;
bannerFrame.origin.y = contentFrame.size.height;
} else {
bannerFrame.origin.y = contentFrame.size.height;
}
[UIView animateWithDuration:animated ? 0.25 : 0.0 animations:^{
_bannerView.frame = bannerFrame;
}];
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
[self layoutAnimated:YES];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[self layoutAnimated:YES];
}
Related
I'm trying to handle my iAd via a singleton, since I'm using these banners in several view controllers. Now I'm confused of what do these objects store, since I move them around differently on each view controller when an ad is shown or if an error occured. Here my code:
Singleton:
+ (MySingleton *)sharedInstance {
static dispatch_once_t once;
static MySingleton * sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init
{
if (self = [super init]) {
if ([ADBannerView instancesRespondToSelector:#selector(initWithAdType:)]) {
self.bannerView = [[ADBannerView alloc] initWithAdType:ADAdTypeBanner];
} else {
self.bannerView = [[ADBannerView alloc] init];
}
}
return self;
}
And here how it is initalized:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//iAd
if(![[NSUserDefaults standardUserDefaults] objectForKey:kInAppPurchaseNoAds]){
self.bannerView = [MySingleton sharedInstance].bannerView;
self.bannerView.delegate = self;
self.bannerView.frame = CGRectOffset(self.bannerView.frame, 0, self.view.frame.size.height);
[self.view addSubview:self.bannerView];
}
}
And the delegate methods:
- (void)showBanner
{
if(!self.isBannerVisible){
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.5
animations:^{
//Restore the constraint
self.mainContainerToSuperviewConstraint.constant = 50;
//Move the banner on
self.bannerView.frame = CGRectOffset(self.bannerView.frame, 0, -50);
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.isBannerVisible = YES;
}];
}
}
- (void)hideBanner
{
if(self.isBannerVisible){
[self.view layoutIfNeeded];
[UIView animateWithDuration:0.5
animations:^{
//Restore the constraint
self.mainContainerToSuperviewConstraint.constant = 0;
//Move the banner off
self.bannerView.frame = CGRectOffset(self.bannerView.frame, 0, self.bannerView.frame.size.height);
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
self.isBannerVisible = NO;
}];
}
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self showBanner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
[self hideBanner];
}
Now what I'm confused is, do I have to check the position of the banner view again if the user was in another view with also an iAd where the rectangle with visible banner was at let's say 75 from the bottom of the screen and not 50? Or do these positions do not influence the AdBannerView but only the single object in each class?! I mean if he was in the other view and there the code moved the Banner to 75 pixels from the bottom, are these 75 pixels stored in my singleton AdView? So the original view had the banner now at 75 and not at 50?
I would suggest against having a singleton for a view - one view instance can be a subview only of 1 view, so you need to track adding/removing it and also you need to set the frame every time you add it again as a subview. You better have some kind of base view controller to share the instantiation logic and the control of the banners.
I am trying to integrate iAd with my existing Cocosd2d 1.x project. I picked up the codes from this site. I put this in my main menu class. it compiles and link fine but the banner is not showing. The NSlog shows that bannerViewDidLoadAd is called. What am I missing here? Your help is highly appreciated. The code is given below.
//iAd begin
-(void)onEnter
{
[super onEnter];
NSLog(#"onEnter called");
adView = [[ADBannerView alloc]initWithFrame:CGRectZero];
adView.delegate = self;
adView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil];
adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifier480x32;
CGSize widowSize = [[CCDirector sharedDirector] winSize];
adView.center = CGPointMake(adView.frame.size.width/2, widowSize.height/2+145);
adView.hidden = YES;
}
-(void)onExit
{
NSLog(#"onExit called");
adView.delegate = nil;
[adView removeFromSuperview];
[adView release];
adView = nil;
[super onExit];
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
NSLog(#"bannerViewDidLoadAd called");
adView.hidden = NO;
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(#"banner didFailToReceiveAdWithError called");
adView.hidden = YES;
}
-(void)bannerViewActionDidFinish:(ADBannerView *)banner
{
NSLog(#"bannViewActiondidFinishe called");
[[UIApplication sharedApplication] setStatusBarOrientation:(UIInterfaceOrientation)[[CCDirector sharedDirector]deviceOrientation]];
}
-(BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
NSLog(#"bannerviewActionShouldBegin called");
return YES;
}
//end iAd
You add this code to your onEnter method,
[[[CCDirector sharedDirector]view] addSubview:adView];
Regarding your specific question, I think #Liya is on the right track: you need to add the AdBannerView object to the view hierarchy; now, you're just creating the object but not using it.
Not sure if it will help, but I wrote recently a tutorial on integrating iAds with Cocos2d-x. The language is different (C++ instead of Objective-C), but the organization of code and some software engineering tips might be helpful if you want to integrate iAds with the scenes and layers of your game in Cocos2d: http://becomingindiedev.blogspot.com.es/2015/02/integrating-iad-in-cocos2d-x-v3x.html
i want to display iAd at the bottom of the screen..
i tried to add subView but the iAd showed in a cell and he hides him.
what should i do to make the tableView to scroll under the iAd?
my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self createAdBannerView];
[self.view addSubview:self.adBannerView];
}
#pragma mark - ADBannerViewDelegate
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
[self adjustBannerView];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
[self adjustBannerView];
}
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
}
- (void) adjustBannerView
{
CGRect contentViewFrame = self.view.bounds;
CGRect adBannerFrame = self.adBannerView.frame;
if([self.adBannerView isBannerLoaded])
{
CGSize bannerSize = [ADBannerView sizeFromBannerContentSizeIdentifier:self.adBannerView.currentContentSizeIdentifier];
contentViewFrame.size.height = contentViewFrame.size.height - bannerSize.height;
adBannerFrame.origin.y = contentViewFrame.size.height;
}
else
{
adBannerFrame.origin.y = contentViewFrame.size.height;
}
[UIView animateWithDuration:0.5 animations:^{
self.adBannerView.frame = adBannerFrame;
self.contentView.frame = contentViewFrame;
}];
}
- (void) createAdBannerView
{
self.adBannerView = [[ADBannerView alloc] initWithFrame:CGRectZero];
CGRect bannerFrame = self.adBannerView.frame;
bannerFrame.origin.y = self.view.frame.size.height;
self.adBannerView.frame = bannerFrame;
self.adBannerView.delegate = self;
self.adBannerView.requiredContentSizeIdentifiers = [NSSet setWithObjects:ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];
}
EDIT:
How do I prevent this?
i want to keep the iAd at the botton..
thanks in advance!
If you're using auto layout, what I've done before is add an outlet to the constraint for the bottom space to superview (assuming you have a tableview within a view).
You can then just adjust the constraint in the callback when the ad is loaded by for example doing
tableViewBottomSpaceConstraintOutlet.constant -= adBannerView.frame.size.height;
where tableViewBottomSpaceConstraintOutlet is the outlet on the bottom space to superview constraint and adBannerView is your ad banner's view.
Suggestion from Apple is to add a container view to contain the ScrollView(TableView) and setup constraints between the fixed view and the container view
details here:
Using Scroll Views with Auto Layout
I have this in my webViewDidFinishLoad:
- (void)setupAdBanner {
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
CGRect adFrame = adView.frame;
if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait
|| [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) {
adView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierPortrait;
adFrame.origin.y = self.view.frame.size.height-adView.frame.size.height;
} else {
adView.currentContentSizeIdentifier =
ADBannerContentSizeIdentifierLandscape;
adFrame.size.width = adView.frame.size.width;
adFrame.origin.y = self.view.frame.size.height-adView.frame.size.height;
}
adView.frame = adFrame;
[self.view addSubview:adView];
}
This overlaps HTML content in my phonegap application. How do I adjust my webview frame sizes to account for the ad banner?
I had this exact problem. I blogged about my solution here http://hawkinbj.wordpress.com/2013/04/16/implement-iad-banner-ads-without-covering-uiwebview-in-phonegap/
You need to implement ADBannerViewDelegateProtocolReference. In MainViewController.h:
#interface MainViewController : CDVViewController <ADBannerViewDelegate>
{
ADBannerView *adView;
}
#end
The rest of the steps are in MainViewController.m.
In webViewDidFinishLoad:
adView.delegate = self;
Add these two methods:
- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
CGRect resizedWebView = [super webView].frame;
resizedWebView.size.height = adView.frame.origin.y;
[super webView].frame = resizedWebView;
[self.view bringSubviewToFront:adView];
adView.hidden = NO;
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
CGRect resizedWebView = [super webView].frame;
resizedWebView.size.height = self.view.frame.size.height;
[super webView].frame = resizedWebView;
adView.hidden = YES;
}
The magic is
[self.view bringSubviewToFront:adView];
I just implemented adWhirl to my app with iAds and adMob. Everything compiles correctly and adMob works perfectly, but my iAd's are not being sized correctly. the ad looks like its the right size, but it actually appears to be cut off. About 1/4 of the ad seems like it is missing. Since i have no bugs i don't know exactly where to look to fix this.
here is a screenshot of what my ad bar looks like.
http://imgur.com/waPPD
any help or just a nudge in the right direction would be appreciated!
here is the AdWhirlAdapteriAd.h
#import "AdWhirlAdNetworkAdapter.h"
#import <iAd/ADBannerView.h>
#interface AdWhirlAdapterIAd : AdWhirlAdNetworkAdapter <ADBannerViewDelegate> {
NSString *kADBannerContentSizeIdentifierPortrait;
NSString *kADBannerContentSizeIdentifierLandscape;
}
+ (AdWhirlAdNetworkType)networkType;
#end
here is AdWhirlAdapteriAd.m
#import "AdWhirlAdapterIAd.h"
#import "AdWhirlAdNetworkConfig.h"
#import "AdWhirlView.h"
#import "AdWhirlLog.h"
#import "AdWhirlAdNetworkAdapter+Helpers.h"
#import "AdWhirlAdNetworkRegistry.h"
#implementation AdWhirlAdapterIAd
+ (AdWhirlAdNetworkType)networkType {
return AdWhirlAdNetworkTypeIAd;
}
+ (void)load {
if(NSClassFromString(#"ADBannerView") != nil) {
[[AdWhirlAdNetworkRegistry sharedRegistry] registerClass:self];
}
}
- (void)getAd {
ADBannerView *iAdView = [[ADBannerView alloc] initWithFrame:CGRectZero];
kADBannerContentSizeIdentifierPortrait =
&ADBannerContentSizeIdentifierPortrait != nil ?
ADBannerContentSizeIdentifierPortrait :
ADBannerContentSizeIdentifierPortrait;
kADBannerContentSizeIdentifierLandscape =
&ADBannerContentSizeIdentifierLandscape != nil ?
ADBannerContentSizeIdentifierLandscape :
ADBannerContentSizeIdentifierPortrait;
iAdView.requiredContentSizeIdentifiers = [NSSet setWithObjects:
kADBannerContentSizeIdentifierPortrait,
kADBannerContentSizeIdentifierLandscape,
nil];
UIDeviceOrientation orientation;
if ([self.adWhirlDelegate respondsToSelector:#selector(adWhirlCurrentOrientation)]) {
orientation = [self.adWhirlDelegate adWhirlCurrentOrientation];
}
else {
orientation = [UIDevice currentDevice].orientation;
}
if (UIDeviceOrientationIsLandscape(orientation)) {
iAdView.currentContentSizeIdentifier = kADBannerContentSizeIdentifierLandscape;
}
else {
iAdView.currentContentSizeIdentifier = kADBannerContentSizeIdentifierPortrait;
}
[iAdView setDelegate:self];
self.adNetworkView = iAdView;
[iAdView release];
}
- (void)stopBeingDelegate {
ADBannerView *iAdView = (ADBannerView *)self.adNetworkView;
if (iAdView != nil) {
iAdView.delegate = nil;
}
}
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation {
ADBannerView *iAdView = (ADBannerView *)self.adNetworkView;
if (iAdView == nil) return;
if (UIInterfaceOrientationIsLandscape(orientation)) {
iAdView.currentContentSizeIdentifier = kADBannerContentSizeIdentifierLandscape;
}
else {
iAdView.currentContentSizeIdentifier = kADBannerContentSizeIdentifierPortrait;
}
// ADBanner positions itself in the center of the super view, which we do not
// want, since we rely on publishers to resize the container view.
// position back to 0,0
CGRect newFrame = iAdView.frame;
newFrame.origin.x = newFrame.origin.y = 0;
iAdView.frame = newFrame;
}
- (BOOL)isBannerAnimationOK:(AWBannerAnimationType)animType {
if (animType == AWBannerAnimationTypeFadeIn) {
return NO;
}
return YES;
}
- (void)dealloc {
[super dealloc];
}
#pragma mark IAdDelegate methods
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
// ADBanner positions itself in the center of the super view, which we do not
// want, since we rely on publishers to resize the container view.
// position back to 0,0
CGRect newFrame = banner.frame;
newFrame.origin.x = newFrame.origin.y = 0;
banner.frame = newFrame;
[adWhirlView adapter:self didReceiveAdView:banner];
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
[adWhirlView adapter:self didFailAd:error];
}
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication: (BOOL)willLeave {
[self helperNotifyDelegateOfFullScreenModal];
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner {
[self helperNotifyDelegateOfFullScreenModalDismissal];
}
#end
Here is where the ads are being called in the app
MainMenuInterface.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "GameManager.h"
#import "AdWhirlView.h"
#import "AdWhirlDelegateProtocol.h"
#import "Reading_FluencyAppDelegate.h"
#import "RootViewController.h"
enum GameStatePP {
kGameStatePlaying,
kGameStatePaused
};
#interface MainMenuInterface : CCLayer <AdWhirlDelegate>
{
CCMenu *mainMenu;
CCMenu *aboutPage;
RootViewController *viewController;
AdWhirlView *adWhirlView;
enum GameStatePP _state;
}
#property(nonatomic,retain) AdWhirlView *adWhirlView;
#property(nonatomic) enum GameStatePP state;
-(void)displayStartButton;
#end
and here is the important stuff in MainMenuInterface.m
- (void)adWhirlWillPresentFullScreenModal {
if (self.state == kGameStatePlaying) {
//[[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
[[CCDirector sharedDirector] pause];
}
}
- (void)adWhirlDidDismissFullScreenModal {
if (self.state == kGameStatePaused)
return;
else {
self.state = kGameStatePlaying;
//[[SimpleAudioEngine sharedEngine] resumeBackgroundMusic];
[[CCDirector sharedDirector] resume];
}
}
- (NSString *)adWhirlApplicationKey {
return #"23myapplicationkey39203924";
}
- (UIViewController *)viewControllerForPresentingModalView {
return viewController;
}
-(void)adjustAdSize {
[UIView beginAnimations:#"AdResize" context:nil];
[UIView setAnimationDuration:0.2];
CGSize adSize = [adWhirlView actualAdSize];
CGRect newFrame = adWhirlView.frame;
newFrame.size.height = adSize.height;
CGSize winSize = [CCDirector sharedDirector].winSize;
newFrame.size.width = winSize.width;
newFrame.origin.x = (self.adWhirlView.bounds.size.width - adSize.width)/2;
newFrame.origin.y = (winSize.height - adSize.height);
adWhirlView.frame = newFrame;
[UIView commitAnimations];
}
- (void)adWhirlDidReceiveAd:(AdWhirlView *)adWhirlVieww {
[adWhirlView rotateToOrientation:UIInterfaceOrientationLandscapeRight];
[self adjustAdSize];
}
-(void)onEnter {
viewController = [(Reading_FluencyAppDelegate *)[[UIApplication sharedApplication] delegate] viewController];
self.adWhirlView = [AdWhirlView requestAdWhirlViewWithDelegate:self];
self.adWhirlView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
[adWhirlView updateAdWhirlConfig];
CGSize adSize = [adWhirlView actualAdSize];
CGSize winSize = [CCDirector sharedDirector].winSize;
self.adWhirlView.frame = CGRectMake((winSize.width/2)-(adSize.width/2),winSize.height- adSize.height,winSize.width,adSize.height);
self.adWhirlView.clipsToBounds = YES;
[viewController.view addSubview:adWhirlView];
[viewController.view bringSubviewToFront:adWhirlView];
[super onEnter];
}
-(void)onExit {
if (adWhirlView) {
[adWhirlView removeFromSuperview];
[adWhirlView replaceBannerViewWith:nil];
[adWhirlView ignoreNewAdRequests];
[adWhirlView setDelegate:nil];
self.adWhirlView = nil;
}
[super onExit];
}
-(void)dealloc
{
self.adWhirlView.delegate = nil;
self.adWhirlView = nil;
[super dealloc];
}
Maybe the winSize property for your sharedDirector still thinks your in portrait? What if you flipped it so you had:
newFrame.size.width = winSize.height;
newFrame.origin.x = (self.adWhirlView.bounds.size.width - adSize.width)/2;
newFrame.origin.y = (winSize.width - adSize.height);
adWhirlView.frame = newFrame;
for those that need to know in the future, my problem turned out to be that it was calling ads for landscape instead of portrait, than when it called adjustAdSize() it wasnt getting correct sizing.
i changed
- (void)adWhirlDidReceiveAd:(AdWhirlView *)adWhirlVieww {
[adWhirlView rotateToOrientation:UIInterfaceOrientationLandscapeRight];
[self adjustAdSize];
{
to
- (void)adWhirlDidReceiveAd:(AdWhirlView *)adWhirlVieww {
[adWhirlView rotateToOrientation:UIInterfaceOrientationPortrait];
[self adjustAdSize];
{
and it fixed all my problems!