《插件自助开发——广告类插件》

广告系统

广告系统包含广告显示隐藏等相关的接口,需要实现框架接口InterfaceAds,并通过框架的AdsWrapper类实现回调等。

类名及协议

推送系统的类一般命名为"Ads+插件名",并且遵循框架的InterfaceAds及SDK相关协议。
以admob为例,需要遵循框架的InterfaceAds协议及admob的两个协议。

@interface AdsAdmob : NSObject <InterfaceAds,GADBannerViewDelegate,GADInterstitialDelegate>

初始化方法

- (void)configDeveloperInfo:(NSMutableDictionary *)cpInfo; 初始化方法主要作用是初始化一些成员变量、配置调试模式、配置参数等工作。
具体步奏为首先重写init方法,然后在init方法里调用插件初始化的configDeveloperInfo:方法。在configDeveloperInfo:方法里,完成初始化的相关操作。
configDeveloperInfo:的参数从PluginHelper类的getParamsInfo方法获取

- (id)init {
    if ([super init]) {
         [self configDeveloperInfo:[PluginHelper getParamsInfo]];
    }
    return self;
    }

 - (void)configDeveloperInfo:(NSMutableDictionary *)cpInfo {
     OUTPUT_LOG(@"config params:%@",cpInfo);
     self.bDebug = [PluginHelper getDebugModeStatus];

     _currentBannerDic = [NSMutableDictionary dictionary];
     _currentFullScreenDic = [NSMutableDictionary dictionary];

     // modify _supportAdsType according to SDK
     _supportAdsType = [[NSArray alloc] initWithObjects:@"AD_TYPE_BANNER", @"AD_TYPE_FULLSCREEN", @"AD_TYPE_MOREAPP",@"AD_TYPE_OFFERWALL",nil];

     // init SDK
     _adRequestAgent = [cpInfo objectForKey:@"ABBannerRequestAgent"];
  }

相关接口

在InterfaceAds协议中,有以下接口必须实现:

显示广告

- (void)showAds:(NSMutableDictionary *)info;
showAds:方法的info参数是以字典的形式传递
参数一对应的key为@"Param1",value为广告的类型,和枚举ADS_TYPE对应。

typedef enum
{
    AD_TYPE_BANNER = 0,/**< enum value is banner ads . */
    AD_TYPE_FULLSCREEN,/**< enum value is fullscreen ads . */
    AD_TYPE_MOREAPP,/**< enum value is moreapp ads . */
    AD_TYPE_OFFERWALL /**< enum value is offerwall ads . */

 } ADS_TYPE;

参数二对应的key为@"Param2",value为参数序列,和打包工具配置填写的参数序列对应。
显示广告需要做这么三步:
1. 从showAds:接口传递的info参数里获取相应的参数。
2. 调用SDK的相关方法生成广告的视图。
3. 最后调用AdsWrapper类的addAdview:atPos方法,把view添加到视图。参阅添加广告视图小节。 显示广告需要回调的结果可能有:
1. 接受到广告
2. 广告显示
3. 网络错误
4. 未知错误
以下以admob为例,在showAds:方法里调用了admob的SDK显示广告。注意这里的info参数是框架传递下来的,而getAdsParam:idx:方法获取到的参数是打包工具里配置的。

