Friday, May 25, 2012

Cordova (PhoneGap) and AdMob Together: iOS Version

Ads are one the easiest ways for a developer to get paid for an app. Apache Cordova, the new name for PhoneGap, is one of the easiest ways to develop apps for the iOS and other platforms. The problem is how to combine the two of them? Nothing in the official documentation of either says how to do it. After a long evening of hacking, I have gotten it to work for me and here is how I did it.


Some assumptions before we begin: 

  • XCode version 4.3.2
  • Apache Cordova version 1.7.0
  • AdMob version 6.0.3 (6.0.4 uses the device's UDID, which creeps me out)


1. Get Your App Working


The first step is to get your Cordova app working. In my case I am using my calculator example that I introduced a few tutorials ago. You can use whatever app you have just keep in mind that AdMob will need 320x50 pixels, so be sure to leave it some room. 


2. Copy the AdMob Files


Now we copy the AdMob files into the project. Right-click on your project name in Xcode, choose Add Files to "your project name"... Select all of the files except "README.txt" and the "Mediation" folder. 


3. Add Some Missing Frameworks


The following frameworks need to be added to your project:

  1. AudioToolbox
  2. MessageUI
  3. SystemConfiguration
  4. CoreGraphics
Double click the project name to show the settings page. Click the tab marked, "Build Phases". Click the accordion marked, "Link Binary With Libraries". Click the plus sign in the lower left corner, in the dialog box that appears select all of the missing frameworks, then click the "Add" button. 

4. Add the Code

In the file, MainViewController.h, add the import statement:

#import "GADBannerView.h"

Add the banner view declaration:

@interface MainViewController: CDVViewController {
  GADBannerView *bannerView_;
}
@end


Added and define the MY_BANNER_UNIT_ID near the top of MainViewController.m.

#define MY_BANNER_UNIT_ID @"YourPublisherId"

5. Modify the viewDidLoad
After the [super viewDidLoad] add the following code:


6. Modify the viewDidUnload

Release the bannerView_ in the viewDidUnload method:

[bannerView_ release];

7. Modify the Cordova.plist

In order for AdMob to get ads from its server, you need to permit it. Expand the "Supporting Files" folder. Then click the "Cordova.plist". Open the ExternalHost, click the plus sign, and the type "*". The asterisk says to permit all outside connections to go through. You can make this list as exclusive as you'd like. If you don't do this you will see the following error in Xcode's console output section:

ERROR whitelist rejection: url='http://media.admob.com/sdk-core-v40.js

8. Try It Out

Try launching your app and you should see the Google banner ad at the bottom of the page. If you click it, it will take you to another page. 

If you need a bit more help I have include the full source code to the Cordova calculator with the AdMob ad. Don't freak out, the name of the project is DelMe3, not calculator. It is a huge project though at 10.6 MB. I wasn't too sure what I could safely leave out of the project, so I included it all.
  

Full Source Code, 10.6 MB


40 comments:

  1. Thanks for this fantastics tutorial! :) I've a problem with iPad... How can i set the Ads at Bottom in iPhone and iPad, for universal app? In iPhone it work, but in iPad i see the Ads in middle of the screen... I'm using "kGADAdSizeSmartBannerPortrait"...
    MY CODE:
    bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeSmartBannerPortrait];
    // Must be a better way to position at bottom of page
    [bannerView_ setCenter:CGPointMake(kGADAdSizeBanner.size.width/2, 435)];

    Help me please! :) Thanks again!

    ReplyDelete
    Replies
    1. Here is the video tutorial in ITALIAN and ENGLISH:

      http://youtu.be/PPrBHzxc-QY

      Thanks to Troy Miles for the Tutorial.

      Delete
  2. Hi Hardy,
    In viewDidLoad, replace the code after bannerView_ = ... with the following:

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGFloat screenWidth = screenRect.size.width;
    CGFloat screenHeight = screenRect.size.height;
    CGFloat screenXPos = (screenWidth/2);
    CGFloat screenYPos = screenHeight - kGADAdSizeBanner.size.height;
    [bannerView_ setCenter:CGPointMake(screenXPos, screenYPos)];

    This works for iPhone and iPad. I will update the blog later in the week. I am in the middle of moving all of my source files to GitHub.

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Hi niz91,

      It appears that your code has a syntax error on the following line:
      bannerView_ = CGRect screenRect = [[UIScreen mainScreen] bounds];

      It should read:

      CGRect screenRect = [[UIScreen mainScreen] bounds];

      Let me know if that works.

      Troy

      Delete
    3. thank you, it's working but i still have the banner in the middle of the screen

      my code :

      - (void) viewDidLoad
      {
      [super viewDidLoad];


      // Create a view of the standard size at the bottom of the screen.
      // Available AdSize constants are explained in GADAdSize.h.
      bannerView_ = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
      CGRect screenRect = [[UIScreen mainScreen] bounds];
      CGFloat screenWidth = screenRect.size.width;
      CGFloat screenHeight = screenRect.size.height;
      CGFloat screenXPos = (screenWidth/2);
      CGFloat screenYPos = screenHeight - kGADAdSizeBanner.size.height;
      [bannerView_ setCenter:CGPointMake(screenXPos, screenYPos)];






      // Must be a better way to position at bottom of page
      [bannerView_ setCenter:CGPointMake(kGADAdSizeBanner.size.width/2, 435)];

      // Specify the ad's "unit identifier." This is your AdMob Publisher ID.
      bannerView_.adUnitID = MY_BANNER_UNIT_ID;

      // Let the runtime know which UIViewController to restore after taking
      // the user wherever the ad goes and add it to the view hierarchy.
      bannerView_.rootViewController = self;
      [self.view addSubview:bannerView_];

      // Initiate a generic request to load it with an ad.
      GADRequest *request = [GADRequest request];
      // remove this line when you are ready to deploy for real
      request.testing = YES;
      [bannerView_ loadRequest:request];


      // Do any additional setup after loading the view from its nib.

      }

      Delete
    4. it's ok i forgot the delete : [bannerView_ setCenter:CGPointMake(kGADAdSizeBanner.size.width/2, 435)];

      thank you

      Delete
  3. Now it works! Thank you so much! Have a nice day! :)

    ReplyDelete
  4. My pleasure. Be sure to follow on Twitter @therockncoder. I will be doing more posts on PhoneGap and jQuery Mobile and I always announce on Twitter first.

    ReplyDelete
  5. Ok thanks for Twitter Troy! I have a problem when I go to create the archive of the app and I get this error:

    warning: iPad: icon.png: icon dimensions (57 x 57) don't meet the size requirements. The icon file must be 72x72 pixels, in .png format (-19014)
    Unable to validate your application. - (null)

    I searched on the internet but nothing ... You know how to solve this problem? only occurs when I create universal app. is a problem of icons... Thanks again! :)

    ReplyDelete
  6. Ok, I solved the problem! :) Sorry for the double post!

    ReplyDelete
    Replies
    1. Hi Nick,
      I'm not sure of the solution that Hardy found, but I know that the dimensions for iPad icons is different than those of the iPhone. Apple has pretty good documentation on this at: http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html

      Let me know if this helps.

      Delete
    2. Hi Nick, Troy is right the guide is perfect, but there are other problems that occur with XCODE... Soon I will make a video tutorial to solve this and other problems related to XCODE...

      Delete
  7. Troy, thanks for a great tutorial. I can't download the DelMe3 source code. Could you update the link to the source code?

    ReplyDelete
    Replies
    1. Sorry, about that. I have been moving files around a lot preparing for the release of my app and for Code Camp San Diego. The file has been re-uploaded to my site.

      Delete
  8. Troy, Please contact me at meirliraz(at)gmail.com. I need your professional help.
    Thanks, Meir

    ReplyDelete
  9. Hi,
    I've implemented your code and it work, but I have 2 problem:
    -The ad cover the web view, how can I resize/autoresize the web view when the ads is loaded?
    -The banner size is 320x50, but a 320x35 banner is loaded from admob, so the bottom part of the ad is empty, what's wrong? THere's something to setup to have 320x50?

    Finally, that's not a problem, how to set the refresh time of the ads?
    Is better if I set on the admob cp?
    Thanks
    Regards Mix

    ReplyDelete
    Replies
    1. Hi Daniele,

      Unfortunately all of the things you ask about are beyond your control. AdMob sells the ads in your app based on the max size of the ad container. Sometimes they fill the container completely, other times the ad is smaller, but there is no way to know what size the ad will be. Likewise timing is beyond your control.

      But there are other ad providers, which may be able to address your need.

      Troy

      Delete
    2. HI Troy,
      Thanks for the awnser!!!

      Only the last question: ho can I resize the web view? At the moment the ad cover it and I need to resize the web view to -50px (when the ads is loaded)

      There's any event when the ad is loaded that I could use to resize?

      THere's any common solution used to solve that problem?

      Thanks again
      Daniele

      Delete
    3. Hi Daniele,

      I will take another look at the code once I arrive home this evening and make it more flexible. Not sure how long it will take but hopefully I will have an answer tomorrow. Also I want to get ads working on Android too. You might want to follow me on Twitter @therockncoder. I always announce new posts there first.

      Delete
    4. Hi Troy,
      Thanks again, I'll wait ;-)

      On android is very simple to do, there's a wiki on the phone gap site that work (I've used the method 2)
      http://wiki.phonegap.com/w/page/51172827/HOW%20TO%3A%20Add%20admob%20ads%20to%20your%20phonegap%20application

      It's perfect and auto-adapt the web view

      Thanks again!

      Delete
    5. If anyone is interested this is the code to resize the web view:

      CGRect viewfr = self.view.frame;
      viewfr.size.height = bannerView_.frame.origin.y;
      self.view.frame = viewer;


      I've put that in the adViewDidReceiveAd function that occur when the ad is loaded (so if it's not loaded the web view have the full height).

      This is the code to put above the @end in MainViewController.m:
      - (void) adViewDidReceiveAd:(GADBannerView *) banner {
      CGRect viewfr = self.view.frame;
      viewfr.size.height = bannerView_.frame.origin.y;
      self.view.frame = viewfr;
      }

      To make it work you need to add 2 other line:

      In MainViewController.m, below the "bannerView_.adUnitID = MY_BANNER_UNIT_ID;" added before, add this
      bannerView_.delegate = self;

      In MainViewController.h add after "@interface MainViewController : CDVViewController" this


      so the line look in this way after:
      @interface MainViewController : CDVViewController {

      @troy: if you wanna, you can add at your code in the tutorial
      bye

      Delete
    6. This comment has been removed by the author.

      Delete
    7. blogspot have filtered the code to add couse the < and > tag, this is the code < GADBannerViewDelegate >
      (remove the space before > and after <)

      bye

      Delete
    8. Hi Daniele, I tried your code, but I have a problem: Now the ad banner doesn't cover the bottom of the page, but if I try to click on it, nothing happens. Why? Thanks in advance for your reply. I tried to contact you by google plus, sono italiano se vuoi puoi rispondermi anche in italiano ;-) )

      Delete
    9. same issue here, the ads is not clickable anymore !

      Delete
  10. This comment has been removed by the author.

    ReplyDelete
  11. I kind of have the same problem, everything works fine, but I would like to re-size the webview. Where can I do that? And I don't really understand how to size it for the Ipad. The banner always is in the middle of my application :(

    Thank you soo much for the great work!

    ReplyDelete
    Replies
    1. i think it is not called webview for iOS I search the iOS solution :)

      Delete
    2. Hi Tim,
      for the problem of the iPad there's a comment of troy with the right code for both iPad & iPhone, check above.

      Here's the code:

      In viewDidLoad, replace the code after bannerView_ = ... with the following:

      CGRect screenRect = [[UIScreen mainScreen] bounds];
      CGFloat screenWidth = screenRect.size.width;
      CGFloat screenHeight = screenRect.size.height;
      CGFloat screenXPos = (screenWidth/2);
      CGFloat screenYPos = screenHeight - kGADAdSizeBanner.size.height;
      [bannerView_ setCenter:CGPointMake(screenXPos, screenYPos)];

      Bye
      Daniele

      Delete
    3. This comment has been removed by the author.

      Delete
  12. I got it to work thank you very much :)

    I solved the problem with the webview by adding some empty space in my html file. That works fine for me.

    ReplyDelete
    Replies
    1. I've solved with the code I've write above ;-)

      (so you can make a page with scroll like in my app)

      Delete
  13. Hi,

    Thanks for this excellent article! I have been following these guidelines along with the code to dynamically resize the webview. The ads are showing up fine, but nothing happens when I try to click the ad links.

    Having never worked with iOS before I'm not sure how to solve this, so wondering if you or anyone else reading this know what might have gone wrong?

    This issue does not occur when I'm not dynamically resizing the webview.

    my code:
    http://pastie.org/4461308

    Thanks
    /Ksprrrs

    ReplyDelete
  14. Just as a heads up, for iOS6 and Cordova 2.1.0 I had to add the ad support framework as well.

    ReplyDelete
  15. Thanks for the Tutorial, I just ran into some Mach-O-Linker Errors using Cordova/Phonegap 2.2.0 and xcode 4.5. Adding the StoreKit Framework did the trick. I followed this guide from Google https://developers.google.com/mobile-ads-sdk/docs/

    Anyway theres a problem i didn't solved yet:

    When the app is started and the device has no internet connection, the admob banner is not displayed. the rest of the app works as its supposed to be. so far so good.

    problem is, when the device establishes an internet connection during your use of the app, or even when the app is minimized in the background (and you've once opened it without connection), admob don't seem to try to "call home" again.

    anyone has an idea how to solve that? is there a way to connect phonegaps "online" eventlistener to the creation of the admob banner?

    thanks, mike

    ReplyDelete
  16. Awesome. I followed above and also this tutorial helped even though it's italian

    http://www.youtube.com/watch?v=4r4nQLc2Fas

    ReplyDelete
  17. Why not using a plugin? It's an easy and fast solution that will work with both Android and iPhone toghether without having to edit native code.

    See:
    https://github.com/appfeel/admob-google-cordova

    And
    http://stackoverflow.com/a/25760180/513570

    ReplyDelete
    Replies
    1. You're right. When this post came out no plugin was available.

      Delete