If you're new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting!
With the iOs SDK 4 now public and the advent of iAds just a few days away, I thought we’d celebrate with a tutorial on how to integrate iAd into your iPhone app!
In this tutorial, not only will we show you how to get started with iAd, but we’ll also show you how to deal with some complex issues you may run into along the way such as:
- Supporting both Portrait and Landscape ads in the same app
- Integrating into a Universal app
- Maintaining backwards compatibility with iOs 3.0
- What to do if you are using a UITableViewController!
We’re actually going to start with where we left off in the How To Port an iPhone Application to the iPad and use the universal app we developed in that tutorial in the starting point.
So grab a copy if you haven’t already, and let’s get to adding some iAds!
Base SDK vs. Deployment Target
The first step to use iAd is to make sure our project has the right Base SDK and iPhone OS Deployment Target selected.
For those of you confused about the difference between the Base SDK and Deployment Target (like I was for quite some time!), here’s what they mean:
- The Base SDK is the version of the SDK you are linking against. Your app can use any classes or functions available in the version of the SDK you choose here – as long as they are available on the actual device the code runs on.
- The Deployment Target is the earliest possible version of the SDK your code can run on. This can be an earlier version than the Base SDK – in fact you often want to set it to be earlier to ensure that as many different versions of the OS can run your code as possible!
The tricky bit is what happens when you want to use a class, function, or framework available in one version of the OS if it’s available, but still work on the old version of the OS if it isn’t. We already did some of this in How To Port an iPhone Application to the iPad, and we’ll do even more in this tutorial!
For this tutorial, we want to set things up so that our code can use stuff available in iOS 4.0 (such as iAd), but still run on as many devices as reasonable (3.0+).
So first let’s set iOs 4.0 as the base SDK. To do this, expand the Targets directory, right click on PortMe, and choose “Get Info”. Click the Build tab, make sure “All Configurations” is selected, navigate to Architectures\Base SDK, and change the value to iPhone Device 4.0.
Then, let’s set iPhone OS 3.0 as the iPhone OS Deployment Target. To do this, still in the Target Build tab, navigate to Deployment\iPhone OS Deployment Target, and change the value to iPhone OS 3.0.
You should now be able to compile and run your app (use the iPhone simulator), and try it out on an iPhone 4 simulator. Once you run your code, in the simulator choose Hardware\Device\iPhone OS 4 and re-run your app. The simulator window will look a little different, and say iPhone 4 in the toolbar, so you’ll know it’s working!
Linking Against the iAd Framework
The next thing we need to do is add the iAd framework to the project. You can do this by right clicking on Frameworks, choosing “Add\Existing Frameworks…”, and choosing “iAd.framework”.
The problem is, if that is all we do our code will break on older devices that don’t have the iAd framework.
You can verify this by trying to run your code in the iPad Simulator 3.2 – boom! The app will crash on startup and you’ll see the following error log:
dyld: Library not loaded: /System/Library/Frameworks/iAd.framework/iAd
Referenced from: /Users/rwenderlich/Library/Application Support/
iPhone Simulator/3.2/Applications/
3ACB1BDA-26F6-43A6-84EA-9FB637B8CDCD/PortMe.app/PortMe
Reason: image not found
Update: Marin Todorov pointed out in the forum discussion that in later versions of Xcode, if you add a framework it’s automatically linked on earlier iOS versions you target! Pretty cool!
To fix this, we need to weak link against the iAd framework. Expand the Targets directory, right click on PortMe, and choose “Get Info”. Click the Build tab, make sure “All Configurations” is selected, and navigate to Linking\Other Linker Flags. Double click on that entry, click the “+” button, and type “-weak_framework iAd”.
Click OK, and then try your app on the iPad simulator again and viola – it should work!
Preparing our XIB
In this tutorial, we’re going to integrate iAd into both the PortMeGameListController and the PortMeGameDetailsController. However, the integration is a bit easier in the PortMeGameDetailsController because it is a subclass of UIViewController, so we’re going to start there first.
Open up PortMeGameDetailsController.xib. You’ll see that all of the controls are children of a single view:
What we’re going to need to do with iAd is scroll an ad view onto the screen when an ad is available, and shrink the rest of the content to fill the remaining space. As currently designed, this isn’t that easy because all of the controls are direct children of the root view. But there’s an easy way to fix it – we’ll simply move the controls into a subview instead!
The easiest way to do this is to drag another view from the library into the XIB, and change its size to be the same as the existing view’s size (320×416). Then drag the existing view as a subview of the new view. When you’re done, it should look like the following:
Then, control-drag from the File’s Owner to the new view (which is now the root view) to connect it to the view outlet. Save your XIB, and run the project and verify that everything still works OK with the details view (in particularly that orientation resizing works correctly). If all works well, we’re one step closer to integrating iAd!
Simple iAd Integration
Ok, now let’s get to the fun part – integrating iAd!
First, make the following changes to PortMeGameDetailsController:
// In the import section #import "iAd/ADBannerView.h" // Modify the PortMeGameDetailsController interface @interface PortMeGameDetailsController : UIViewController <GameSelectionDelegate, UISplitViewControllerDelegate, ADBannerViewDelegate> { // Inside the PortMeGameDetailsController interface UIView *_contentView; id _adBannerView; BOOL _adBannerViewIsVisible; // After the interface @property (nonatomic, retain) IBOutlet UIView *contentView; @property (nonatomic, retain) id adBannerView; @property (nonatomic) BOOL adBannerViewIsVisible; |
We first include the iAd headers and mark the view controller as implementing the ADBannerViewDelegate. This way, we can receive events as ads become available or not.
We then declare a property to keep track of the content view that contains all of the controls (basically the inner UIView). We also declare a variable to keep track of our iAd banner view, and whether or not it’s currently visible.
Note that we declare the iAd banner view as an id variable rather than as a ADBannerView. This is because we want to ensure backwards compatibility all the way to OS 3.0, and the ADBannerView class is only available on 4.0+, so we need to weak link against it.
Before we forget, let’s hook up our content view to the new outlet we just made. Make sure you save PortMeGameDetailsController.h, go back to PortMeGameDetailsController.xib, control-drag from the File’s Owner to the inner (second) UIView, and connect it to the contentView outlet.
Then switch over to PortMeGameDetailsController.m and make the following changes:
// In the synthesize section @synthesize contentView = _contentView; @synthesize adBannerView = _adBannerView; @synthesize adBannerViewIsVisible = _adBannerViewIsVisible; // In the dealloc section self.contentView = nil; self.adBannerView = nil; |
Next, we’re going to add the meat of the code. But there’s a lot of it – so let’s break it down into 6 steps.
1) Add helper functions to get height of iAd banner
- (int)getBannerHeight:(UIDeviceOrientation)orientation { if (UIInterfaceOrientationIsLandscape(orientation)) { return 32; } else { return 50; } } - (int)getBannerHeight { return [self getBannerHeight:[UIDevice currentDevice].orientation]; } |
There are several places in the rest of the code where we’re going to want to know how large the banner view should be given a particular orientation. Currently iAds have two possible sizes: 320×50 for portrait, or 480×32 for landscape. So we simply retrieve the proper height based on the passed in orientation.
2) Add helper function to create the iAd view
- (void)createAdBannerView { Class classAdBannerView = NSClassFromString(@"ADBannerView"); if (classAdBannerView != nil) { self.adBannerView = [[[classAdBannerView alloc] initWithFrame:CGRectZero] autorelease]; [_adBannerView setRequiredContentSizeIdentifiers:[NSSet setWithObjects: ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil]]; if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation)) { [_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier480x32]; } else { [_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier320x50]; } [_adBannerView setFrame:CGRectOffset([_adBannerView frame], 0, -[self getBannerHeight])]; [_adBannerView setDelegate:self]; [self.view addSubview:_adBannerView]; } } |
This helper function creates an ADBannerView in a manner that is safe to use across multiple OS versions. It uses weak linking and NSClassFromString to check if the ADBannerView class is available – if it is not, the method will return nil and the function will bail.
However, if it is available it creates an instance of the class. It then uses the setRequiredContentSizeIdentifiers to specify what kind of ads this app needs. For our case, our app supports both portrait and landscape modes so it needs both ad options.
It then calls setCurrentContentSizeIdentifier to tell iAd which ad it should display. We simply choose the correct one by looking at the current orientation.
Next, we need to set the frame for the iAd. Note there’s some funky business here – we actually set the frame of the view to be offscreen! This is because we don’t know if an ad is available yet, and we don’t want to display the view until we know one is.
We set our view controller as the delegate so that we can receive notice about iAds being available or not. Then finally we ad the new iAd banner view as a subview of our view!
Note something subtle about the above – we always use message passing syntax rather than dot notation (i.e. [_adBannerView setRequiredContentSizeIdentifiers:...] instead of _adBannerView.requiredContentSizeIdentifiers = …). This is again to make sure everything runs fine on OS 3.0+.
3) Add function to size views correctly
- (void)fixupAdView:(UIInterfaceOrientation)toInterfaceOrientation { if (_adBannerView != nil) { if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { [_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier480x32]; } else { [_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier320x50]; } [UIView beginAnimations:@"fixupViews" context:nil]; if (_adBannerViewIsVisible) { CGRect adBannerViewFrame = [_adBannerView frame]; adBannerViewFrame.origin.x = 0; adBannerViewFrame.origin.y = 0; [_adBannerView setFrame:adBannerViewFrame]; CGRect contentViewFrame = _contentView.frame; contentViewFrame.origin.y = [self getBannerHeight:toInterfaceOrientation]; contentViewFrame.size.height = self.view.frame.size.height - [self getBannerHeight:toInterfaceOrientation]; _contentView.frame = contentViewFrame; } else { CGRect adBannerViewFrame = [_adBannerView frame]; adBannerViewFrame.origin.x = 0; adBannerViewFrame.origin.y = -[self getBannerHeight:toInterfaceOrientation]; [_adBannerView setFrame:adBannerViewFrame]; CGRect contentViewFrame = _contentView.frame; contentViewFrame.origin.y = 0; contentViewFrame.size.height = self.view.frame.size.height; _contentView.frame = contentViewFrame; } [UIView commitAnimations]; } } |
This is a helper function we can call to make sure our views are in the right position. If ads are available, we want the ad banner view to be at the top of the screen and the content view shrunk a bit to fill the rest of the area. If ads are not available, we want the ad banner view offscreen and the content view as large as the entire view here.
And that’s exactly what the above function does. It looks long, but is fairly simple and self-explanatory. Note that we wrap the resizing code in an animation block to make things look awesome.
4) Call createAdView in viewDidLoad
- (void)viewDidLoad { [self createAdBannerView]; } |
We want to create our ad view as soon as our view is loaded, even if we aren’t ready to display it quite yet.
5) Call fixupAdView in viewWillAppear and willRotateToInterfaceOrientation
- (void) viewWillAppear:(BOOL)animated { [self refresh]; [self fixupAdView:[UIDevice currentDevice].orientation]; } - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [self fixupAdView:toInterfaceOrientation]; } |
We need to fix up our ad view in viewWillAppear, because the device may have changed orientations in the time between when our view was visible last and now. And we obviously need to change it upon rotation as well!
6) Implement ADBannerViewDelegate
#pragma mark ADBannerViewDelegate - (void)bannerViewDidLoadAd:(ADBannerView *)banner { if (!_adBannerViewIsVisible) { _adBannerViewIsVisible = YES; [self fixupAdView:[UIDevice currentDevice].orientation]; } } - (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error { if (_adBannerViewIsVisible) { _adBannerViewIsVisible = NO; [self fixupAdView:[UIDevice currentDevice].orientation]; } } |
Now that we have our helper functions, implementing the ADBannerViewDelegate methods are quite simple. We simply toggle whether the ad banner view should be visible or not, and call fixupAdView.
Done!
And that’s it! Compile and run your project, and you should see ads appear correctly in both portrait and landscape mode.
And best yet – if you run the code on an iPad or iPhone 3.0 device it will work just fine as well, but without ads!
UITableView integration
Well that worked great for our details controller, but we want it in our list controller too!
The problem is our list controller is a UITableViewController. Unfortunately, it seems like the best way to deal with this situation is to convert your UITableViewController to a normal UIViewController and then proceed similarly to the way we did above. So here are all of the gory steps:
1) Create a XIB for PortMeGameListController
Go to File\New File, choose User Interface and View XIB, make sure Product is iPhone, and click Next. Name the XIB PortMeGameListController.xib and click Finish.
Open up the XIB, click on the File’s Owner, and in the fourth tab of the Attributes Inspector change the class to PortMeGameListController.
Then drag a UIView into the current UIView (so there are 2, just like we did before), and add a UITableView to the inner view. When you’re done it should look like this:
2) Make some changes to PortMeGameListController
Inside PortMeGameListController.h:
// Change the interface declaration @interface PortMeGameListController : UIViewController <UITableViewDelegate, UITableViewDataSource> { // Add inside class UITableView *_tableView; UIView *_contentView; // Add after class @property (nonatomic, retain) IBOutlet UITableView *tableView; @property (nonatomic, retain) IBOutlet UIView *contentView; |
Inside PortMeGameListController.m:
// In synthesize section @synthesize tableView = _tableView; @synthesize contentView = _contentView; // In dealloc section self.tableView = nil; self.contentView = nil; |
Don’t forget to save the files!
3) Hook up outlets
Now go back to PortMeGameListController.xib and connect the first view to the view outlet, the second to the contentView outlet, and the third to the tableView outlet.
Also control-drag from the tableView back to the File’s Owner and set it as the delegate and datasource.
4) Set the NIB name for PortMeGameListController in MainWindow
Open MainWindow.xib and MainWindow-iPad.xib, expand the Navigation Controller, select “Port Me Game List Controller”, and change the nib name to PortMeGameListController.
5) Compile and test to make sure everything works as usual
At this point, compile and run your code and make sure everything works as it usually does – but now you’re using a UIViewController rather than a TableViewController, and you have a XIB laid out in a nice way to use iAds!
6) Follow the steps from the previous section
Now you’re exactly where we were in the previous section with a view controller – so follow the same steps to integrate in this view!
Done!
If all goes well, you should be able to compile and run your project and see advertisements at the top of your table view!
Where To Go Now?
Here is a sample project with all of the code we’ve developed in the above tutorial.
Now you should know how to integrate iAds into your projects – no matter what OSs you wish to support for your app! I’d love to hear your experiences with iAds and how well they are working (or not) for your app!
Category: iPhone

















