Nobollel開発者ブログ

Nobollelのエンジニアが、UnityやCocos2d-xの旬な情報・技術を紹介します。

Admobでバナーの位置を微調整する

皆さんこんにちは、エンジニアの石橋です。
今回はみんなが大好きな広告、GoogleのAdmobを取り上げたいと思います。
有名なN社さんやI社さんなどでは標準で付いているのですが、Google Admobではバナーのセンタリングとオフセットをサポートしていません。
レクタングルバナーを表示する際に困る場合があります。
幸いなことにAdmobはソースが公開されているのでカスタマイズすれば独自に表示することが出来る様になります。

この記事はバージョンは3.0.4を元にしています。
プラグインのダウンロードはこちら
GitHub - googleads/googleads-mobile-unity: Official Unity Plugin for the Google Mobile Ads SDK

編集が必要な箇所は以下のファイルになります。

  • GoogleMobileAds/Api/AdPosition.cs
  • GoogleMobileAds/Common/IBannerClient.cs
  • GoogleMobileAds/Platforms/iOS/BannerClient.cs
  • GoogleMobileAds/Common/DummyClient.cs
  • GoogleMobileAds/Api/BannerView.cs
  • GoogleMobileAds/Platforms/iOS/Externs.cs
  • Plugins/iOS/GADUBanner.h
  • Plugins/iOS/GADUInterface.h
  • Plugins/iOS/GADUBanner.m
  • Plugins/iOS/GADUInterface.m

結構な数がありますね、順を追って見ていきましょう。

GoogleMobileAds/Api/AdPosition.cs

//enum値のAdPositionにCenterがないので追加します
Center = 6 //custom

GoogleMobileAds/Common/IBannerClient.cs

//CreateBannerViewにオフセット値の引数を追加します
void CreateBannerView(string adUnitId, AdSize adSize, AdPosition position, float offsetX, float offsetY);

GoogleMobileAds/Platforms/iOS/BannerClient.cs

//IBannerClientを継承しているBannerClient.csでCreateBannerViewにオフセット値の引数を追加します
public void CreateBannerView(string adUnitId, AdSize adSize, AdPosition position, float offsetX, float offsetY) {
    IntPtr bannerClientPtr = (IntPtr) GCHandle.Alloc(this);

    if (adSize.IsSmartBanner) {
        //objective-cのメソッドへオフセットを渡します
        BannerViewPtr = Externs.GADUCreateSmartBannerView(
                    bannerClientPtr, adUnitId, (int)position, offsetX, offsetY );
            }
            else
            {
                //objective-cのメソッドへオフセットを渡します
                BannerViewPtr = Externs.GADUCreateBannerView(
                    bannerClientPtr, adUnitId, adSize.Width, adSize.Height, (int)position, offsetX, offsetY );
            }
            Externs.GADUSetBannerCallbacks(
                    BannerViewPtr,
                    AdViewDidReceiveAdCallback,
                    AdViewDidFailToReceiveAdWithErrorCallback,
                    AdViewWillPresentScreenCallback,
                    AdViewDidDismissScreenCallback,
                    AdViewWillLeaveApplicationCallback);
        }

GoogleMobileAds/Common/DummyClient.cs

//Dummyにも同じくオフセット値の引数を追加します
public void CreateBannerView(string adUnitId, AdSize adSize, AdPosition position, float offsetX, float offsetY)