- (void)showAds:(NSMutableDictionary *)info {
    OUTPUT_LOG(@"showAds:%@ invoked.\n",info);
    @try {
        int adsType = [[info objectForKey:@"Param1"] intValue] ;// 广告类型
        int idx = [[info objectForKey:@"Param2"] intValue];// 参数序列
        //call sdk method
        switch (adsType) {
            case AD_TYPE_BANNER: {
               NSDictionary *dic = [self getAdsParam:@"Banner" idx:idx];
               if (![dic objectForKey:@"ABBannerUnitId"]) {
                   OUTPUT_LOG(@"unitID is null, please check it!");
                   return;
                }
               GADBannerView *adview = [[GADBannerView alloc] initWithAdSize:[dic objectForKey:@"ABBannerSize"] ? [self getSize:[dic objectForKey:@"ABBannerSize"]]:kGADAdSizeBanner];
               adview.adUnitID = [dic objectForKey:@"ABBannerUnitId"];
               adview.delegate = self;
               [adview setRootViewController:[AdsWrapper  getCurrentRootViewController]];
               [adview setTag:[self getPos:[dic objectForKey:@"ABBannerPos"]]];
               [adview loadRequest:[self getGADRequest]];

               [AdsWrapper addAdView:adview atPos:[self getPos:[dic  objectForKey:@"ABBannerPos"]]];
               [_currentBannerDic setObject:adview forKey:[[NSNumber alloc] initWithInt:idx]];
        }

            break;
        case AD_TYPE_FULLSCREEN: {
            GADInterstitial *interstitialAd = [_currentFullScreenDic objectForKey:[NSNumber numberWithInt:idx]];
            if (interstitialAd) {
                if ([interstitialAd isReady]) {
                    OUTPUT_LOG(@"GADInterstitial is ready!");
                    id rootVC = [AdsWrapper getCurrentRootViewController];
                    if (!rootVC) {
                        OUTPUT_LOG(@"Can't find correct UIViewController, please check it!");
                        return;
                    }
                    [interstitialAd presentFromRootViewController:rootVC];
                    return;
                }
            }
            OUTPUT_LOG( @"GADInterstitial is null, Creating new GADInterstitial!");
            [self newAndLoadFullScreenAd:@"FullScreen" idx:idx operation:OPER_FULLSCREEN_SHOW];

        }
            break;
        default:
            break;
    }
  }
  @catch (NSException *exception) {
    NSLog(@"NSException %@\n",exception);
  }
}

- (NSDictionary *)getAdsParam:(NSString *)name idx:(int)idx {
@try {
    NSDictionary *jsonObject = [AdsUtil getAdsParams];
    NSArray *item = [jsonObject objectForKey:name];
    return [item objectAtIndex:idx < 1 ? 0 : idx - 1];
  }
  @catch (NSException *exception) {
      NSLog(@"%@",exception);
  }
}

- (int)getPos:(NSString *)posName{
   int pos = POS_CENTER;
   if (!posName) {
      return pos;
   }
   if ([posName isEqualToString:@"center"]) {
      pos = POS_CENTER;
   } else if ([posName isEqualToString:@"top-middle"]) {
      pos = POS_TOP;
   } else if ([posName isEqualToString:@"top-left"]) {
      pos = POS_TOP_LEFT;
   } else if ([posName isEqualToString:@"top-right"]) {
      pos = POS_TOP_RIGHT;
   } else if ([posName isEqualToString:@"bottom-middle"]) {
      pos = POS_BOTTOM;
   } else if ([posName isEqualToString:@"bottom-left"]) {
      pos = POS_BOTTOM_LEFT;
   } else if ([posName isEqualToString:@"bottom-right"]) {
      pos = POS_BOTTOM_RIGHT;
   }
 return pos;
}

隐藏广告

- (void)hideAds:(NSMutableDictionary *)info;
hideAds:方法的info参数是以字典的形式传递
参数一对应的key为@"Param1",value为广告的类型,和枚举ADS_TYPE对应。

typedef enum
{
    AD_TYPE_BANNER = 0,/**< enum value is banner ads . */
    AD_TYPE_FULLSCREEN,/**< enum value is fullscreen ads . */
    AD_TYPE_MOREAPP,/**< enum value is moreapp ads . */
    AD_TYPE_OFFERWALL /**< enum value is offerwall ads . */

} ADS_TYPE;

参数二对应的key为@"Param2",value为参数序列,和打包工具配置填写的参数序列对应。
在hideAds:方法里,调用SDK的隐藏视图方法,或者是直接把广告视图从父视图上移除/隐藏掉。
隐藏广告需要回调的结果有:
1. 广告隐藏
以admob为例,先获取到广告视图,然后直接从父视图上移除掉。

