PhoneGap / Cordova and iAd integration

PhoneGap (Cordova) users, you are no doubt used to dealing with PhoneGap plugins to interact with frameworks, to keep your distance from having to dive into Objective-C. Well, in the case of iAd integration, you might actually find that the native approach is easier.

What's one of the biggest headaches as the layers of abstraction get higher and higher – dependencies. Finding the right plugin to match your version of PhoneGap, and integrating it requires another layer that just isn't necessary.

I'm going to describe the step to integrate iAd into your PhoneGap application, leaving you amazed at how simple it is. Note that I'm walking through this using XCode 4.3.2. The steps may be different for earlier/later releases.

  1. Click on the top-most item in your hierarchy, the target. In the Build Phases tab, expand Link Binary with Libraries.
  2. Click the + icon to add the iAd.framework to your project.
  3. In your app -> Classes folder, open up MainViewController.h, and drop in the following code:

    #import <iAd/iAd.h>

    @interface MainViewController : CDVViewController {
        ADBannerView *adView;
    }

  4. Open up MainViewController.m

  5. In your viewDidUnload method, add:

    [adView release];

     

  6. In your webViewDidFinishLoad method, add:
     

    adView = [[ADBannerView alloc] initWithFrame:CGRectZero];

    if([UIApplication sharedApplication].statusBarOrientation == 
        UIInterfaceOrientationPortrait ||
       [
    UIApplication sharedApplication].statusBarOrientation ==
        UIInterfaceOrientationPortraitUpsideDown) {
      adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
    }
    else {
      adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
    }


    adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
    CGRect adFrame = adView.frame;
    adFrame.origin.y = self.view.frame.size.height-adView.frame.size.height;
    adView.frame = adFrame;
    [self.view addSubview:adView];

     

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

    - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)newInterfaceOrientation duration:(NSTimeInterval)duration {

      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);

       }

    }

 

 

Steps 1-6 should be somewhat straightforward, but let's talk about step #7 a bit.  Essentially what we're doing here is handling the change in orientation of the phone from portrait to landscape mode, and vice-versa. iAd advertisements have different sizes which are better suited to a given orientation. But, this is not handled automatically.

You need to adjust not only the size of the ad displayed, but also it's position in the view, whenever the orientation is changed. One of the most confusing aspects, is that although the orientation has changed, the dimensions stick.

For example, in portrait mode, self.view.frame.size.width will read 320. However, it reads the same dimension even in landscape mode. So, to properly place the ad in landscape (if you wish to place it at the bottom of the view), we need to subtract the ad height from the frame width.

Why follow me on Twitter?

  • I tweet about new technologies, services or libraries I find interesting
  • Yeah, sometimes I'll post a pet-peeve or rant about something trivial
  • If I discover something that made my web development life easier, I share it
  • I'll shout out any handy tip that I think might be useful to other devs


Tagged .

Updated: 2012-07-26

