bekkou68 の日記

Gogengo! や IT 技術など。

Tutorial of mopub SDK integration on iOS <Google AdMob> <Millennial Media> <iOS5 iOS6> <w/ ARC>

Introduction

I've integrated mopub SDK and wrote how to do that. There are few documents on the Internet so I made many efforts X(

日本語版のエントリはこちら

What is mopub?

mopub is a system of ad management. Once you integrate SDK, you can select ad networks, adjust a frequency of showing ads, and so on. And you can analyze many things like CPM. One of the merit of integration is absorbing a difference between ad network's SDKs. Actually, all of them are different to integrate so you must pay times to do them. But pay attention, some ad networks like Google AdMob or Millennial Media etc. want you to integrate another SDK.

Goal

The goal of the entry is that Objective-C app is in below:

  • Integrated default mopub SDK, and banner ad and interstitial ad are shown
  • Integrated Google AdMob SDK, and that of banner ad is shown
  • Integrated Millennial Media SDK, and that of interstitial ad is shown

And I prepared a project which achieved the goal. Refer it.

Precondition

I'll set the following precondition.

  • Registered banner ad and interstitial ad from administrator web site
  • Created Objective-C project as Single View Application
  • Created Controller named as TopViewController which is shown at first and we'll show a banner ad on there
  • Created Controller named as InterstitialViewController on which we'll show a interstitial ad

Policy of procedure

  • We'll create a project with Deployment Target as 5.1
  • We'll use cocoapods as we can
  • App with ARC

Preparation: Install mopub SDK

Now we'll integrate latest mopub SDK, 1.12.1.0. As I wrote, you can know how to use cocoapods in this document (Japanese only).

Write Podfile as follows.** ATTENTION ** This pod spec is in pull request now. So you can copy and paste spec to your ~/.cocoapods directory by accessing the previous URL. It was merged (edit 2013/5/25).
FYI, it seems the active spec is MoPubClient(edit 2014/1/8)。

platform :ios
pod 'MoPubSDK', '1.12.1.0'

And install.

$ pod install

mopub prepared test project for us, with it, we can see banner ad and interstitial ad respectively. The project has test unit ID. Just clone and work on XCode. We'll use it after so clone now.

$ git clone git://github.com/mopub/mopub-client.git

Open mopub-client/MoPubiOS/SimpleAdsDemo/SimpleAds.xcodeproj on XCode.

Show banner ad

According to an official document, implement TopViewController.m.

A diff of the project on GitHub is here.

diff --git a/mopub_spike/TopViewController.h b/mopub_spike/TopViewController.h
index f51d4a3..9d1b8b5 100644
--- a/mopub_spike/TopViewController.h
+++ b/mopub_spike/TopViewController.h
@@ -7,8 +7,8 @@
 //

 #import <UIKit/UIKit.h>
+#import "MPAdView.h"

-@interface TopViewController : UIViewController
+@interface TopViewController : UIViewController <MPAdViewDelegate>

 @end
-
\ No newline at end of file
diff --git a/mopub_spike/TopViewController.m b/mopub_spike/TopViewController.m
index 2d19850..554de97 100644
--- a/mopub_spike/TopViewController.m
+++ b/mopub_spike/TopViewController.m
@@ -8,8 +8,13 @@

 #import "TopViewController.h"

+// The below is test ad unit ID. Fill in by your's.
+#define BANNER_AD_UNIT_ID @"agltb3B1Yi1pbmNyDAsSBFNpdGUYkaoMDA"
+
 @interface TopViewController ()

+@property (strong, nonatomic) MPAdView *adView;
+
 @end

 @implementation TopViewController
@@ -17,7 +22,14 @@
 - (void)viewDidLoad
 {
     [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
+
+    MPAdView *adView = [[MPAdView alloc] initWithAdUnitId:BANNER_AD_UNIT_ID size:MOPUB_BANNER_SIZE];
+    adView.frame = CGRectMake(0, VIEW_HEIGHT - 50, 320, 50);
+    adView.delegate = self;
+    [adView loadAd];
+    _adView = adView;
+
+    [self.view addSubview:adView];
 }

 - (void)didReceiveMemoryWarning
@@ -26,4 +38,9 @@
     // Dispose of any resources that can be recreated.
 }

+// REQUIRED: Some of ad networks call this method.
+- (UIViewController *)viewControllerForPresentingModalView {
+    return self;
+}
+
 @end