- (void)hideAds:(NSMutableDictionary *)info {
  OUTPUT_LOG(@"hideAds:%@ invoked.\n",info);
  @try {
    int adsType = [[info objectForKey:@"Param1"] intValue] ;// 广告类型
    int idx = [[info objectForKey:@"Param2"] intValue];// 参数序列
    //call sdk method
    switch (adsType) {
        case AD_TYPE_BANNER: {
            GADBannerView *bannerView = [_currentBannerDic objectForKey:[NSNumber numberWithInt:idx]];
            if (bannerView) {
                [bannerView removeFromSuperview];
                [_currentBannerDic removeObjectForKey:[[NSNumber alloc] initWithInt:idx]];
            }
        }
            break;
        case AD_TYPE_FULLSCREEN: {
            GADInterstitial *interstitialAd = [_currentFullScreenDic objectForKey:[NSNumber numberWithInt:idx]];
            if (interstitialAd) {
                [_currentFullScreenDic removeObjectForKey:[NSNumber numberWithInt:idx]];
            }
        }
            break;
        default:
            OUTPUT_LOG(@"AdMob does not support ads type <AD_TYPE_MOREAPP>, <AD_TYPE_OFFERWALL>.");
            break;
    }


  }
  @catch (NSException *exception) {
     NSLog(@"NSException %@\n",exception);
  } 
}

预加载广告

- (void)preloadAds:(NSMutableDictionary *)info;
在preloadAds:方法里,调用SDK的预加载方法,在显示广告之前把需要的数据缓存下来。
预加载广告需要回调的结果可能有:
1. 接受到广告
2. 网络错误
3. 未知错误
以admob为例,在preloadAds:方法里调用SDK的预加载广告方法。

- (void)preloadAds:(NSMutableDictionary *)info {
    OUTPUT_LOG(@"preloadAds:%@ invoked.\n",info);
    @try {
        int adsType = [[info objectForKey:@"Param1"] intValue] ;// 广告类型
        int idx = [[info objectForKey:@"Param2"] intValue];// 参数序列
        //call sdk method
        switch (adsType) {
            case AD_TYPE_BANNER:
                OUTPUT_LOG(@"AdMob banners can not be preloaded.");
                break;
            case AD_TYPE_FULLSCREEN: {
                 GADInterstitial *interstitialAd = [_currentFullScreenDic objectForKey:[NSNumber numberWithInt:idx]];
                 if (interstitialAd) {
                    if ([interstitialAd isReady]) {
                        OUTPUT_LOG(@"this interstitial ad is already preloaded!");
                        return;
                     }
                 }
                 [self newAndLoadFullScreenAd:@"FullScreen" idx:idx operation:OPER_FULLSCREEN_PRELOAD];
            }
                 break;
            default:
                 OUTPUT_LOG(@"Now not support in Admob!");
                 break;
       }
    }
    @catch (NSException *exception) {
         NSLog(@"NSException %@\n",exception);
    }
 }

- (void)newAndLoadFullScreenAd:(NSString*)name idx:(int)idx operation:(int)oper {
    NSString *unitID = [[self getAdsParam:name idx:idx]objectForKey:@"ABFullScreenUnitId"];
    if (!unitID) {
       OUTPUT_LOG(@"unitId of fullScreen ads is null.");
       return;
    }
    GADInterstitial *fullView = [[GADInterstitial alloc] initWithAdUnitID:unitID];
    _operation = oper;
    [fullView setDelegate:self];
    [fullView loadRequest:[self getGADRequest]];

    [_currentFullScreenDic setObject:fullView forKey:[NSNumber numberWithInt:idx]];
}

积分查询

- (float)queryPoints;
如果SDK有积分查询的相关接口,需要在queryPoints方法里调用SDK的查询积分方法,并且返回单精度浮点型的积分数。
积分查询需要回调的结果可能有:
1. 积分墙积分改变

