Wednesday, February 06, 2013

Add iAd to PhoneGap Application

This post derives from the SiteKickr Blog post "PhoneGap/Cordova and iAd integration." I got stuck in a couple of spots and decided to attempt to lend a little clarity for anyone else seeking a solution. I've also taken a couple of the comments from that post and integrated here.

1. Click on the "Project Navigator" icon in the left most panel in XCode.



2. Click on the top-most item in your hierarchy. 



3. Click on the Build Phases tab. 



4. Expand "Link Binary with Libraries."



5. Click the + icon to add the iAd.framework to your project.



6. In your App -> Classes folder, open up MainViewController.h, and drop in the following code after any existing #import statements but before @end:

 #import <iAd/iAd.h>
 @interface MainViewController : CDVViewController {  
   ADBannerView *adView;  
 }   



7. Open up MainViewController.m


8. In your viewDidUnload method, which should already exist, add:

 [adView release];   



9. In your webViewDidFinishLoad method, add the following just before: 
"return [super webViewDidFinishLoad:theWebView];"

   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.width-adView.frame.size.height;  
   }  
   adView.frame = adFrame;  
   [self.view addSubview:adView];  


10. If you don't already have a willAnimateRotationToInterfaceOrientation method, add it, and drop in the following code:

   BOOL hide = (newInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || newInterfaceOrientation == UIInterfaceOrientationLandscapeRight);  
   [[UIApplication sharedApplication] setStatusBarHidden:hide withAnimation:UIStatusBarAnimationNone];  
   CGRect mainFrame = [[UIScreen mainScreen] applicationFrame];  
   [self.view setFrame:mainFrame];  
   if (newInterfaceOrientation != UIInterfaceOrientationLandscapeLeft && newInterfaceOrientation != UIInterfaceOrientationLandscapeRight) {  
     adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;  
     [self.view bringSubviewToFront:adView];  
     adView.frame = CGRectMake(0.0, self.view.frame.size.height - adView.frame.size.height, adView.frame.size.width, adView.frame.size.height);  
   }  
   else {  
     adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;  
     [self.view bringSubviewToFront:adView];  
     adView.frame = CGRectMake(0.0, self.view.frame.size.width - adView.frame.size.height, adView.frame.size.width, adView.frame.size.height);  
   }  


A couple of points of note regarding ad placement:
- iAd is not like Adwords or Admob. Ad placement is not done in your HTML and does not use your javascript or CSS.

- By default, the ad will be placed on the bottom of your app's UI. To change the position of the ad, you'll need to edit all instances of the value of adFrame.origin.y to equal 0 (adFrame.origin.y=0).

- After you're done and ready to deploy, you'll need to enable iAd in your application through iConnect. Keep in mind you can only do this AFTER you upload your app.

  1. Log in to iTunes Connect
  2. Click on "Manage Your Applications"
  3. Click on the App you want to enable iAd on.
  4. Click on the blue "Set Up iAd Network" button.
  5. Follow the instructions.

That's it! Good luck.

UPDATE 03.06.2013: Check out this great response at StackOverflow regarding not showing the ad placeholder if an ad is not delivered: http://stackoverflow.com/a/14764349/2037540

UPDATE 04.17.2013: Brandon Hawkins has come up with a great solution to deal with the issue of the ad frame setting on top of the webview. Check it out here: http://hawkinbj.wordpress.com/2013/04/16/implement-iad-banner-ads-without-covering-uiwebview-in-phonegap/

