Update 10/11/09: Fixed code display. Update 01/05/2010: Download a MonoDevelop project sample at http://www.sabonrai.com/downloads/MT_SampleAdMob.zip. This includes fixes for the problems pointed out in the comments by Rory.
It’s not complete yet, but the basics work, so here’s my effort at building a MonoTouch binding for AdMob. This is my first attempt at making a MonoTouch binding to an Objective-C type, so please make suggestions.
Follow these MonoTouch-specific instructions adapted from AdMob’s wiki page. The paragraph numbers correspond to their instructions.
(1) Copy the 3.0 libraries (.a files) found in the AdMob SDK extras directory into your MonoTouch project.
(2) Add these to your additional mtouch arguments:
-gcc_flags “-framework QuartzCore -Lpath-to-the-admob-library -lAdMobSimulator3_0 -ObjC”
(3) “Get a publisher id from www.admob.com.”
(4) “Integrate AdMob ads with your app.” I chose this technique:
(b) “Add an ad to a view programmatically.”
[sourcecode language=”csharp”] // Create and customize the delegate AdMobDelegate adMobDelegate = new AdMobDelegate(); adMobDelegate.PublisherId = new NSString(myPublisherID); adMobDelegate.AdReceived += delegate (AdMobView adView) { this.View.AddSubview(advertView); Thread thread = new Thread(new ThreadStart(RequestFreshAd)); thread.Start(); }; // Example of changing the background color adMobDelegate.AdBackgroundColor = new UIColor(0, 0, 0, 1);
// Create the AdMobView referencing the delegate you just created AdMobView advertView = AdMobView.RequestAdWithDelegate(adMobDelegate);
// In this example, the AdMobView is placed just above a UIToolBar float advertHeight = 48; advertView.Frame = new RectangleF ( 0, this.View.Frame.Height - advertHeight - toolbar.Frame.Height, this.View.Frame.Width, advertHeight); [/sourcecode]
Departing from AdMob’s instructions (numbers don’t correspond):
(5) Sample code for requesting a fresh ad:
[sourcecode language=”csharp”] private void RequestFreshAd() { while (true) { Thread.Sleep(60000); // Request fresh ad once per minute this.InvokeOnMainThread(advertView.RequestFreshAd); } } [/sourcecode]
(6) The AdMobView class works except for the Version property. I don’t know why it’s sending the message to the AdMobViewInternal class and so getting an unrecognized selector.
[sourcecode language=”csharp”] using System; using System.Drawing;
using MonoTouch.Foundation; using MonoTouch.ObjCRuntime; using MonoTouch.UIKit;
namespace AdMob { [Register (“AdMobView”)] public class AdMobView : UIView { static Selector selInit = new Selector(“init”); static Selector selRequestAdWithDelegate = new Selector(“requestAdWithDelegate:”); static Selector selRequestFreshAd = new Selector(“requestFreshAd”); static Selector selVersion = new Selector(“version”);
- [Export (“init”)]
- public AdMobView()
- base(NSObjectFlag.Empty) { Handle = Messaging.IntPtr_objc_msgSend( this.Handle, selInit.Handle); }
- // This constructor must be present so that
- // MonoTouch can create instances of this type
- // from Objective-C code.
- public AdMobView (IntPtr handle)
- base(handle) { }
/** * Initiates an ad request and returns a view that will * contain the results; the delegate is alerted when the * ad is ready to display (or has failed to load); this is * a good opportunity to attach the view to your * hierarchy. If you already have a AdMobView with an * ad loaded, and simply want to show a new ad in the * same location, you may use -requestFreshAd instead * (see below). * * This method should only be called from a run loop in * default run loop mode. If you don’t know what that * means, you’re probably ok. If in doubt, check whether * ([[NSRunLoop currentRunLoop] currentMode] == * NSDefaultRunLoopMode). */ public static AdMobView RequestAdWithDelegate( AdMobDelegate Delegate) { // Get class type Class adMobViewClass = new Class(“AdMobView”);
return (AdMobView) Runtime.GetNSObject( Messaging.IntPtr_objc_msgSend_IntPtr( adMobViewClass.Handle, selRequestAdWithDelegate.Handle, Delegate.Handle)); }
/** * Causes an existing AdMobView to display a fresh ad. * If an ad successfully loads, it is animated in with a * flip; if not, this call fails silently and the old ad * remains onscreen. * * Note that, during the flip, views under the AdMobView * will be exposed. * * To preserve the user experience, we recommend loading * fresh ads no more frequently than once per minute. */ public virtual void RequestFreshAd() { Messaging.void_objc_msgSend( this.Handle, selRequestFreshAd.Handle); }
/** * Returns the version of the current SDK. */ public virtual string Version { get { return ((NSString) Runtime.GetNSObject( Messaging.IntPtr_objc_msgSend( this.Handle, selVersion.Handle))).ToString(); } } } } [/sourcecode]
(7) This AdMobDelegate class is unfinished:
[sourcecode language=”csharp”] using System; using System.Drawing;
using MonoTouch.Foundation; using MonoTouch.ObjCRuntime; using MonoTouch.UIKit;
namespace AdMob { [Register(“AdMobDelegate”)] public class AdMobDelegate : NSObject { public delegate void AdReceivedDelegate (AdMobView adView); public event AdReceivedDelegate AdReceived;
public delegate void AdReceiveFailedDelegate (AdMobView adView); public event AdReceivedDelegate AdReceiveFailed;
private static Selector selInit = new Selector(“init”);
- [Export (“init”)]
- public AdMobDelegate()
- base(NSObjectFlag.Empty) { Handle = Messaging.IntPtr_objc_msgSend(this.Handle, selInit.Handle); }
- // This constructor must be present so that MonoTouch
- // can create instances of this type from Objective-C code.
- public AdMobDelegate (IntPtr handle)
- base(handle) { }
// Use this to provide a publisher id for an ad request. Get a publisher id // from http://www.admob.com private NSString myPublisherID; public virtual NSString PublisherId { [Export (“publisherId”)] get { return myPublisherID; } set { myPublisherID = value; } }
// Sent when an ad request loaded an ad; this is a good opportunity to add // this view to the hierachy, if it has not yet been added. // Note that this will only ever be sent once per AdMobView, regardless of whether // new ads are subsequently requested in the same AdMobView. [Export (“didReceiveAd:”)] public virtual void DidReceiveAd (AdMobView adView) { if (AdReceived != null) AdReceived (adView); }
// Sent when an ad request failed to load an ad. // Note that this will only ever be sent once per AdMobView, regardless of whether // new ads are subsequently requested in the same AdMobView. [Export (“didFailToReceiveAd:”)] public virtual void DidFailToReceiveAd (AdMobView adView) { if (AdReceiveFailed != null) AdReceiveFailed (adView); }
// Specifies the ad background color, for tile+text ads. // Defaults to [UIColor colorWithRed:0.443 green:0.514 blue:0.631 alpha:1], which is a chrome-y color. // Note that the alpha channel in the provided color will be ignored and treated as 1. // We recommend against using a white or very light color as the background color, but // if you do, be sure to implement adTextColor and useGraySpinner. // Grayscale colors won’t function correctly here. Use e.g. [UIColor colorWithRed:0 green:0 blue:0 alpha:1] // instead of [UIColor colorWithWhite:0 alpha:1] or [UIColor blackColor]. private UIColor adBackgroundColor; public virtual UIColor AdBackgroundColor { [Export (“adBackgroundColor”)] get { return adBackgroundColor; } set { adBackgroundColor = value; } }
// Specifies the primary text color for ads. // Defaults to [UIColor whiteColor]. private UIColor primaryTextColor; public virtual UIColor PrimaryTextColor { [Export (“primaryTextColor”)] get { return primaryTextColor; } set { primaryTextColor = value; } }
// Specifies the secondary text color for ads. // Defaults to [UIColor whiteColor]. private UIColor secondaryTextColor; public virtual UIColor SecondaryTextColor { [Export (“secondaryTextColor”)] get { return secondaryTextColor; } set { secondaryTextColor = value; } }
// When a spinner is shown over the adBackgroundColor (e.g. on clicks), it is by default // a white spinner. If this returns YES, a gray spinner will be used instead, // which looks better when the adBackgroundColor is white or very light in color. /* - (BOOL)useGraySpinner;
// Whether AdMob may use location information. Defaults to NO. // We ask that you respect your users’ privacy and only enable location requests // if your app already uses location information. // Note that even if this is set to no, you will still need to include the CoreLocation // framework to compile your app; it will simply not get used. (It is a dynamic // framework, so including it will not increase the size of your app.)
- (BOOL)mayAskForLocation;
// If you have location information available for the user at the time that you // make the ad request, you may provide it here (and it is recommended that you do // so, to improve user experience and preserve battery life). If this method is implemented, // AdMob will not request location information from the OS, even if the method returns // nil (which it should if the user’s location is not known); if this method is not // implemented, then AdMob will request location information directly from the OS. // // If mayAskForLocation (above) is not implemented, or returns NO, this will not be called // and may be completely ignored.
- (CLLocation *)location;
// If implemented, lets you specify whether to issue a real ad request or a test // ad request (to be used for development only, of course). Defaults to NO.
- (BOOL)useTestAd;
// If implemented, lets you specify the action type of the test ad. Defaults to @”url” (web page). // Does nothing if useTestAd is not implemented or returns NO. // Acceptable values are @”url”, @”app”, @”video”, @”itunes”, @”call”, @”canvas”. // Normally, the adservers restricts ads appropriately (e.g. no click to call ads for iPod touches). // However, for your testing convenience, they will return any type requested for test ads.
- (NSString *)testAdAction;
// The following functions, if implemented, provide extra information // for the ad request. If you happen to have this information, providing it will // help select better targeted ads and will improve monetization. // // Keywords and search terms should be provided as a space separated string // like “iPhone monetization San Mateo”. We strongly recommend that // you NOT hard code keywords or search terms. // // Keywords are used to select better ads; search terms _restrict_ the available // set of ads. Note, then, that providing a search string may seriously negatively // impact your fill rate; we recommend using it only when the user is submitting a // free-text search request and you want to _only_ display ads relevant to that search. // In those situations, however, providing a search string can yield a significant // monetization boost. // // For all of these methods, if the information is not available at the time of // the call, you should return nil.
- (NSString *)postalCode; // user’s postal code, e.g. “94401”
- (NSString *)areaCode; // user’s area code, e.g. “415”
- (NSDate *)dateOfBirth; // user’s date of birth
- (NSString *)gender; // user’s gender (e.g. @”m” or @”f”)
- (NSString *)keywords; // keywords the user has provided or that are contextually relevant, e.g. @”twitter client iPhone”
- (NSString *)searchString; // a search string the user has provided, e.g. @”Jasmine Tea House San Francisco”
// You can control the appearance of the AdMob mini-browser and the nav bars // to fit with the rest of your app. See the documentation for UIToolbar // and UINavigationBar for details. Defaults to standard iPhone chrome.
- (UIBarStyle)embeddedWebViewBarStyle;
- (UIColor *)embeddedWebViewTintColor;
// Sent just before presenting the user a full screen view, such as a canvas page or an embedded webview, // in response to clicking on an ad. Use this opportunity to stop animations, time sensitive interactions, etc.
- (void)willPresentFullScreenModal;
// Sent just after dismissing a full screen view. Use this opportunity to // restart anything you may have stopped as part of -willPresentFullScreenModal:.
- (void)didDismissFullScreenModal; */ } } [/sourcecode]