之前写了篇Cocos2d-x 3.X, iOS版添加广点通广告。但是那篇只提到了广告条的集成(有需要的,请戳这里)。不少网友反映出对插屏广告的需求。所以在这里就把插屏广告的集成也写一遍。其实方法是一样的,就是做一个C++类,把它的源文件后缀改成mm,这样就可以把广点通的Objective C指令放里面和C++一起混编。同时它的头文件不含Objective C指令,这样就可以被纯C++文件包含。
本文所用Cocos2d-x为3.9版,Xcode为7.1版,广点通SDK为IOS 4.1版。(插播广告:如需添加安卓版广告请戳这里)
准备工作:
1)进入广点通官网,注册账号。注册时需要上传身份证正反面照片(好像还需要手持身份证照片)以及银行账户。然后等待审核。广点通审核时间略长,大概要一个礼拜。
2)审核通过后就可以创建应用和广告位,并得到应用和广告位ID。这两个ID会被添加到我们的程序当中。
3)下载广点通IOS版SDK。广点通的SDK文件夹里有示例代码和帮助文档Guide 4.1.pdf。可以打开看一看(可以结合本文一起阅读),但是没有针对Cocos2d-x的。
开干正事:
1)新建HelloWorld项目。在搞懂如何添加之前,建议不要直接在自己的工程里面添加,最好新建一个HelloWorld项目用于试验。新建IOS版的HelloWorld项目相对简单。配置好环境变量后,只需一行命令即可完成。这个可以参考Cocos2d-x官方文档。
2)添加广点通SDK。打开下载好的广点通SDK文件夹,将其中libs里面的所有文件都拖入Xcode的HelloWorld项目中(注意libGDTMobSDK.a得放在项目根目录下,如果放在Classes下面链接时会找不到)。
3)添加相应Frameworks。进入Xcode项目的TARGETS部分,选择HelloWorld-mobile,进入Build Phases下的Link Binary With Libraries。往里面添加以下Frameworks:
AdSupport.framework,CoreLocation.frameworkQuartzCore.framework (注意官方文档上单词拼写错误,漏了一个t)SystemConfiguration.frameworkCoreTelephony.frameworklibz.dylib或libz.tbdSecurity.frameworkStoreKit.framework
这些都是广点通帮助文档里要求添加的Frameworks。但是这些还不够,还需要往里面添加两个frameworks:GameController.framework和MediaPlayer.framework。具体原因请参考之前的那篇广告条添加(戳这里)。
4)更改导入静态库设置。再次进入Xcode项目的TARGETS部分,选择HelloWorld-mobile,进入Build Settings下面的Linking部分,往Other Linker Flags里添加两个参数-ObjC和-lstdc++。
以上部分和官方帮助文档Guide 4.1.pdf一致,如有不清楚的地方可以参考官方文档。接下来就不太一样了,请留意。
5)找到RootViewController.h,令RootViewController继承一个广点通广告条相关协议,以便让RootViewController成为广告的代理。并且为了在测试时监控广告是否加载成功,我们在RootViewController.mm里实现两个协议方法。完整代码如下所示:
RootViewController.h
#import <UIKit/UIKit.h> #import "GDTMobInterstitial.h" @interface RootViewController : UIViewController<GDTMobInterstitialDelegate> { } - (BOOL) prefeRSStatusBarHidden; @end
#import "RootViewController.h" #import "cocos2d.h" #import "platform/ios/CCEAGLView-ios.h" static NSString *INTERSTITIAL_STATE_TEXT = @"插屏状态"; @implementation RootViewController /** * 广告预加载成功回调 * 详解:当接收服务器返回的广告数据成功后调用该函数 */ - (void)interstitialSuccessToLoadAd:(GDTMobInterstitial *)interstitial { NSLog(@"%@:%@",INTERSTITIAL_STATE_TEXT,@"Success Loaded."); } /** * 广告预加载失败回调 * 详解:当接收服务器返回的广告数据失败后调用该函数 */ - (void)interstitialFailToLoadAd:(GDTMobInterstitial *)interstitial error:(NSError *)error { NSLog(@"%@:%@",@"Fail Loaded." ); } /* // The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) { // Custom initialization } return self; } */ /* // Implement loadView to create a view hierarchy programmatically,without using a nib. - (void)loadView { } */ /* // Implement viewDidLoad to do additional setup after loading the view,typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; } */ // Override to allow orientations other than the default portrait orientation. // This method is deprecated on ios6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return UIInterfaceOrientationIsLandscape( interfaceOrientation ); } // For ios6,use supportedInterfaceOrientations & shouldAutorotate instead - (NSUInteger) supportedInterfaceOrientations{ #ifdef __IPHONE_6_0 return UIInterfaceOrientationMaskAllButUpsideDown; #endif } - (BOOL) shouldAutorotate { return YES; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; auto glview = cocos2d::Director::getInstance()->getOpenGLView(); if (glview) { CCEAGLView *eaglview = (CCEAGLView*) glview->getEAGLView(); if (eaglview) { CGSize s = CGSizeMake([eaglview getWidth],[eaglview getHeight]); cocos2d::Application::getInstance()->applicationScreenSizeChanged((int) s.width,(int) s.height); } } } //fix not hide status on ios7 - (BOOL)prefeRSStatusBarHidden { return YES; } - (void)didReceiveMemoryWarning { // Releases the view if it doesn't have a superview. [super didReceiveMemoryWarning]; // Release any cached data,images,etc that aren't in use. } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; } - (void)dealloc { [super dealloc]; } @end
6) 新建一个C++类,命名为AdInterC,用来加载和显示广告。注意我们要在Cocos2d-x的场景里生成广告,而Cocos2d-x场景又都是C++代码实现的(主要是因为Cocos2d-x都是以.cpp文件存在,它不支持对Objective C指令的编译),所以必须新建C++类,而非Objective C类。完整代码如下:
#ifndef AdInterC_hpp #define AdInterC_hpp //要被cpp包含,所以不能有任何Objective C指令,也就是说这里即不能#import GDTMobBannerView.h, //也不能用@class GDTMobBannerView. 只能通过一个结构体来间接的调用GDTMobBannerView struct AdInterImpl; class AdInterC { public: AdInterC(); ~AdInterC(); void loadAd();//加载广告 void showAd();//显示广告 private: AdInterImpl* impl; }; #endif /* AdInterC_hpp */
#include "AdInterC.h" #include "RootViewController.h" struct AdInterImpl { GDTMobInterstitial * _interObj; }; AdInterC::AdInterC() { impl = new AdInterImpl(); } AdInterC::~AdInterC() { impl->_interObj.delegate=nil; delete impl; } void AdInterC::loadAd() { impl->_interObj = [[GDTMobInterstitial alloc] initWithAppkey:@"2211675583" placementId:@"2954362461573316031"];//注意测试的时候就要改成自己申请来的ID,否则很难加载成功 auto rootViewController = (RootViewController*) [[[UIApplication sharedApplication] keyWindow] rootViewController]; impl->_interObj.delegate = rootViewController; //设置委托 impl->_interObj.isGpsOn = NO; //【可选】设置GPS开关 //预加载广告 [impl->_interObj loadAd]; } void AdInterC::showAd() { UIViewController *vc = [[[UIApplication sharedApplication] keyWindow] rootViewController]; [impl->_interObj presentFromRootViewController:vc]; }注意要把app key和placement id改成自己申请来的,否则很难加载成功。另外要把加载方法和显示方法分开。
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include "AdInterC.h" class HelloWorld : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); //加载回调 void loadCallback(cocos2d::Ref* pSender); //显示回调 void showCallback(cocos2d::Ref* pSender); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); AdInterC *ad; }; #endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h" USING_NS_CC; Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } //创建一个广告类对象 ad=new AdInterC(); Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); ///////////////////////////// // 2. add a menu item with "X" image,which is clicked to quit the program // you may modify it. //加载菜单项 auto loadItem = MenuItemImage::create( "CloseNormal.png","CloseSelected.png",CC_CALLBACK_1(HelloWorld::loadCallback,this)); //显示菜单项 auto showItem = MenuItemImage::create( "CloseNormal.png",CC_CALLBACK_1(HelloWorld::showCallback,this)); loadItem->setPosition(Vec2(origin.x + loadItem->getContentSize().width/2,origin.y + loadItem->getContentSize().height/2)); showItem->setPosition(Vec2(origin.x + visibleSize.width - showItem->getContentSize().width/2,origin.y + showItem->getContentSize().height/2)); // create menu,it's an autorelease object auto menu = Menu::create(loadItem,showItem,NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu,1); ///////////////////////////// // 3. add your codes below... // add a label shows "Hello World" // create and initialize a label auto label = Label::createWithTTF("Hello World","fonts/Marker Felt.ttf",24); // position the label on the center of the screen label->setPosition(Vec2(origin.x + visibleSize.width/2,origin.y + visibleSize.height - label->getContentSize().height)); // add the label as a child to this layer this->addChild(label,1); // add "HelloWorld" splash screen" auto sprite = Sprite::create("HelloWorld.png"); // position the sprite on the center of the screen sprite->setPosition(Vec2(visibleSize.width/2 + origin.x,visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer this->addChild(sprite,0); return true; } void HelloWorld::loadCallback(Ref* pSender) { ad->loadAd(); } void HelloWorld::showCallback(Ref* pSender) { ad->showAd(); }
水平有限,如有不妥,欢迎指正!
参考资料:
1)广点通官方文档Guide 4.0.pdf
2) 广大网友