28 comments:

  1. Hi Scott,

    Many Thanks for filling the gap. I was able to integrate it in a phonegap application, but ran into a couple of issues.

    After integration of Step 10, Xcode ran into errors and pointing to teh statement

    if (newInterfaceOrientation != UIInterfaceOrientationLandscapeLeft && newInterfaceOrientation != UIInterfaceOrientationLandscapeRight)

    Errors:

    Expected ';' after expression
    Use of undeclared identifier 'amp'
    Expected Expression

    Look forward to your assistance.

    -
    Nikhil

    ReplyDelete
  2. Hi Nikhil,

    What version of XCode are you running?

    Scott

    ReplyDelete
  3. Hi Scott,

    Xcode version is 4.6

    Nikhil

    ReplyDelete
  4. Try copying and pasting the code from step 10 again. I updated it a few days ago. The new code should address your problem.

    ReplyDelete
  5. Ok, Will try and keep you posted.

    Would you be recommending any best practices to prevent App rejection coz of iAD plugin. I mean any pit falls, One can take care of.

    Thank!!!

    ReplyDelete
  6. Hi Scott,

    I must say, I got caught in the midst of Phonegap Plugins, as I was trying your piece of instructions coupled with that. Daaaaa. I think I was trained myself to do so coz of integrating Phonegap Plugins with the Phonegap Apps.

    Many Thanks, it would seamlessly. Do we have instructions to avoid there warning in the console.

    ADBannerView: Unhandled error (no delegate or delegate does not implement didFailToReceiveAdWithError:): Error Domain=ADErrorDomain Code=3 "The operation couldn’t be completed. Ad inventory unavailable" UserInfo=0xac4a450 {ADInternalErrorCode=3,
    ADInternalErrorDomain=ADErrorDomain, NSLocalizedFailureReason=Ad inventory unavailable}
    ADBannerView: Unhandled error (no delegate or delegate does not implement didFailToReceiveAdWithError:): Error Domain=ADErrorDomain Code=5 "The operation couldn’t be completed. Banner view is visible but does not have content" UserInfo=0xad1f0c0 {ADInternalErrorCode=5, ADInternalErrorDomain=ADErrorDomain, NSLocalizedFailureReason=Banner view is visible but does not have content}

    ReplyDelete
  7. Unfortunately, I don't. Is the app running in the simulator? Are you seeing a blank area in the app that an ad should be?

    ReplyDelete
  8. Yes, exactly that is the problem. I see a blank screen when deployed onto the device.

    ReplyDelete
  9. I even tried this.

    http://stackoverflow.com/questions/14764313/how-to-hide-iad-banner-when-no-ads-are-available-i-know-absolutely-nothing-abou/14764349#14764349

    I Think placement of adView.hidden = YES; in the original method is the key. Can you help me understand which method is being referred here.

    Many Thanks Scott for all the help.

    Regards,
    Nikhil Juneja

    ReplyDelete
    Replies
    1. Regarding adView.hidden, you'll want to add the following to your MainViewController.m:

      - (void)bannerViewDidLoadAd:(ADBannerView *)banner {
      adView.hidden = NO;
      }

      - (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error {
      adView.hidden = YES;
      }

      Delete
  10. Thanks Scott. The Apps Will be live this month

    Nikhil

    ReplyDelete
  11. iad banner sometimes display white bannner xcode 4.5 and phonegap 2.2.0

    ReplyDelete
    Replies
    1. Check out this great response at StackOverflow regarding not showing the ad placeholder if an ad is not delivered: http://stackoverflow.com/a/14764349/2037540

      Delete
  12. Great tutorial. I have one problem. The ad frame is on top of the webview where my html is. Any idea how to fix this? I am using latest Cordova 2.6.0
    Thanks again for the great tutorial!

    ReplyDelete
    Replies
    1. Hi Boyan. I actually just place the ad at the bottom of the view and add some bottom padding to the html. Would that work for you?

      Delete
    2. The padding will do yes. But I wes hoping for some more native solution. I guess it will be hard to be done without changing some Cordova code.
      10x for the quick responce

      Delete
    3. Is there a non-html way to do this? Thanks!

      Delete
  13. Hey Scott, fantastic tutorial. I am using the Sencha Touch HTML5/javascript framework and have the same problem with ads covering actual content (anchored tabs/buttons). Is there a non-HTML solution to this problem? Thanks so much

    ReplyDelete
    Replies
    1. Thanks Hawk. I haven't found a native fix but, if you do, please come back and post it and I'll add it to the tutorial. Thanks again.

      Delete
    2. Found a solution :) I blogged about it here http://hawkinbj.wordpress.com/2013/04/16/implement-iad-banner-ads-without-covering-uiwebview-in-phonegap/

      Delete
    3. Great work Brandon. I've added a link to your blog in an update at the bottom of this post. Thanks again.

      Delete
  14. Anonymous2:57 PM

    "Keep in mind you can only do this AFTER you upload your app."
    Is there any difference between if you do it before you upload the app (but after you created the version) vs. after you upload the app?

    ReplyDelete
    Replies
    1. I'm not 100% sure on that. You'll just have to try it out.

      From Apple: You can only change your iAd Settings when the latest version of your app is in an editable state. Refer to the iTunes Connect Developer Guide for a list of editable states. http://developer.apple.com/library/ios/iTunesConnectGuide

      Delete
  15. Excellent tutorial.

    I wanted to put the ad on top of the app. I did the following and it worked:

    adFrame.origin.y = 0 (I found 2 instances) inside MainViewController.m

    Now what is happening is that the ad is there but the entire app is showing up I mean all divs not only the first one.

    I probably missed something. Any help would be greatly appreciated.

    Thanks,

    Fernando

    ReplyDelete
    Replies
    1. Sorry Fernando, I run my ads on the bottom so I've not personally run into your problem. I'd suggest running your HTML through a w3c validator or similar. You may find an unclosed tag or something simple.

      Delete
  16. thanks.
    is it possible to turn it off/one from phonegap javascript, any suggestions maybe?

    ReplyDelete
    Replies
    1. Not that I'm aware of Xin.

      Delete
  17. Jouhayna12:53 PM

    Thank you very much!!! great on SDK 7.0

    ReplyDelete