Ray you are a pure inspiration :) If I could only quit my day job I’d be following in your footsteps to share iPhone knowledge to everyone in such a cool way
Best, wishes
Awesome tutorial Ray. Thanks so much for the info, I’m looking forward to giving this a try. I really like that you took iOS 3.0 into consideration with this and provided code that also provided backwards compatibility components.
Hey.. Very useful.. I was just wondering how to start and u finished it up… Thank You.
When i run it on my iPad, I cant see the advertisement. Why is that so?
@Marin, @Shawn: Thanks guys for the kind words! :]
@Abhinav: iAds are only available on iOS4+, so they will not work on iPad yet!
Ok. So, When it will be available on iPad..??
Can I upgrade iPad to 4.0?
Hi Ray,
I have finally decided to add a comment to one of your tutos just to let you know that your site has become my number one information source for iPhone dev.
Your tutos are clear and very helpfull.
So keep going and share your great knowledge with us to build a big community that will make the development skillz for iPhone / iPad evolving !
best regards from France ;)
@Abhinav: Not sure when iOS4.0 will be available for iPad, but for now – unfortunately no iAds on iPad!
@olinsha: Wow, thanks for the kind words! I think we have an awesome and helpful community of iPhone developers so trying to do my part!
Hey Ray,
Thanks for the tutorial.
Could you explain how to implement it in cocos2d?
Thanks!!
Declaring the ADBannerView as id is totally unnecessary since you already weak linked the framework, which can be done more easily by changing the type to weak in the general tab of your target’s settings
Hello Ray
i want to add a button and when a user tape the button , the player should move, but i want to add 4 sided button like when the user drag the button on right side the player should move on the right side and when the user drag the button on left side the player should move onto the left side.i want to use one button instead of 4 buttons and want 4 functionality from the one button rather than using 4 buttons because iphone screen is limited.
please reply me, i need your help.
thanks Ray
@Alon Ezer: Maybe in a future tutorial, we’ll see! But to get you started, you should be able to just put the Cocos2D view inside a view controller, and then follow the rest of the tutorial as-is.
@Vlad: Good points on both cases, didn’t realize that, thanks for the tips!
@Asad: I think you are posting in the wrong thread, this is a thread about integrating iAd ;]
However, it sounds like you are looking for a joystick implementation in Cocos2D. There are a bunch of guys that have released code for this, here’s a link to one that looks good:
http://github.com/sneakyness/SneakyInput
Hi Ray,
thank you very much for this helpful tutorial. That’s exactly what I’m looking for to solve my problem.
I did it so well with your tutorial’s supports.
However, I have one question. I’ve got so many “warning”… it’s about “invalid receiver type ‘id*’”
Of course the application is running well. However, I don’t know if those warning make my app got rejected on the AppStore. Do you have any ideas?
Best Regards,
Thang
@Thang: Hm, not sure I just re-built the sample project and don’t get any warnings. Do you see warnings compiling the sample project?
One thing to check is that you declared your id variables like “id foo”, not “id * foo”.
Hi Ray,
thank you very much. I’ve solved the problem. I didn’t notice that I should declare the id adView instead of id *adView.
However, I’ve been getting some warnings even in the auto-gererated code from XCode. Like when I use UITableView, I got a warning inside
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I’m gonna submit my first app on AppStore. I’m wondering if the warning fail my app submission or not. The best way should be trying ;) I will try and let you know if I got a reject because of the warning.
thanks for the tutorial. i just have one question. is that it? once a app is submitted, if you the ads will simply appear instead of that Test advertisement message??
@Dion: YES
But in order to have it, you must complete a special contract on iTunes Connect (like you did for selling apps) to have the ability to get the ads’ contents.
@Thang: Apple won’t reject you if your code has warnings (I doubt they will even know such things), however you should be careful about warnings because quite often they indicate bugs in your code that you should address. A lot of people like compiling their code with an option that sets warnings to errors just so they are forced to go through and clean up warnings.
Thanks for answering Dion’s question too btw!
Ray,
Nice article but…
I downloaded your code and ran it without change and the iAd test ads do not come up. Is there something on my end that I need to set in order to get your app functioning?
Good work.
John
Hi Ray,
I know I already left a comment, but I’m banging my head against the wall here, so I thought you might give me a tip …
When I installed the latest XCode I went straight to try your iAd example – and it works great in the iPhone 4 Simulator and the iPad Simulator, but I want to actually be sure it works on 3.1 and I see the 3.1 images are there in the Simulators folder, but XCode does not list them anymore … What do you say, did you find way to test on 3.1 Simulator somehow ?
Thanks a lot, hope you have the right tip as always,
Marin
@Ray: thanks for your comment
@Marin: I’m afraid that you can’t test on the 3.1 simulator. But you can test on the 3.1+ devices. My iPhone is running 3.1.3 and I can test the app when I plug my iPhone with XCode, and I selected Device 4.0
@John: Just downloaded the sample code and tried it out, and I see ads on my end. So not sure! Could be maybe the test ad server was down, or some kind of internet connectivity issue?
@Thang: Thanks again for helping out! Yeah that’s what I did back when my device was running 3.1.3 too… however now that it’s running 4.0 not sure what I’ll do for testing here on out!
@Ray: it has been being a big discussion on devforum.apple.com
Hello Ray,
thanks to your tuto I switched one of my app from AdMob (totally screwed with iOS4) to iAd. On my iPhone using iOS 4 and using the latest X-Code it’s working fine
But I also kept an older X-Code version to test my apps on older OS. And when I build my app for OS 3.1.3 I have plenty of errors (42 !!) that are all related to iAd :
* iAd/ADBannerView.h: No such file or directory
* cannot find protocol declaration for ‘ADBannerViewDelegate’
and so on.
I don’t understand the issue as I made iAd framework dependance weak. So I am not sure that we can really make such application run on older OS.
hi Ray
i have integrated iAd in my app with the help of your great tutorial but i don’t know whether it shows only one ad or there is a log in account or a secret key (like in case of admob, mobclix) to show ads changing after some instant of time.
Thanks in advance….
This is really nice. We were trying to get it to do the same thing, but have the ad on the bottom, and the image move up. I see how to move where the ad is, but the image is moving always up. I am trying to adjust some of the logic but so far no luck.
Any suggestions? Thanks!
@olinsha: An app with iAd will not compile with an old version of the SDK because it requires symbols in the iOS4+ SDK. However, the app itself should run just fine on devices running iOS 3.0+ if you build it with the above instructions. The best way to test is on a device running iOS3.0 AFAIK.
@Asad: You don’t need to integrate a secret key or anything like some other APIs.
@Eric: What do you mean the image is always moving up? I assume you already modified the code in fixupAdView to put the ad on the bottom and the content view a bit smaller but on top?
Ray,
Have you found problems when you have a view that is nested below Nav controllers, tab views and in a table?
I get your app working (and the WWDC app sample) working no problem. But when I try to include it in my working app with tab views/nav controllers and a table view, the apps don’t want to show.
Thoughts?
Great work.
John
Other people tell that installing the old XCode on an external drive will let you use the 3.1.3 Simulator, didn’t try it myself, but probably in the weekend I’ll have time to give it a try!
I “grafted” the code into one of my existing apps, and it works! One problem: sometimes I get compiler complaints about mycontroller may not respond to fixupAdView????
Thanks for a great tutorial
First, thanks a lot for the great article.
Question: I followed the article and can see the “test ad” in simulator. But when I load the app onto my test device (iPhone 3GS with OS 4.0), the ad bar is always blank, doesn’t show the test message. And console shows this:
Error Domain=ADErrorDomain Code=0 “Invalid app id/account information” UserInfo=0x26eac0 {NSLocalizedDescription=Invalid app id/account information}
Did I do anything wrong or is it expected behavior? (e.g., ad won’t show up on device until approval?)
I already submitted the app for review anyways. During uploading, I made sure I did turn on iAd, and completed the contract process.
Thanks!
@John: I’ve tried it in several of my apps that have nav controllers without any issues – haven’t tried it with tab bar controllers but I can’t see why that shouldn’t work. Have you tried debugging through and seeing if the resize code gets called and printing out the frames of the views, etc?
@Marin: You’re right about that, in fact Matt Gallagher just came out with a nice post that mentions this as well as some other useful tips:
http://cocoawithlove.com/2010/07/tips-tricks-for-conditional-ios3-ios32.html
@Bob: To avoid those warnings, make sure fixupAdView is declared before you call it, or add the signature of fixupAdView to your class’s header.
@samson: Hm, I haven’t seen that problem. Maybe it was due to timing – when you create the app in iTunes Connect, you have a checkbox to enable the app for iAd support. Let me know if it’s working for you when it gets approved.
Hi Ray,
The problem indeed got fixed when I declared the items in the .h files as needed.
Thanks
Ray, thanks for the reply.
I double checked my app on ITC. It is waiting for review and the info does say “iAd is enabled”. So I guess it should be fine. I will keep you updated once it’s approved (or rejected for reasons related to iAd).
Btw, I forgot to mention in my previous message: that error message was actually printed from adbannerviewdelegate’s didFailToReceiveAd callback.
Hi Ray!
Thanks for the tut, I’ve just intergrated iAds to my app. I’ll test and submit it soon.
Thanks again!
downloaded your code, ran in and rotate (iad) work perfectly , while in landscape i click in test advert and get this in debugger
The view controller returned NO from -shouldAutorotateToInterfaceOrientation: for all interface orientations. It should support at least one orientation.
Normal ?
Great Tutorial :)
T
Great article.
I am having the same problem as Sampson. I have successfully integrated iAds into several new apps but when I activated iAds for an old app and then added my functional iAd code to the debug version, I get the same error message as Sampson on the device.
I can’t run on 4.0 simulator because I have Quattro SDK installed for back-up ads.
Thanks,
Joseph
Anyone had tried to integrate iAds into three20 ? To be more specific, how about TTPhotoView ?
@Samson/@Joseph: Yeah I get that shouldAutorotateToInterfaceOrientation error too. Maybe a bug with the test ads…? Either way, doesn’t seem to cause a problem in my shipped apps with iAds.
@Forrest: I have not, but I’d imagine it would involve a lot of digging around Three20 code unfortunately :P Maybe try the Three20 forums on this one, they might have some good tips to get you started on that.
Thanks Ray but that is not the error we were talking about. We got an “Invalid app id/account information” when running on the device.
Mine went away and turned into a “no qualified ads” error so I still get no test ads with working code on my device.
Joseph
hi, ray.
I’m always thanks for your good tutorial.
I’m trying this IAD tutorial.
but I have some problem.
4.0, 3.1.3 Simulator no problem!
4.0 Device no problem.
but 3.1.3 Device have error. like this.
warning: Unable to read symbols from “iAd” (not yet mapped into memory).
Error launching remote program: security policy error
The program being debugged is not being run.
What should I have to??
Thank you for your time.
@ray, the issue Joseph and I met should have nothing to do with auto-rotation. It’s that the ad is always blank and the delegate’s didFailed… is called with “invalid app id/account” error. Also the following seems to be true for both of us:
- Only occurs on device. On simulator it does show “test ad”. (Seems Joseph can’t run simulator for some reason but he does see the same problem on device)
- Occurs only when you try to upgrade an old app with iAd. (I haven’t tried any new apps but Joseph said new apps are fine)
@tony: the auto rotation error you saw is more like a warning. To avoid it you just need to do this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return interfaceOrientation == UIInterfaceOrientationPortrait;
}
This tells the OS your app only supports portrait mode and can’t rotate at all.
Somehow the template code doesn’t write this part for you. Apparently it still works the same, but the OS is just reminding you to be more specific.
Hello RaY
I have implemented iAd in my application but it only shows Test Advertisement on ads. i have agreed to iAd agreement also. My question is that whether this ad is changing or its statically only one ad, i also want to upload my app to appstore but it contains only one ad. i think if my app gets ready for sale, it will change ads automatically.
please give me some help in this regards.
Thanks
@Asad: you Ad will be fully controlled by Apple iAd server. So you don’t need to care about changing you ad. The only task you have to do after signing the iAd contract is integrate ADBannerView into your apps.
The actual ads will appear when people download your app from AppStore.
Special thanks to Thang Tran, i am going to upload my app to appstore.
@Asad: you are welcome :)
Congratulation, you are going to have a new app your the store, and going to make money. Just share the link when it is available on the store. Best wishes.
Uploaded my app, waiting for review. Thanks to all for the help and comments.
Hi All,
I just found out something: after you login ITC, there is an item called “iAd networks”. From here you can check your app’s iad state. For example mine shows:
Testing: This app is receiving test ads. This app’s status is not yet Ready For Sale. You have not configured ad preferences for this app.
Well this still doesn’t explain why it shows blank id and invalid id error on device, but hope it’s helpful for others.
I seem to be getting EXC_BAD_ACCESS crashes in the simulator after adapting the code (without rotating) into my app. Has anyone else experienced this, or does anyone know where I could have gone wrong?
I have the correct code in the dealloc section, that was my first double check.
@Josesph/@samson: OK, I did some more testing on this… I ran both one of my apps with shipped ads, and the sample code above on my device, and here are the results:
* My app with shipped ads: shows actual ads – I guess because the app has been enabled for iAds & approved…?
* The sample project above: shows test ads.
If you guys run the sample project above on your device, does it show test ads or do you get the error?
Did you guys go to iTunes connect and enable your iAd network contract?
@gojia: Unfortunately I no longer have a 3.1.3 device to test that out on… if anyone else does and can help @gojia out (and let me know if I’ve made some kind of mistake in the project above), I’d greatly appreciate it!
@Thang: Thanks for helping out @Asad!
@MarkAtAR: When you get an EXC_BAD_ACCESS, there are two ways I usually try to track that down: 1) set breakpoints in the code to narrow down the area nearby where it occurs, and 2) enable NSZombieEnabled for the project, which sometimes help give a hint about why it’s occurring:
http://www.cocoadev.com/index.pl?NSZombieEnabled
Hi Ray:
Thanks, I contacted Apple and they said to file a support ticket as something is not set right in the iTunes Connect portal for that one particular app. It probably has to do with the fact that it was an update to an app that was activated for iAds before iAds launched and then later rejected. All my newer apps work fine.
I have another question for you about the iAds in your live app. When you look at the console for the live app can you tell how long after a “ad not received error” the banner attempts to reload. Is it 30 seconds like in the test ads or 3 minutes – the reported refresh rate for successful loads?
Thanks again,
Joseph Nardone
@Ray
Thanks for the quick reply Ray. I have ads on multiple view controllers and the error I am getting is this:
*** -[MenuViewController bannerViewDidLoadAd:]: message sent to deallocated instance 0×141430
But MenuViewController is the first view controller and this error only happens if you go to the next view controller before the first ad is able to load. Then it gives me that error above with NSZombiesEnabled. I think I am misunderstanding what is being done by the ads in the background or I am doing something seriously wrong. Does this make any sense?
Thank you for the great tutorial – it has been a life saver.
I only have one (really annoying) problem left. When I changed my UITableViewController into a UIViewController, the TableView now longer seems to respond to my ToolBar hiding / unhiding.
When the ToolBar is displayed, the last row of my table ends up hidden behind it.
I am beating my head against the wall figuring out how to get the auto-sizing to work for the ToolBar.
Everything else is working great, other than the last line of my table getting lost when the toolbar displays.
Thoughts?
@MarkAtAR: bad_access usually occurs when you use a pointer whose memory is already freed.
Did you set your adBannerView.delegate = NULL in your viewcontroller’s dealloc? This, among many others, is a very common mistake.
@Ray/Joseph,
Looks like new apps are fine. Only upgraded ones have this issue.
I also contacted ITC and haven’t received any feedback yet. But the feedback Joseph received makes sense.
I’ll wait and see. Thanks.
@samson
Yup, I have self.adBannerView = nil in my dealloc. And dealloc is definitely running when I leave the view, but the error still occurs.
@MarkAtAR, yes you set the view to nil. But did you set the delegate to nil too? e.g., self.adBannerView.delegate = nil;
According to documents, it’s very important to set the delegate to nil in dealloc because it is possible that the viewcontroller is dealloc’ed but adview is being held by something else and its reference count is still above 0. In that case, when something happens in adview and it needs to call the delegate, it doesn’t know the delegate is freed, hence the crash.
Fantastic. One of the most concise and well written articles i’ve ever read. Explained it perfectly and I now have iAds intergrated into my already existing App.
It’s now going to be interesting to see what I make with iAds rather than selling my App at a price – but that’s a different topic
@macjasp: yeah, now we have more reasons to provide free apps on the App Store. We can earn money while we do branding on the App Store.
@Joseph: Ah good to know re: the support ticket – that explains why I didn’t see any problems I guess!
Just tested out the refresh rate on my app with ads. Ran it in debug mode on my local device, and after getting a didFailToReceiveAdWithError callback, it appeared to keep trying every 30 seconds thereafter.
@samson: Thanks for helping out @Mark! @Mark, did that resolve it for you?
@Chris: How have you added the toolbar, is it part of the view controller and added/removed to the view dynamically? If you have the table view and toolbar in the same view controller, can’t you just set the frame of the table view to the right size when the toolbar displays?
Just checked out your blog by the way – looks pretty interesting and a cool lifestyle you lead, I’ll be following your site from now on! :]
@Thang/@mac: Personally I’ve had better luck with regular app sales than with iAds… however iAds are a helpful addition to the free apps I make with the goal of enticing people to upgrade for the full versions. However, it really depends on your app – and how many people you can get to download it! :]
@Ray: yeah, you are right! This is the key point no matter if your app is free for paid :)
Update on my app:
1. It gets rejected because my app doesn’t hide the ad bar when the app fails to receive an ad. Looks like “hide when no ad” becomes a mandatory requirements. (Mine is actually a little special — I put ad in UITableView.tableHeaderView so it can be scrolled away. I don’t want to hide the ad because it will shift the rows and might cause user to tap a wrong row if ad update happens about the same time of tapping. Anyways I’m trying other method to comply.)
2. From yesterday, my app on device no longer receives “invalid app id/account” error. Now it still never gets an ad, and didFailToReceiveAd… is still called all the time. Only difference is that the error msg now becomes:
Error Domain=ADErrorDomain Code=0 “no qualified ads found for this request” UserInfo=0×13871140 {NSLocalizedDescription=no qualified ads found for this request}
I guess Apple support team might have done something to my account and this error looks more normal… But it still doesn’t see the test ad. I’m waiting for their further response.
@samson in order to hide ads if errors happen, maybe like this
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(@”ad is wrong “);
if( error != nil ){
if( bannerView != nil ){
bannerView.hidden = YES;
}
}
}
@all
Actually regarding the delegate, so odd that they seems like do not run , for example, I put NSLog(..) to print info inside those three delegates,
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
NSLog(@”Banner view is beginning an ad action”)
return TRUE;
}
- (void)bannerViewDidLoadAd:(ADBannerView *)banner {
NSLog(@”ad is okay “);
if( bannerView != nil ){
bannerView.hidden = NO;
}
}
- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
NSLog(@”ad is wrong “);
if( error != nil ){
if( bannerView != nil ){
bannerView.hidden = YES;
}
}
}
Tested on simulator, there was no any info printed out, just something like these , is that wrong ?
ADManager: did enter background
The view controller returned NO from -shouldAutorotateToInterfaceOrientation: for all interface orientations. It should support at least one orientation.
@Forrest, thanks for the info. I know how to hide the ad upon failure, just not sure if I want to do it — I put ad in tableheaderview of uitableview, if I hide/show ad, user will see the table shift up or down 50 px. If user is about to tap on a row, he/she might tap on the wrong one because of the shift. Maybe I should rethink the overall design — but I really like the way the user can scroll the ad off screen.
For your other question — did you check all the simple things first, such as:
- you did set delegate to self
- you did set ad content size set, and current size
- you did call request ad on adbannerview
I know these are just wild guesses… But it doesn’t hurt to check simple things first.
(btw the auto rotate error is irrelevant to iAd and is not important. See my earlier comment)
@samson: Good to know that hide when no ad is mandatory! I’m glad that first error went away, keep us posted and let us know if/when it starts showing up actual ads.
Regarding your ad placement, why not implement it the same way as in this tutorial where there’s a banner view that appears above the table view? Personally I like having it permanently showing even if the user scrolls, because after all you don’t get any $$ if the user can’t see it! :]
@Forrest: That’s not the best way to hide the banner view when the ad isn’t showing, it’s best to remove the view or move it offscreen because otherwise you just have a blank spot where the ad is supposed to be. I mentioned one way to do so in the above tutorial.
Samson has some good ideas about how to narrow down where your problem is. If none of those work, try the code from the sample project which will give you a working base to start with.
Hi Ray, thanks so much for the tutorial, really helpful!
I’ve only a question : i’m creating an app that has a lot of table views, navigation controller-based. Have I to put an iAd on any table view or only on the root view? What does Apple reccomends? Thanks very much :)
@Ricky: I haven’t seen an Apple doc with any specific recommendations of whether to put it just on the root view or all views… but personally, my rule of thumb is if there’s a good chance the user will be looking at a view for a period of time, in my apps I’ll put an ad view there, even if on multiple drill-down views. After all, more ads = more $$!
Hi Ray,
Thanks to you, my app is now up.
http://itunes.apple.com/us/app/icoin-free/id381816540?mt=8
@ricky, I have similar app structure — many levels hierarchy of UITableView. I put Ad in every of them.
Just make sure you implement viewDidLoad/viewDidUnload pair properly so that your ad views in invisible views are freed when memory is low, and recreated when that view goes visible again. Otherwise you might run out of memory sooner than you should.
Usually you just need to set all subview properties to nil — assume you declare them as “retain” property and recreate them in viewDidLoad.
@ray, yes i probably should just make it simpler and put the ad view in a constant area. The reason of my current design was that I thought the screen was small enough…
First of all, thanks so much for your answers.
@Ray i haven’t seen it too and it was for this reason that i asked for. So, i’ll put adbanners wherever i’ll suppose they would be helpful. Thanks :)
@samson: Yes, I set them to nil in the dealloc section and I create them in viewDidLoad. If banner is available I show it, else the frame of the adbanner view in out of the view and it’s set to hidden. In the tableviews, i don’t have the problem of resize the view if the banner is hidden because it stays in a separate view and i can scroll the table view up/down separately. But the $$ comes only if the user tap on the banner view?
Really thanks :)
Sorry for the double post… but so, in any view i want the iAd i have to create a view implement the banner and all its methods?
@ricky, yes you need to implement the ad banner delegate for every view controller. All my views inherit from a super class I created, so I just do it once in that super class. Maybe creating a category in UIViewController is an option too.
Regarding setting view to nil, doing it in dealloc is necessary but might not be sufficient. You should do it in viewDidUnload too. The logic here is that, when a viewcontroller becomes invisible (e.g., another view pushed into the top of navigation controller), the system might choose to free its views in case of low memory (but will not release the view controller object itself). When the system does so, it will call viewDidUnload. You should then release anything you explicitly created in viewDidLoad or held in a retained property. The next time this view controller goes visible again (e.g., the view that covers it gets popped out), viewDidLoad will be called again.
I think most apps with iAd will create iAd view manually in viewDidLoad, so you should do the opposite in viewDidUnload. Otherwise the system’s memory management won’t work efficiently (worse, it could cause memory leak if you don’t realize viewDidLoad could be called multiple times in a viewcontroller’s lifecycle).
You can test this behavior by adding log statement in viewDidLoad/viewDidUnload, and use simulator’s “simulate low memory warning” menu. You’ll notice that viewDidUnload of the invisible views are called when you choose this menu item, and viewDidLoad called upon when it goes visible again.
For more details please refer to “memory management” paragraph of http://developer.apple.com/iphone/library/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
Thanks samson, you are really really helpful!! :)
@Bob: Awesome, congrats!
@Ricky: Yeah, similar to what Samson mentioned, for my apps I pulled the above code into a helper object to avoid all the code duplication.
@Samson: Agreed, thanks for helping out Ricky here! Good point on the viewDidLoad/viewDidUnload scenario, that is something that took me a long time to figure out with iPhone dev :]
Hi Ray –
The quality of conversation and help in this thread is phenomenal – I love it.
You asked: “How have you added the toolbar, is it part of the view controller and added/removed to the view dynamically?”
I have a MainWindow.xib that has a Navigation Controller, featuring a Navigation Bar, a Toolbar, and a Root View Controller.
The RootViewController.xib is now set up with a Table View contained within a View, contained within a view – as instructed in the tutorial here.
“If you have the table view and toolbar in the same view controller, can’t you just set the frame of the table view to the right size when the toolbar displays?”
I’m probably doing something simple wrong. The Table View used to resize automatically before I changed things to incorporate the iAd. Now the bottom row ends up obscured when the Toolbar slides up.
“Just checked out your blog by the way – looks pretty interesting and a cool lifestyle you lead, I’ll be following your site from now on! :]”
*blush* – Thanks! Nomadic life is fun indeed. I look forward to tracking each others blogs.
Thanks for everything,
– Chris
@ray & ricky, you are welcome!
BTW yesterday my app was approved! It’s still the “ad in the tableheaderview and can be scrolled away” design. My final solution to avoid row shifting cause by ad bar hide/show is to use a static logo bar when ad is not available. Looks like app reviewers are fine with it as long as a blank ad bar is not shown.
Now the iAd fill rate is really low, like 5-7% for me. But each click generates $1.x income. Not bad. eCPM shows $300+ (note: this doesn’t mean you’ll get $300 for every 1000 impressions. It’s a reversed calculated value by dividing your income of all clicks and impressions by number of impressions. It can’t be used to predict or calculate your income. Took me a while to understand this).
I believe the rate will decrease as more apps support iAd. Also there are only 2 ads right now, dove + men and nissan leaf car. I’m kind of bored to see them everyday. Hope more advertisers join.
Does iAds work on ALL iPods or only those with certain specs?
Hi Ray,
I have a question. When I put this into my app, I get a warning on:
[self createAdBannerView]; in the viewDidLoad method,
and the same warning on this line:
[self refresh]; in the viewWillAppear method.
The warning says, “‘iCharacterViewController’ may not respond to ‘-refresh’” and
‘iCharacterViewController’ may not respond to ‘-createAdBannerView’.
The app crashes whenever it is opened…
Help? Anyone?
@Chris: Hm, the first thing I’d check is if the autosizing properties are set up properly for your RootViewController’s view, subview, and table view controller. Yeah autosizing can be a pain to get working right sometimes…
@samson: Awesome, glad your app got approved! Fill rate is 15% on one of my apps, and 7% on another. I’m not sure why there’s a difference! But either way agreed that is pretty low eh? I’ve heard some people are showing ads from other networks when iAds aren’t available?
@Bob: iAds only work on iOS 4.0+.
@Philip: That warning means the compiler can’t find the refresh and createAdBannerView methods in your class. Have you added those methods? If all else fails, try stepping through with your debugger.
Thanks again Ray. You are awesome! I made some slight changes if you want ads to appear at the bottom.
Thought I’d share it to save someone else the trouble.
I get the warning too about -shouldAutorotateToInterfaceOrientation:. I researched it on developers forum. It’s a known bug in the iAd framework.
Here is code with ability to to do Bottom display. Just use the define to activate relevant code:
// Comment out or undef to use iAds at top of screen. #define __BOTTOM_iAD__ -(void)createAdBannerView { Class classAdBannerView = NSClassFromString(@"ADBannerView"); if (classAdBannerView != nil) { self.adBannerView = [[[classAdBannerView alloc] initWithFrame:CGRectZero] autorelease]; [adBannerView setRequiredContentSizeIdentifiers:[NSSet setWithObjects: ADBannerContentSizeIdentifier320x50, ADBannerContentSizeIdentifier480x32, nil]]; if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation)) { [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier480x32]; } else { [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier320x50]; } #ifdef __BOTTOM_iAD__ // Banner at Bottom CGRect cgRect =[[UIScreen mainScreen] bounds]; CGSize cgSize = cgRect.size; [adBannerView setFrame:CGRectOffset([adBannerView frame], 0, cgSize.height + [self getBannerHeight])]; #else // Banner at the Top [adBannerView setFrame:CGRectOffset([adBannerView frame], 0, -[self getBannerHeight])]; #endif [adBannerView setDelegate:self]; [self.view addSubview:adBannerView]; } } -(void)fixupAdView:(UIInterfaceOrientation)toInterfaceOrientation { if (adBannerView != nil) { if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier480x32]; } else { [adBannerView setCurrentContentSizeIdentifier:ADBannerContentSizeIdentifier320x50]; } [UIView beginAnimations:@"fixupViews" context:nil]; if (adBannerViewIsVisible) { CGRect adBannerViewFrame = [adBannerView frame]; adBannerViewFrame.origin.x = 0; #ifdef __BOTTOM_iAD__ CGRect cgRect =[[UIScreen mainScreen] bounds]; CGSize cgSize = cgRect.size; adBannerViewFrame.origin.y = cgSize.height - [self getBannerHeight:toInterfaceOrientation]; #else adBannerViewFrame.origin.y = 0; #endif [adBannerView setFrame:adBannerViewFrame]; CGRect contentViewFrame = contentView.frame; #ifdef __BOTTOM_iAD__ contentViewFrame.origin.y = 0; #else contentViewFrame.origin.y = [self getBannerHeight:toInterfaceOrientation]; #endif contentViewFrame.size.height = self.view.frame.size.height - [self getBannerHeight:toInterfaceOrientation]; contentView.frame = contentViewFrame; } else { CGRect adBannerViewFrame = [adBannerView frame]; adBannerViewFrame.origin.x = 0; #ifdef __BOTTOM_iAD__ CGRect cgRect =[[UIScreen mainScreen] bounds]; CGSize cgSize = cgRect.size; adBannerViewFrame.origin.y = cgSize.height; #else adBannerViewFrame.origin.y = 0; #endif [adBannerView setFrame:adBannerViewFrame]; CGRect contentViewFrame = contentView.frame; contentViewFrame.origin.y = 0; contentViewFrame.size.height = self.view.frame.size.height; contentView.frame = contentViewFrame; } [UIView commitAnimations]; } }@Jim: Awesome, thanks so much for sharing, I’m sure it will be useful to others as well!
I also recently submitted an app in the store that implements the ad banner view. I guess I just want to reiterate what samson said:
** Apple REQUIRES that you hide your banner ad if no ads are being served, FOR NOW. This is NOT explicitly mentioned in the documentation. If you don’t do this, the app will get rejected. **
And yes, there aren’t that many ads being served yet. I think that’s part of the reason why they are rejecting apps that don’t hide the banner view (since there aren’t that many ads being served yet, to begin with).
Yes, Apple wants that, and i think he’s right. I need to use the iAd banner in the bottom of the screen, so tomorrow i’ll try the code Jim Murff, thank you so much for sharing :)
Sorry for the Off Topic, but my app makes an export of the datas on some files with a personalized extension, but i don’t know how set the document icon for these files. I’ve looked all around the developer site and the web without find a solution, somebody of could help me? :(
Great tutorial, not sure if this has already been asked/answered but what are your thoughts on iAd placement within an app?
Some views require as much screen real-estate as possible for your app and adding an iAd is simple too much. Do you think adding an iAd within an ‘about app’ view for example would be frowned upon by Apple? I know to benefit the developer its about getting an much exposure to the ad as possible but wondered what peoples thoughts were on this.
Thanks
Adrian
My app is ready for sales but iAds isn’t good as I think before, revenue is worse than AdMob :(
Hi
The artice is great. I finally managed to integrate iAd into my game. Everything runs smoothly (it works also on pre 4.0 without apps) but I have problem with clicking the ad.
When I click the ad the correct callback is called as it should be (implementation is below)
[code] - (BOOL)bannerViewActionShouldBegin:(id)banner willLeaveApplication:(BOOL)willLeave
{
GLOG(@"bannerView Begin");
if (!willLeave)
[game pauseAndStopMusic];
return YES;
}[/code]
But nothing changes (except game is paused and music stops) in displaying ad (I can’t see no “action”). Also there should be called other callback some time after clicking ad informing its action is over. I have implemented it like so:
[code]
- (void)bannerViewActionDidFinish:(id)banner
{
GLOG(@"bannerView End");
[game continueWithMusic];
}[/code]
It is never called. Have You any idea why it is not called? I have tested it on the simulator and real device (iPod Touch) and the results are the same. Is it possible that those “test ads” are bad? I belive there is no possibility to have real ads during development – only distributed apps via AppStore have real ads, am I right?
@JDizzle: Good to know that hiding is actually required – thank goodness I happened to do it that way when I submitted my app! :]
@Ricky: Have you tried setting the document icon for your app according to this guide?
http://developer.apple.com/iphone/library/documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html
@Adrian: AFAIK it’s up to you as a developer where you put your ads, so I don’t think there would be any problem putting it in an about view. But of course, I doubt users would go there much, which means you wouldn’t make as much revenue…
@itgbau: Yeah will be interesting to see how this plays out in the long run…
@Gucman: Interesting, I haven’t seen that problem. I’d try the sample project above and make sure the ads show up for you OK there – if they do it may be something specific to your project that is preventing the ads from displaying.
Such a great tutorial. I was able to retrofit my app in about 2 hours (and I had to do the rework of several table views)!
Great job Ray!
Bill
Great layout, design, and implementation.
-
I implemented something very similar using your suggestions and everything works really-really well for the iAds.
-
** However, I do get a crash that I have narrowed down to the following steps…
-
1. Run the app,
2. Use any part of the app as normal, perhaps view one of the iAds test screens; not important.
3. “Single-Click” home button to send the app to the Background.
4. While in the background, “Double-Click” the home button to display the background tray.
5. Hold down on app to display the “Terminate” icon, and then terminate my app while it was in the background.
6. When I try to restart the app, it is frozen and unresponsive????
-
I have killed the delegate and bannerView in the dealloc method with bannerView.delegate = nil; & self.bannerView = nil;
-
iAd.framework is “weak” linked. baseSDK 4.0, target: 3.0,
-
Do you need some way of turning the delegate off, when you head to the background? or unload the view?
-
Any Suggestions??
I just tested out your sample download using the same steps I mentioned in my comment that makes my app crash and I get the same crash when trying to restart the app.
-
Then after that, I can’t get either app to load, just shows a dark black screen. I have to tap the “Power” button once-(1) & release, then tap the “Home” key once, and it brings me back to the “Locked-Screen” and from there I can re-enter my Home-Screen, but neither app loads.
-
I’m sure others have come across this as well, if so I would love to hear your solutions??
-
I played around with several configurations prior realizing this crash and had a version on my iPhone 3Gs that did not crash with the above mentioned steps. Unfortunately, I could not recall what was different in that version, that made it work, and already saved and build several other changes that I lost the fix.. **But at least that told me that there is a solution, and this is not normal iAd configuration issue**
-
Thanks!
Sorry for the (3rd) comment, the above crash only occur on actual devices, I have not been able to reproduce in Simulator. But it is consistent and occurred for my app and yours in the same manner with the same results.
-
However, I can’t upload to AppStore like this, users have no way to re-install the app if they happen terminate it in the background tray. And I don’t want to set the UIApplicationExitsOnSuspend flag which would take away all the fast-app-switching utilities.
-
Okay, no more comments until I hear from somebody, or give someone else a chance.
!!!! Crash Solved For All those Interested or who may of had the same Problem !!!
-
It was because the device was still connected to Xcode.
-
I built and ran on device. While still connected, I use the app when it loads, then close as mentioned in the steps that cause the crash. If the device is still connected it crashes when I try to reload. If the device is disconnected after building, the app does not crash. This seems to happen with all the apps that I tried that are using iOS 4.0 background methods, including your sample app for iAds.
-
There must be some kind of back-end issue with Xcode and the Debugger trying to maintain communicate with the device. This also explains why it only occurred on actual devices and not in the simulator.
-
If I simply load the app onto the device, then unplug, the app is killed, but when I perform the same steps as mentioned above that caused the crash, it works fine.
-
Hope this helps somebody else from the same two days of debugging.
-
P.S. Did not mean to monopolize this much of your blog, been checking out your other stuff and it looks great. I especially like the facebook Graph API tutorials that you have.
Thanks for your great tutorial. I’ve downloaded this code. Run in simulator and also device (os 4). But i don’t get any test ad.
I don’t change any line of code. Just run it.
Would you please tell me what is the problem?
@Newbyman: Thanks for posting about your experience with that, hopefully it will help anyone else going through the same thing!
@Mainul: I just double checked the sample app and the test apps show up OK for me. I’ve heard of some people overseas having issues or if you don’t have network connectivity, do either of those apply to you?
Thanks for your reply. Yes, i have network connectivity. some people overseas, if you mean that the country location, then i’m a Bangladeshi.
hi ray , Thanks ray here is one question what this add will display and what would be the link if some one click on it , whether a developer can have a control over it or this is control by Apple.
@umer: You might want to check this out:
http://developer.apple.com/support/resources/iad-network.html
Basically, your control over the ads is limited to:
1. the keywords included in the meta data for the app in iTunes; and
2. the keywords that you put in the “Ad Exclusion” setting in iTunesConnect.
Everything else is controlled by Apple.
PS: Our Golf Etiquette app has been up for awhile now in iTunes. According to the report in iTunesConnect, most of the ad impressions are targetting the US. I have yet to see the ad view pop up in my phone (ps: I’m in Canada)
I really expect iAd to deploy in other countries — I got many users in other countries and now those are 0 impressions and $0 income…
Hi Ray,
Very thanks full to you,
I am following your site always.
Good updation.
Am learn lot of things from your posts like facebook integration,iad…..
@JDizzle: Thanks for helping out @umer, and for sharing the info about impressions outside of the US as well!
@harish: Thanks for the kind words!
nice tutorial. got iAd integration working in an hour. quick question: do the adds rotate automatically ever time the view appears.
@Rajesh: In the example above we call refreshAdView in the viewWillAppear, so it should display the ad view in the appropriate orientation each time the view controller is displayed.
Very informative post Ray, thanks for taking the time to post this up I was clueless with the Apple documentation. My app was denied because the banner wasn’t hidden, I was a bad student and actually placed the iAd into my .xib so it wouldn’t hide.
I removed it and resubmitted it and Apple approved my app.
Thanks for the help, this was the only online resource I found that worked.
@Lee: Cool, hopefully it will be approved this time! It sounds like a lot of people have been caught by that. I’m glad the tutorial helped!
I havent been able to find a way around the “Invalid app id/account information” error. I’m using AdWhirl for mediation now, but I continue to get the same error I was getting when I was doing the mediating between iAds and AdMob myself. For a short time, I got the no ads available to be served error, but that only lasted for about an hour. The exact error I’m getting:
Error Domain=ADErrorDomain Code=0 “Invalid app id/account information” UserInfo=0x68b92e0 {NSLocalizedDescription=Invalid app id/account information}
I have never been able to see a real iAd nor a testing iAd in my app — only the border with an empty center. The app I’m working on has yet to be submitted to the app store but I don’t want to submit and then hope that it’ll work once its accepted unless others can tell me that this is how it works. Can anyone offer some advice?
Ray,
Well done and thank you.
My nav bar is being hidden by the ad. I’ve seen other comments on this issue but they’ve not responded with how they fixed it. Any ideas?
Again, thank you for making this easy.
@Ivan, i had the same error (on device, not on simulator) before my app got approved. after approval everything automatically went normal. i know it’s a bit blind to hope it will work but i’m afraid there isn’t a way to confirm it yet.
also make sure you filled out all the contract and payment info in itunes center’s contract page.
Ray,
Thanks for this, is really great.
I think I missed the [self refresh] method, because I don’t see any implementation here and it’s not a member of the UIViewController.
Could you please help me with this?
Thanks
is it possible to add multiple iad in uiviewcell as contentview?
Best tutorial on the internet for iAds. Thanks for taking the time to create it and make it free. This is book quality stuff.
@samson: Thanks for helping out Ivan!
@Daniel: The refresh method is just a helper method I wrote in my view controller to refresh the current view from the model. It’s nothing specific to iAds so if you don’t have/need that, just remove the call to the refresh method.
@Michael: I haven’t run into that myself. Have you followed the same approach here of including the iAds inside a subview of your view controller?
@Yoon: I assume you’re trying to add multiple iAds in different spots in a table view? I don’t see why that wouldn’t work. You’ll just have to make sure you add code to dynamically add/remove the rows as iAds become available or not to avoid rejection.
@John: Thanks for the kind words, and glad you liked the tutorial! :]
First of all ,thanks for your great comm.
i have a problem in implementation of iad in tableview.app freezes at bannerViewActionDidFinish: method where nothing is called. Is there problem with implementation in table view.. however same code workd fine in another view..reply …
There is a bug to use toolbar at the bottom. When view switch back from Landscape to Portrait the toolbar in the bottom was hidden. There is no problem when not use iAd.
Thanks a great case study for iAd.
What would be the best way to disable the ad from showing up (ie, if I have an free ad version of the app and a paid version with no ads)
I’m getting a very strange error every once in a while from the “didFailToReceiveAdWithError” callback.
Error Domain=ADErrorDomain Code=0 “The operation couldn’t be completed. Unknown error” UserInfo=0x7b5a200 {ADInternalErrorCode=-1001, NSLocalizedFailureReason=Unknown error}
Sorry for the double post on this topic, after that error (or any error) I then immediately get EXC_BAD_ACCESS and my app crashes. The relevant info from the debugger stack is:
#2 0x024544a1 in -[NSInvocation invoke]
#3 0×02455354 in ___forwarding___
#4 0x02454e72 in __forwarding_prep_0___
#5 0×00033222 in -[ADDistributedMessagingCenter messagePort:receivedMessage:withData:]
#6 0x0003383b in ADMessagePortCallBack
Any ideas as to why this is happening?
Hi all!
I made iad app and do well by iPhone 3g with iOS4.
But it doesn’t show any iad with iPhone 4.
Could someone give me advice?
Anyway thanks Ray, this blog is great help!
Hi, Ray:
Echoing everyone else, great iAd tutorial!
I’ve implemented iAds as per your tutorial, and everything appears to be working exactly as advertised (on the Sim, anyway…still waiting for the new iPhone to show up), and testing on a iOS 3.0 device (my gen 1 iPod Touch) works well – no iAds, and no crashes.
I’ve got two (minor) concerns, however:
1. To @Samson’s point, the iAd docs say that you have to set the adBanner delegate to nil. However, when I try to do that (in my dealloc method), I get a compile error:
Request for member ‘delegate’ in something not a structure or union.
I’m guessing that’s because the delegate is created/set ‘conditionally’ in the createAdBannerView method (i.e., it’s not created if the ADBannerView class doesn’t exist). @Samson, how did you get around this problem?
2. I’m still getting the ‘The view controller returned NO from -shouldAutorotateToInterfaceOrientation: for all interface orientations. It should support at least one orientation.’ warning when I click on the test ad in the Simulator. I’ve added the shouldAutorotateToInterfaceOrientation method to all of my view controllers, to no avail. Any ideas?
PS – I’m also in Canada…I’ll keep everyone posted on the iAd frequency up here.
My question is solved.
Kill background process and delete app from iPhone.
Then clean all the target, rebuilt and run.
Thank you all.
@Alok: I’ve used iAds in apps with table views a bunch of times, I don’t know of any reason offhand why that should cause a problem.
@Daniel: For free vs. paid, I usually solve that by having two targets (free version and lite version), and in the lite version I have a Preprocessor Macro define for LITE_VERSION. Then in the code I surround the stuff that should only be in the lite version (such as ads) with #ifdef LITE_VERSION … #endif.
As for the error/exception you saw, I haven’t seen that bug if you figure it out please post here so others can benefit!
@shmyt: Glad you got it working!
@MarkB: For issue #1, are you using the dot notation for the property? If you use that while conditionally loading the classes you’ll get an error like that. However, you should be able to use the [adBanner setDelegate:nil] notation and it should work.
For issue #2, I get that warning as well but iAds work well anyway (and with rotation), so I think that is safe to ignore.
Hi, Ray:
I followed @Vlad’s comments and declared the adBanner as an ADBannerView (instead of as an id) – I can now set the delegate to nil with no issue. Everything still works in the Sim (and works – without ads, of course, on the Gen 1 iPod Touch).
I wonder if #2 is a problem in the API…
Thanks for the tutorial.
I have 2 problem:
1) If I test my app in simulator it’s OK but in iPhone (3GS) the banner will not appears (not called bannerViewDidLoadAd).
2) How to hidden the banner when it will not appear?
Thanks.
@MarkB: Cool, glad you got it working!
@Michele: If you check the comments above, you’ll see some others have reported having trouble getting the ads to show up on their device until they submit – that may be the issue. As for hiding the banner, the tutorial shows how to do that based on whether the _adBannerViewIsVisible boolean is true or not.
Hi guys,
I’ve a really big problema with iAd :(
My app is made with many table views with a navigation controller system and the iAd banner in any of these views. The problem is that when I open the banner in the Root view and after i close it, everything is ok, but if I open it in any of other view, when I close it my app goes on the root page, the navigation bar disappears and the app doesn’t work anymore until it crashes. In any page i create a new Banner view indipendently. Please help me :(
@Michele the code for show/hide the banner is written above. This code creates the banner outside the view and move it inside/outside if the banner is available/unavailable. Remember that the real iAd banner (not the “test banner”) is available only in usa and england.
@Ricky
Thanks.
I has solved your problem adding the banner in a UINavigationController not in the root view controller.
Excuse me for my english very bad!
Thans to all.
@Michele I believe you are italian like me :D Mi spieghi meglio questa cosa? E’ un problema che mi sta mandando al manicomio! Nelle finestre modali infatti non succede! Succede solo se apro l’iad in una pagina che non sia la prima della navigation :(
English version:
Sorry for the italian post, i’ve asked to him how has he solved this common problem :)
@Ricky C’è un modo per scambiarci l’email? hai Skype? Io sono manvalan
I’ve added you on skype, mi contact is “namelessna” ;)
Lol awesome guys, glad you got in touch, and best of luck! :]
thanks for all your help Ray, these tutorials are great! Im having trouble minimizing the table view and putting in a imageview underneath, iads no longer show up and it isnt a show stopper, iads just no longer show test ads in tableview or detail view. could you go into detail about linking to uitableview. the integration into tableview messed me up on displaying on main screen without a tableview.
Really comprehensive tutorial, great way to start building universal Apps which require iAd support. If you want any free promo codes for our Apps just ask.
Thanks Ray!
Hey Ray,
Previously I told you I managed to use your method to get my app integrated with iAds, after successful approval to the app store I couldn’t be happier.
I recently bought an iPad for development reasons and attempted to upgrade my apps. All is well apart from my iAds.
I have an issue with the app view from iAds, can you tell me what’s causing this on the iPad? Screen shot link below:
http://img251.imageshack.us/i/screenshot20101002at624.jpg/
Thanks again for your very informative website.
@Daniel: In my case, this was a response to a failed ad load from an ADBanner whose delegate/ViewController was no longer in existence.
From the docs for ADBannerView’s delegate:
Important: Before releasing an instance of ADBannerView for which you have set a delegate, you must first set its delegate property to nil. This can be done, for example, in your dealloc method.
In the example above, I changed this:
// In the dealloc section
self.contentView = nil;
self.adBannerView = nil;
To this:
// In the dealloc section
self.contentView = nil;
self.adBannerView.delegate = nil;
self.adBannerView = nil;
@james: I’m not quite sure what you’re trying to do, could you please explain?
@Jamie: Thanks, and nice to meet you!
@Lee: iAds aren’t supported on the iPad in iOS 3.2, so that may be the issue :]
@Fork: Thanks for posting your solution here to help out Daniel!
Ray, do you know of any way for the app developer to control look and feel of the ad when it is being displayed within their app?
Hello!
And maybe you can give me a link How to integrate iAd into iPad? I need a size of banner and space where it should placed on the screen.
great tutorial as always.
followed to the T… works great with iAd on the top.
Applied Jim’s changes and it shows on the bottom but about 1/3 of it is below the screen.
any ideas for a fix?
@Duke J: You can’t control the look and feel of the ad – it’s up to the advertiser.
@Mitille: iAd is not yet supported on the iPad.
@spoolup: I haven’t tried Jim’s changes myself, but if you’re having troubles I’d suggest carefully stepping through the code, checking that the variables are set correctly, etc.
Hii….
I want to know whether or not we can show 4 iads on a page.I have implemented 4 iads.
but when i tap on that page sometimes it shows 1 iAd sometimes 2 and sometimes all of four.Why???
any idea.
Hello All
i have installed the xcode 3.2.5 and now i can’t see the iAd Test Advertisement on the screen.
i can’t see iAd even in iAd sample code.
Anyone facing this problem, Please share your suggestions.
please ans my question my client is waiting.
Thanks Ray for the code. It works great!
Will you update it for the iPad when it’s supported?
Thanks again!
Hi there,
I have integrated iAd in my App. NOw i want to monitor the number of times a user clicks on the banner. Pls. advise the code.
Thanks
Kumar
Hi Ray,
I tried to integrate iAds in my app, I followed this tutorial and only get the following error in didFailToReceiveAdWithError:(NSError *)error
method:
Error Domain=ADErrorDomain Code=3 “The operation couldn’t be completed. Ad inventory unavailable” UserInfo=0x7a2a920 {ADInternalErrorCode=3, NSLocalizedFailureReason=Ad inventory unavailable}
Thinking about it, I downloaded your example and get the same error.
@Divya: AFAIK there shouldn’t be any reason you can’t (in theory) display up to 4 iAds at a time. However, iAds usually have a low fill rate, so the chances of having 4 iAds available for display at a time are probably low.
@Jorge: If I have time! :]
@kumar: One thing you could do is put a view overtop the area where the user clicks on the iAd and intercept the click for statistics.
@Smaug: Here’s a thread with some information with some people who had the same problem:
http://stackoverflow.com/questions/3720459/iad-error-ad-inventory-unavailable-solved
@Fork Thanks for the insight, memory management was the issue, I forgot to post back about it.
Hi Ray.
Thanks for an awesome tutorial on iAd. I followed some of this, esp the weaklink method.
But I can’t seem to show the Ad in simulator. It always called that didReceiveError delegate with message “no qualified ads”..
Does the Test Ad fill rate affected by my location?? I cant think of any reason why my ad is not showing.
Hi Ray,
Great Work Ray, I successfully integrate iAds and its working on simulator but when i tested it on device it calls didFailToReciveAd, and no ads are displaying even test ad which was displaying on simulator, is there any changes i have to do in my provisioning profile or there is another problem. I am using my older provisioning profile.
@Rocotilos/@Ibnyadam: Not sure, test ads have always shown up fine for me. I’ve heard some people say that being overseas or making an update to an existing app may affect it? Another thing to check is if you’ve enabled iAds for your app in iTunes Connect.
Is i have to enabled iAds in iTunes Connect to test it on device? and regenerate my Provisioning Profile?
Thanks for the tutorial, it was really helpful, especially the tableview stuff. I *hate* interface builder, and I had multiple tableviews to change, so I made a quick class that you can just subclass to get an iAd enabled UITableViewController. There seems to be no way to post code here, but you’re welcome to it if you want.
@Ray thank you so much for ur reply.
@Justin: Cool! A good way to post code snippets for people to use online is to use the following site and post a link:
https://gist.github.com/
Good plan. Try this:
https://gist.github.com/676210
or this:
git clone git://gist.github.com/676210.git gist-676210
It’s pretty much all your code, I just needed to add a few lines to make sure the table view is resized correctly – not sure if IB does this automatically.
Just subclass this, and in your subclass’s init method make sure you call:
[super initWithStyle:(UITableViewStyle)style];
That’s it.
The same could be done with the normal uiviewcontroller, but I haven’t got around to that yet…
Thanks again for the tutorial. Saved me heaps of time.
@Justin: Thanks for your code!!
It works great on the iPhone but if you use it in an iPad project inside a UISplitViewController it has an offset to the right side.
any idea why?
@Justin: It doesn’t resize when the device rotates either
@Justin: Cool man, thanks for sharing, looks like it will be really handy for others!
@Jorge: As far as the gap goes, can you post a screenshot so we can see what you’re seeing? As far as getting the view controller to rotate, you need to implement shouldAutorotateToInterfaceOrientation.
I added this code to solve it
- (void) viewDidAppear:(BOOL)animated {
_contentView.frame = self.view.bounds;
_tableView.frame = _contentView.bounds;
[self fixupAdView:[UIDevice currentDevice].orientation];
}
Hi;;
iAd is working in simulator(4.0). But when deployed application on ipod (4.0), it is not appearing,even as Test advertisements. Please help…….
I am from India…..Is that a problem….???
@Jorge: Nice!
@Ashish: Not sure, apart from the suggestions from others in the comments above.
Late back to the party on this one, but looks like it’s sorted. I’ve only been working on iphone with portrait orientation so far, so I didn’t test it as thoroughly as I might have. Whoops.
Hello Ray.
Thank you for this tutorials. It is awesome.
I have a problem with the backward compatibility. My application runs on iOS 3.1.2, but I don’t have iAds.
I don’t have any warnings at build, but iAds banner does not appear. Strangely all the functions run without errors, but with no iAds banner display.
Best Regards,
Andrei Neacsu
Hi Ray,
I was looking to make my app support iAds, but also still OK to work on OS3.2. This tutorial is awesome. Thanks a lot man!
@Andrei: That’s exactly what should happen – iAds are only supported on iOS 4+, so obviously the older devices can’t show ads. The backwards compatibility is meant to make your code not crash on the older devices :]
@Emir: Cool glad it helped! :]
tks for the useful tutorial.
i’ve got this doubt.
i guess that there are revenues also for (just) the adv exposed, not only when the user click on it,
and i guess that revenues for just expose adv
in our apps start just if advs are visible for some (how many?) seconds.
i wonder if “this timer” in your app with the 2 views starts again from zero everytime a user click and change view, reloading a new adv…
in this case it would be probably better to load a “sueper” adv-layer which never stop and just change position when the view change…
do you think it could be possible in an app like the one in your tutorial?
tks again
luca
HI ray…
i have this error
“_ADBannerContentSizeIdentifier480x32″, referenced from:
_ADBannerContentSizeIdentifier480x32$non_lazy_ptr in iDemotivational_LiteViewController.o
(maybe you meant: _ADBannerContentSizeIdentifier480x32$non_lazy_ptr)
ld: symbol(s) not found
collect2: ld returned 1 exit status
-.- any ideas?
i fix this problem… but iad don’t appear… also in your source code… is a problem with new iOS?
Went through this tutorial yesterday and it worked like a charm. Thanks Ray!
Also, the code for Part 3: fixupAdView can be DRY’d up like this:
- (void)fixupAdView:(UIInterfaceOrientation)toInterfaceOrientation {
if (_adBannerView != nil) {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
[_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier480x32];
[self layoutAdBannerView:0 contentViewFrame:[self getBannerHeight:toInterfaceOrientation]];
} else {
[_adBannerView setCurrentContentSizeIdentifier: ADBannerContentSizeIdentifier320x50];
[self layoutAdBannerView:-[self getBannerHeight:toInterfaceOrientation] contentViewFrame:0];
}
[UIView beginAnimations:@"fixupViews" context:nil];
if (_adBannerViewIsVisible) {
} else {
}
[UIView commitAnimations];
}
}
- (void)layoutAdBannerView:(int)adBannerViewFrameHeight contentViewFrame:(int)contentViewFrameHeight {
CGRect adBannerViewFrame = [_adBannerView frame];
adBannerViewFrame.origin.x = 0;
adBannerViewFrame.origin.y = adBannerViewFrameHeight;
[_adBannerView setFrame:adBannerViewFrame];
CGRect contentViewFrame = _contentView.frame;
contentViewFrame.origin.y = contentViewFrameHeight;
contentViewFrame.size.height = self.view.frame.size.height – contentViewFrameHeight;
_contentView.frame = contentViewFrame;
}
Thanks for this tutorial.
@luca: Good question, never thought of that, not sure how it affects the revenue. Yeah that does seem like a good way to do it, you could have a little helper class to manage the view or some such.
@Andre: Not sure, the ads appear OK in the example for me.
@Gavin: Cool, thanks for sharing the code!
Ha, every time i need a hand with something in my app, google always directs me to your site! Fantastic work Ray!!!
@Christopher: Lol! Good to see the site’s getting some traction with Google :]
I have a problem. The callback “bannerViewDidLoadAd” is never called. only “didFailToReceiveAdWithError” is called each time and the ad Banner is never shoed.
I followed the steps exactly, any clue ???