diff --git a/mopub_spike/mopub_spike-Prefix.pch b/mopub_spike/mopub_spike-Prefix.pch
index 64731a3..0d9f26e 100644
--- a/mopub_spike/mopub_spike-Prefix.pch
+++ b/mopub_spike/mopub_spike-Prefix.pch
@@ -12,3 +12,5 @@
     #import <UIKit/UIKit.h>
     #import <Foundation/Foundation.h>
 #endif
+
+#define VIEW_HEIGHT [[UIScreen mainScreen] applicationFrame].size.height

You can confirm banner ad works by booting simulator.

f:id:bekkou68:20130523233238p:plain

If you tap ad, WebView will be shown in app.

f:id:bekkou68:20130523233233p:plain

When you show ad by WebView and use OpenURL, app boots Safari, so app will dismiss. One of the pros of using mopub SDK is no troublesome of that.

Interstitial ad

Now we'll show interstitial ad after transferred from TopViewController to InterstitialVIewController. Set a button to TopViewController. Refer commit log of the sample project.

Done? OK. Then implement interstitial ad as follows.

It's quote of this commit.

diff --git a/mopub_spike/InterstitialViewController.h b/mopub_spike/InterstitialViewController.h
index 9eec816..83ef891 100644
--- a/mopub_spike/InterstitialViewController.h
+++ b/mopub_spike/InterstitialViewController.h
@@ -7,7 +7,8 @@
 //

 #import <UIKit/UIKit.h>
+#import "MPInterstitialAdController.h"

-@interface InterstitialViewController : UIViewController
+@interface InterstitialViewController : UIViewController <MPInterstitialAdControllerDelegate>

 @end
diff --git a/mopub_spike/InterstitialViewController.m b/mopub_spike/InterstitialViewController.m
index 7f62ebd..44e457b 100644
--- a/mopub_spike/InterstitialViewController.m
+++ b/mopub_spike/InterstitialViewController.m
@@ -8,8 +8,13 @@

 #import "InterstitialViewController.h"

+// The below is test ad unit ID. Fill in by your's.
+#define INTERSTITIAL_AD_UNIT_ID @"agltb3B1Yi1pbmNyDAsSBFNpdGUYsckMDA"
+
 @interface InterstitialViewController ()

+@property (nonatomic, retain) MPInterstitialAdController *interstitialAdController;
+
 @end


 @implementation InterstitialViewController
@@ -27,6 +32,10 @@
 {
     [super viewDidLoad];
     // Do any additional setup after loading the view from its nib.
+
+    _interstitialAdController = [MPInterstitialAdController interstitialAdControllerForAdUnitId:INTERSTITIAL_AD_UNIT_ID];
+    _interstitialAdController.delegate = self;
+    [_interstitialAdController loadAd];
 }

 - (void)didReceiveMemoryWarning
@@ -35,4 +44,24 @@
     // Dispose of any resources that can be recreated.
 }

+- (void)interstitialDidLoadAd:(MPInterstitialAdController *)interstitial {
+    NSLog(@"Interstitial Ad was loaded.");
+
+    [_interstitialAdController showFromViewController:self];
+
+    // If you'd like to pause app, then code in here.
+}
+
+- (void)interstitialDidDisappear:(MPInterstitialAdController *)interstitial {
+    NSLog(@"Interstitial Ad was disappeared.");
+
+    // If you'd like to resume app, code in here.
+}
+
+// ** CAUTION: MUST IMPLEMENT **
+// If you don't implement this method, your app will be crushed when loading ad failed..
+- (void)interstitialDidFailToLoadAd:(MPInterstitialAdController *)interstitial {
+    NSLog(@"** FAIL TO LOAD: Interstitial ad **");
+}
+
 @end

Pay attention. I'd like to notice to you. YOU MUST IMPLEMENT interstitialDidFailToLoadAd method. This is callback called when loading a interstitial ad is fail. Sometimes fail even if you set a correct ad unit ID. Maybe when ad is not selected correctly by mopub system.
Unless you define the callback, APP WILL GO DOWN when loading ad is fail. FYI, app didn't go down when loading BANNER ad is fail. When fail, interstitial ad will not be shown.

Let's confirm whether work or not on simulator.

f:id:bekkou68:20130523233234p:plain

It seems OK!

Say, we've done of integration of default banner ad and interstitial ad. From now, plus alpha, we'll show banner ad of Google AdMob and interstitial ad of Millennial Media.

Show banner ad of Google AdMob

First is Google AdMob. For easy to confirm, it's good practice to set ad to show only Google AdMob by Edit Network Settings button of administration site.

If you find a display as below, preparation is done.