Phil LaNasa follow us in feedly
  • Ed Farias

    This worked great, thank you.  I was really struggling getting the phonegap plugin to even work, and this work right away.
    Quick question, it works in all of my simulator tests except for iPhone 4.3.  Works for iPad 4.3, Ipad and Iphone 5.0.  Any ideas?

    • admin

      That does seem odd. What do you mean by “doesn’t work”? I’ve had success with the iPhone 4.x simulator. But, it’s common, at least for me to see delays before the ads show up.

  • http://zsprawl.com Sprawl

    This page helped me tremendously after taking a break from PhoneGap since version 1.5 and coming back to a command-line centric Cordova. This got my iAds going again, and smoother than before with the normal plugin, so thank you!

  • Mike

    Hey great article I will probably end up using this for my Phonegap project… just one question:

    How do you place the ad on the app? I want the ad unit placed near the top of the screen, how do I do that?

    Thanks a lot for taking the time to write this article, I find it hard to find good articles on Phonegap!

    -Mike

    • admin

      I haven’t actually tested this, but have a look at this line:

      adFrame.origin.y = self.view.frame.size.height-adView.frame.size.height;

      If you changed it to:

      adFrame.origin.y = 0

      I imagine that would do the trick.

  • niz91

    hello, i'm using phonegap 2.1 with xcode 4.4.1 but  this don't worked for me.
    any solution please?

    • admin

      The phonegap version shouldn’t matter, nor the Xcode version I wouldn’t think. But, has this worked for you in prior versions of either?

      Do you at least see a “blank placeholder” where an advertisement should be?

  • niz91

    i don't see a blank placeholder. i don't have error, nothing….
    i tried with xcode 4.3.3, 4.4.1 and 4.5.1.
    i do exactly the tutorial . how can i call the banner and shoose in what page of the app display it?

    • admin

      I’m not sure you’ll have that kind of fine-grained control when using PhoneGap. PhoneGap essentially wraps your entire app in WebView element, the iAd container lives outside that element. So, I’m not certain how PhoneGap would communicate which page is currently loaded to the iAd container. Doable, I’m sure, but you’ll likely need to build a phonegap plugin, or modify the existing iAd plugin.

  • niz91

    it's ok it's work now, my error in the step 6, i put the code a the end of the method.
    i have to put the code a the beginnig.
    but now i have a problem : ADBannerView: WARNING A banner view (0x89506e0) has an ad but may be obscured. This message is only printed once per banner view.
    my ad dispalying correctly, i don't know why i have this error

    • admin

      Step in the right direction. I received this “warning” during development as well, and chose, in the end to ignore it. I had expected the warning when the ad actually was obscured. But, from what I know, if you implement the ad code this way, there’s no way it can be obscured by your PhoneGap application code, as it’s all run within a separate Web View container.

  • http://www.interactivetextbooks.co.uk Iain Coleman

    Hi,
    I followed the exact steps above, but only get the Test Advertisement banner when i rotate the device. Once I have rotated the device, the ad will continue to display.  My app only supports landscape – is this an issue? Do I need to change anything?  In Step 7, you mention adding the method- is this just a case of copying the code into MainViewController.m or do I need to do something else as well?
     
    Thanks for any assistance!

    • admin

      You have definitely set the testing flag to false? No other code should be necessary, other than that in the MainViewController.m (except of course for the various setup steps, such as adding the iAD library, etc.)

      Is your ad at the top or bottom of the web view?

  • http://www.interactivetextbooks.co.uk Iain Coleman

    I'm not sure how to set the testing flag to false sorry. I tried again with an app that runs both portrait and landscape and all seems to work well – very strange! Ads appear at the bottom and move correctly when the orientation changes. Thanks for such an excellent post and for your help, if you have any ideas about the landscape only issue I would be very grateful!

     

  • franztini

    First, Thank you soo much for posting this! I have been struggling trying to get the SAIOSadplugin to work with Cordova 2.0 (have it working great with Phonegap 1.41) and this works and the ad rotates properly between landscape and portrait.  In my iphone app that only supports portrait – works like a charm.  However my ipad app supports both portrait and landscape and I have an issue. 
    1.  No matter what orientation my device is in, when I click on the ad it opens up in Landscape.  So if I am in portrait, the ad displays properly at the bottom, but when it is clicked on the ad is displayed in Landscape.  If the device is in Landscape, and the ad is clicked on  it displays properly in landscape but when the ad is closed, the app content is 'redrawn' to be in portrait (so there is a black area to the right of the content.  
    Any thoughts? 

    • admin

      I unfortunately don’t have any experience with ads on the iPad. I might suggest taking a look at the various methods that are in the main view controller file, to see if you can leverage any of them. Many events are exposed that help you deal with orientation changes.

  • marco rossetti

     
    Thank you very much for your tutorial !
    One simple question: is it possible to set an initial background color in the placeholder?

    • admin

      I asked myself the same question a while back, I came up empty on Android / AdMob integration, so I wonder if there’s a deeper reason for not allowing this. Or, perhaps it’s possible and I haven’t figured it out yet.

  • marco rossetti

    Thanks anyway for the answer

  • franztini

    Thanks for the response.  I will play around with it and if I can come up with a solution I will let you know.

  • Marco

    This is very nice, as a Phonegap/cordova I didn't know that it was that easy to make it work. Otherwise, I see two problems: the ads are opening always in Landscape mode and there's a blank placeholder when the ad is not loaded. I am not really worried about the first one but the second one is important because Apple use to reject that kind of apps :(

    • admin

      Right, that’s as far as I took my example. You could further refine it to check for the presence of an ad, then hide the ad container if an ad is not available.

  • http://www.playfuljack.com Doug

    Here is a fix for the "starting in landscape mode".  The code in step 6 assumes portrait so if the iPad is in landscape the adview is off in lala-land somewhere.  Enjoy!
     
     
        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];

  • http://www.dazindustries.co.uk Darryl Bayliss

    Hey folks, just giving you a small update/hint to this tutorial.
    In the latest version of the Phonegap project (2.2.0 at time of writing) the method name in step 7 is not:
    - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)newInterfaceOrientation duration:(NSTimeInterval)duration
    But infact:
     
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
     
    The issue I had was that the above steps worked, but only when I changed orientation of my app, what you need to do to ensure it works is the following:
     
    1. Copy and paste the body of the method from step 7 into the body of this method (its still in the MainViewController.m file)
     
    (BOOL)shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation)interfaceOrientation
     
    2. Change all the parameter references from newInterfaceOrientation to InterfaceOrientation
     
    3. Test your app!
     
    Hope this helps.
     

  • Robin Bakker

    This doesn't works for me, I don't understand why. it says: "unknown type name 'adView', did you mean 'UIView'?" why does it says this?

    • https://plus.google.com/116836664622246328208/posts admin

      Did you instantiate the adView variable as follows?

      ADBannerView *adView;

      Your error suggests that maybe you did something like this:

      adView *AdBannerView

  • Bobby

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

    • https://plus.google.com/116836664622246328208/posts admin

      It’s been a while for me, but I believe you just open up MainController and move the ad code to below where index.html is loaded.

      • http://brandonjhawkins.com Brandon

        I too have the same question. Unfortunately, index.html is not explicitly loaded in MainController because it's only referenced in config.xml so it's not clear where to move the iAd code. Would be much appreciated if anyone could post a solution.

        • https://plus.google.com/116836664622246328208/posts admin

          I haven’t touched PhoneGap in a while, so it’s likely I’m way behind on recent developments. What does the MainController look like at this point?

          I imagine MainController must be used in some way, to load values in config.xml?

  • Francisco

    Hi, Thanks for the explanation. It is great.
    I am using phonegap 2.6. The ads show perfectly in the simulator, but when I run it in the iphone then the ads wont show but there is a blank space.
    Does any one know what is the problem?
    Maybe someone could put a demo in github with iads working correctly in the simulator and on the iphone.
    thanks

    • https://plus.google.com/116836664622246328208/posts admin

      I’ve had this happen before. I waited a few hours and the ads started appearing.

  • http://brandonjhawkins.com Brandon

    For those having an issue with the ads covering the screen/app content, I blogged my solution here http://hawkinbj.wordpress.com/2013/04/16/implement-iad-banner-ads-without-covering-uiwebview-in-phonegap/