扣除积分

- (void)spendPoints:(int)points;
如果SDK有扣除积分的相关接口,需要在spendPoints:方法里调用SDK的扣除积分方法。
spendPoints:的参数为需要扣除的积分数。
显示广告需要回调的结果可能有:
1. 积分扣除成功
2. 积分扣除失败

是否支持该类型的广告

- (BOOL)isAdTypeSupported:(int)adType;
adType为广告类型,和下表对应
广告类型有以下几个类型:

广告类型 标示符
Banner AD_TYPE_BANNER
插屏广告 AD_TYPE_FULLSCREEN
精品推荐 AD_TYPE_MOREAPP
积分墙 AD_TYPE_OFFERWALL

插件需要在isAdTypeSupported:方法里判断是否支持该类型的广告。
以下以admob为例,_supportAdsType数组的初始化请参阅初始化一项。

- (BOOL)isAdTypeSupported:(int)adType {
     OUTPUT_LOG(@"isAdTypeSupported:%d invoked.\n",adType);
     NSString* nameString = [AdsWrapper getAdNameWithType:adType];
     BOOL ret;
     if (nameString) {
         NSUInteger idx = [_supportAdsType indexOfObject:nameString];
         if (idx != NSNotFound) {
            ret = YES;
         } else {
            ret = NO;
         }
     }
     return ret;
}

获取SDK版本号

- (NSString *)getSDKVersion;
SDK版本是指第三方SDK的版本号,格式可能都不一样,如6.0、1.0.3、2.1.0.4等,这个版本号格式不需要任何改动。
调用getSDKVersion方法返回字符串型的SDK版本号

获取插件版本号

- (NSString *)getPluginVersion;
格式『版本序号_SDK版本号』,版本序号从『2.0.0』开始,每次更新+0.0.1
调用getPluginVersion返回字符串型的插件版本号。

相关回调

插件调用SDK的接口,如果SDK有回调信息,需要把这些回调信息传给框架,就要用到AdsWrapper类。

结果回调

+ (void)onAdsResult:(id)target retCode:(int)code msg:(NSString*)msg;
参数说明:target为做相应处理的对象,code为操作结果代码,msg为简单描述。
SDK的回调信息,通过onAdsResult:retCode:msg:方法传递给框架,对应的参数见下表:

回调信息 code msg
接受到广告 RESULT_CODE_AdsReceived 信息的简单描述
广告显示 RESULT_CODE_AdsShown 信息的简单描述
广告隐藏 RESULT_CODE_AdsDismissed 信息的简单描述
积分扣除成功 RESULT_CODE_PointsSpendSucceed 信息的简单描述
积分扣除失败 RESULT_CODE_PointsSpendFailed 信息的简单描述
网络错误 RESULT_CODE_NetworkError 信息的简单描述
未知错误 RESULT_CODE_UnknownError 信息的简单描述
积分墙积分改变 RESULT_CODE_OfferWallOnPointsChanged 回调积分值

添加广告视图

+ (void)addAdView:(UIView *)view atPos:(AD_POS)pos;
参数说明:view为需要显示的广告视图,pos为需要显示的位置,是个枚举。

typedef enum
{
    POS_CENTER = 0,/**< enum the toolbar is at center. */
    POS_TOP,/**< enum the toolbar is at top. */
    POS_TOP_LEFT,/**< enum the toolbar is at topleft. */
    POS_TOP_RIGHT,/**< enum the toolbar is at topright. */
    POS_BOTTOM,/**< enum the toolbar is at bottom. */
    POS_BOTTOM_LEFT,/**< enum the toolbar is at bottomleft. */
    POS_BOTTOM_RIGHT/**< enum the toolbar is at bottomright. */
}AD_POS;

通用调用SDK相关方法,创建了广告视图,需要调用addAdView:atPos:方法,把视图展示出来。
详细案例请参照显示广告一节。