GoogleMobileAds/Api/BannerView.cs

        //こちらもオフセット値の引数を追加します。
        public BannerView(string adUnitId, AdSize adSize, AdPosition position, float offsetX, float offsetY)
        {
            client = GoogleMobileAdsClientFactory.BuildBannerClient();
            //clientはIBannerClientなので上記でオフセット引数を追加済みなので渡してやります
            client.CreateBannerView(adUnitId, adSize, position, offsetX, offsetY);

GoogleMobileAds/Platforms/iOS/Externs.cs C#からObjective-cへの橋渡しの部分です。

        //オフセット値の引数を追加します。
        [DllImport("__Internal")]
        internal static extern IntPtr GADUCreateBannerView(
            IntPtr bannerClient, string adUnitId, int width, int height, int positionAtTop, float offsetX, float offsetY );

        //オフセット値の引数を追加します。
        [DllImport("__Internal")]
        internal static extern IntPtr GADUCreateSmartBannerView(
            IntPtr bannerClient, string adUnitId, int positionAtTop, float offsetX, float offsetY );

長かったC#のコード編集の次はObjective-c側です。

Plugins/iOS/GADUBanner.h

//AdPosition.csで追加したCenterを追加します
typedef NS_ENUM(NSUInteger, GADAdPosition) {
  
  ...
  
  kGADAdPositionCenter = 6
};

Plugins/iOS/GADUBanner.h

//以下の2つのメソッド定義にオフセット値の引数を追加します。
- (id)initWithBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                           adUnitID:(NSString *)adUnitID
                              width:(CGFloat)width
                             height:(CGFloat)height
                         adPosition:(GADAdPosition)adPosition
                            offsetX:(CGFloat)offsetX
                            offsetY:(CGFloat)offsetY;

- (id)initWithSmartBannerSizeAndBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                                             adUnitID:(NSString *)adUnitID
                                           adPosition:(GADAdPosition)adPosition
                                              offsetX:(CGFloat)offsetX
                                              offsetY:(CGFloat)offsetY;

Plugins/iOS/GADUBanner.m

//adViewDidReceiveAdで使うために一時的に保存するプロパティを追加します
@property(nonatomic, assign) CGFloat offsetX;
@property(nonatomic, assign) CGFloat offsetY;
//オフセットの受け取りとinitWithBannerClientReferenceへの受け渡しを追加します。
- (id)initWithBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                           adUnitID:(NSString *)adUnitID
                              width:(CGFloat)width
                             height:(CGFloat)height
                         adPosition:(GADAdPosition)adPosition
                            offsetX:(CGFloat)offsetX
                            offsetY:(CGFloat)offsetY
{
  GADAdSize adSize = GADAdSizeFromCGSize(CGSizeMake(width, height));
  return [self initWithBannerClientReference:bannerClient
                                    adUnitID:adUnitID
                                      adSize:adSize
                                  adPosition:adPosition
                                     offsetX:offsetX
                                     offsetY:offsetY];
}

//SmartBanner側も同じく処理します
- (id)initWithSmartBannerSizeAndBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                                             adUnitID:(NSString *)adUnitID
                                           adPosition:(GADAdPosition)adPosition
                                              offsetX:(CGFloat)offsetX
                                              offsetY:(CGFloat)offsetY
{
  // Choose the correct Smart Banner constant according to orientation.
  UIDeviceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;
  GADAdSize adSize;
  if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
    adSize = kGADAdSizeSmartBannerPortrait;
  } else {
    adSize = kGADAdSizeSmartBannerLandscape;
  }
  return [self initWithBannerClientReference:bannerClient
                                    adUnitID:adUnitID
                                      adSize:adSize
                                  adPosition:adPosition
                                     offsetX:offsetX
                                     offsetY:offsetY];
}
//オフセットを受け取ります
- (id)initWithBannerClientReference:(GADUTypeBannerClientRef *)bannerClient
                           adUnitID:(NSString *)adUnitID
                             adSize:(GADAdSize)size
                         adPosition:(GADAdPosition)adPosition
                            offsetX:(CGFloat)offsetX
                            offsetY:(CGFloat)offsetY
{
  self = [super init];
  if (self) {
    _bannerClient = bannerClient;
    _adPosition = adPosition;
    //受け取ったオフセットをプロパティに設定します
    _offsetX = offsetX;
    _offsetY = offsetY;
    _bannerView = [[GADBannerView alloc] initWithAdSize:size];
    _bannerView.adUnitID = adUnitID;
    _bannerView.delegate = self;
    _bannerView.rootViewController = [GADUBanner unityGLViewController];
  }
  return self;
}
- (void)adViewDidReceiveAd:(GADBannerView *)adView {
  ...

  switch (self.adPosition) {

    ...


    //Centerのenum値の処理を追加します。
    case kGADAdPositionCenter:
      center = CGPointMake(CGRectGetMidX(unityView.bounds), CGRectGetMidY(unityView.bounds));
      break;
  }
  //プロパティにセットされたオフセットをcenterに追加して位置をずらします。
  center = CGPointMake( center.x + _offsetX, center.y + _offsetY );

  ...
}

Plugins/iOS/GADUInterface.m

//CGFloatを使うのでUIKitをimport
+@import UIKit;
//オフセットの受け取りとGADUBannerへの受け渡しを追加します。
GADUTypeBannerRef GADUCreateBannerView(GADUTypeBannerClientRef *bannerClient, const char *adUnitID,
                                       NSInteger width, NSInteger height,
                                       GADAdPosition adPosition, float offsetX, float offsetY ) {
  GADUBanner *banner =
      [[GADUBanner alloc] initWithBannerClientReference:bannerClient
                                               adUnitID:GADUStringFromUTF8String(adUnitID)
                                                  width:width
                                                 height:height
                                             adPosition:adPosition
                                                offsetX:offsetX
                                                offsetY:offsetY];
  GADUObjectCache *cache = [GADUObjectCache sharedInstance];
  [cache.references setObject:banner forKey:[banner gadu_referenceKey]];
  return (__bridge GADUTypeBannerRef)banner;
}

/// Creates a full-width GADBannerView in the current orientation. Returns a reference to the
/// GADUBannerView.
GADUTypeBannerRef GADUCreateSmartBannerView(GADUTypeBannerClientRef *bannerClient,
                                            const char *adUnitID, GADAdPosition adPosition, float offsetX, float offsetY ) {
  GADUBanner *banner = [[GADUBanner alloc]
      initWithSmartBannerSizeAndBannerClientReference:bannerClient
                                             adUnitID:GADUStringFromUTF8String(adUnitID)
                                           adPosition:adPosition
                                              offsetX:offsetX
                                              offsetY:offsetY];
  GADUObjectCache *cache = [GADUObjectCache sharedInstance];
  [cache.references setObject:banner forKey:[banner gadu_referenceKey]];
  return (__bridge GADUTypeBannerRef)banner;
}

以上です。

手順としては

  1. Unity側でenum、オフセットを追加
  2. C#側で値を受け取り位置を計算

と、するだけです。 Androidは次回。