====================================== CAMPAIGN FILTER RESULTS ======================================
  No adgroups for level 0.
  No adgroups for level 1.
  ... (snip) ...
  No adgroups for level 8.
  No adgroups for level 9.
  No adgroups for level 10.
  Filtered adgroups are: AdMob key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  Mpx creatives: [], filtered creatives: [Creative(name: admob native dummy, source: network, width: 320, height: 50)]
  Calculating eCPMs for adunit creatives:
  admob native dummy: 0.05
  ##############################
  ##############################
  Winner found, rendering: admob native dummy

If you work app on simulator without integrating SDK, you will see the following error log.

...
2013-05-23 20:07:15.176 mopub_spike[17486:12b03] MOPUB: Could not find custom event class named MPGoogleAdMobBannerCustomEvent
2013-05-23 20:07:15.322 mopub_spike[17486:12b03] MOPUB: Banner view (xxxxxxxxxxxxxxxxxxxxxx) failed. Error: Error Domain=com.mopub.iossdk Code=0 "The operation couldn’t be completed. (com.mopub.iossdk error 0.)"

We'll make it work. The official document is here. We'll take some required classes from the project.

Add below to your project on XCode.

  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobBannerCustomEvent.h
  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobBannerCustomEvent.m
  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.h
  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m

f:id:bekkou68:20130523233237p:plain

And, add -fno-objc-arc option to following classes (Choose project > TARGETS > Build Phases > Compile Sources). I got stuck when I added break after line... that's not work. not to add break.

  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobBannerCustomEvent.m
  • AdNetworkSupport/GoogleAdMob/MPGoogleAdMobInterstitialCustomEvent.m

Add the line to Podfile.

+ pod 'AdMob', '6.4.1'

Install.

$ pod install

You will see Google AdMob works, yay!

f:id:bekkou68:20130523233236p:plain

Show interstitial ad of Millennial Media

Finally, let's show an interstitial ad of Millennial Media. Similar to Google AdMob, select only Millennial Media's ad by administrator site.

Add classes.

  • AdNetworkSupport/Millennial/MPMillennialBannerCustomEvent.h
  • AdNetworkSupport/Millennial/MPMillennialBannerCustomEvent.m
  • AdNetworkSupport/Millennial/MPMillennialInterstitialCustomEvent.h
  • AdNetworkSupport/Millennial/MPMillennialInterstitialCustomEvent.m

Add -fno-objc-arc option.

  • MPMillennialBannerCustomEvent.m
  • MPMillennialInterstitialCustomEvent.m

Download SDK from a site of Millennial Media. You need to create an account to download it. No pod spec of Millennial Media SDK may be caused by the background.

Add MMSDK/ directory of downloaded SDK to XCode.

f:id:bekkou68:20130523233235p:plain

Because Millenium Media has a rich ad such as playing music and movie, so you have to add some frameworks. Add frameworks according to a guideline. In this time, you need to add CoreLocation.framework. I wonder Millennial Media use location information to show ad. After integrating the framework, app will ask to user whether app can access to current location or not.

To get a current location, edit your code as follows:

AppDelegate.h

+ #import "MMSDK.h"
+ #import <CoreLocation/CoreLocation.h>

+ @property (strong, nonatomic) CLLocationManager *locationManager;

AppDelegate.m

  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
+     [MMSDK initialize]; //Initialize a Millennial Media session
 
+     //Create a location manager for passing location data for conversion tracking and ad requests
+     self.locationManager = [[CLLocationManager alloc] init];
+     [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
+     [self.locationManager startUpdatingLocation];
 
      return YES;
  } 

Now simulate it. Umm, it looks fail.

2013-05-23 21:39:44.875 mopub_spike[20330:1a303] MOPUB: Ad view is fetching ad network type: clear
2013-05-23 21:39:44.875 mopub_spike[20330:1a303] MOPUB: Ad server response indicated no ad available.
2013-05-23 21:39:44.876 mopub_spike[20330:1a303] ** FAIL TO LOAD: Interstitial ad **

It seems that app will not show ad immediately after registration. Several days later, I got an email like below.

Your Application, Xxx, has been approved! Your application will now serve live campaigns.
Log in to mMedia to view your reports and manage your apps. If you have any questions,
please visit the Resource Center or contact us.

It sounds that we can have an approve after integration SDK. After getting the mail, interstitial ad was shown correctly. If you make a request from here, perhaps, the approve may be faster.

Last of last, set Deployment Target as 5.1 (select project from TARGETS > Summary > Deployment Target), then confirm by simulators of 5.1 and 6.1.

That's all!

At the end

Have a great life of mopub! Cheers!