大佬教程收集整理的这篇文章主要介绍了Cocos2d-x 3.X, IOS版添加广点通广告平台,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
苹果自己的广告平台iAD在中国不好使,获取不到广告,所以必须搞个本土广告平台。首先想到的是广点通。可是广点通官方文档里没有针对Cocos2d-x的版本,所以只好自己摸索。在添加过程中确实遇到了不少问题,在这里将解决方法整理一下,希望能帮助到那些还处于摸索中的朋友们。
本文所用Cocos2d-x为3.8.1版,Xcode为7.1版,广点通SDK为IOS 4.0版。
准备工作:
1)进入广点通官网,注册账号。注册时需要上传身份证正反面照片(好像还需要手持身份证照片)以及银行账户。然后等待审核。广点通审核时间略长,大概要一个礼拜。
2)审核通过后就可以创建应用和广告位,并得到应用和广告位ID。这两个ID会被添加到我们的程序当中。
3)下载广点通IOS版SDK。广点通的SDK文件夹里有示例代码和帮助文档Guide 4.0.pdf。可以打开看一看(可以结合本文一起阅读),但是没有针对Cocos2d-x的。
开干正事:
1)新建HelloWorld项目。在搞懂如何添加之前,建议不要直接在自己的工程里面添加,最好新建一个HelloWorld项目用于试验。新建IOS版的HelloWorld项目相对简单。配置好环境变量后,只需一行命令即可完成。这个可以参考Cocos2d-x官方文档。
2)添加广点通SDK。打开下载好的广点通SDK文件夹,将其中libs里面的所有文件都拖入Xcode的HelloWorld项目中(以group形式加入)。
3)添加相应Frameworks。进入Xcode项目的TARGETS部分,选择HelloWorld-mobile,进入Build Phases下的Link Binary With Libraries。往里面添加以下Frameworks:
AdSupport.framework,CoreLOCATIOn.framework,QuarzCore.framework,SystemConfiguration.framework,CoreTelephony.framework,libz.dylib或 libz.tbd,Security.framework,StoreKit.framework
这些都是广点通帮助文档里要求添加的Frameworks。我们暂且只添加这些,留一伏笔。
4)更改导入静态库设置。再次进入Xcode项目的TARGETS部分,选择HellWorld-mobile,进入Build SetTings下面的Linking部分,往Other Linker Flags里添加两个参数-ObjC和-lstd++。此处再留一伏笔。
以上部分和官方帮助文档Guide 4.0.pdf一致,如有不清楚的地方可以参考官方文档。接下来就不太一样了,请留意。
5)找到RootViewController.h,令RootViewController类继承一个广点通广告条相关协议。完整代码如下
RootViewController.h
#import <UIKit/UIKit.h> #import "GDTMobBAnnerView.h" @interface RootViewController : UIViewController <GDTMobBAnnerViewDelegate>{ } - (BOOL) prefersStatusBarHidden; @end
这一步是为了让RootViewController成为广告的代理。在最简情形下,这样就可以了,无需在RootViewController.mm里添加任何东西。如果需要其他功能,比如当请求广告数据失败后想要触发一个事件(比如输出一段请求失败的信息),那么可以在此实现以下协议方法:
- (void)bAnnerViewFailToReceived:(NSError *)error
6)新建一个C++类,命名为AdBAnnerC,用来生成广告。注意我们要在Cocos2d-x的场景里生成广告,而Cocos2d-x场景又都是C++代码实现的(主要是因为Cocos2d-x都是以.cpp文件存在,它不支持对Objective C指令的编译),所以必须新建C++类,而非Objective C类。完整代码如下:
AdBAnnerC.h
#ifndef AdBAnnerC_h #define AdBAnnerC_h //要被cpp包含,所以不能有任何Objective C指令,也就是说这里即不能#import GDTMobBAnnerView.h, //也不能用@class GDTMobBAnnerView. 只能通过一个结构体来间接的调用GDTMobBAnnerView struct AdBAnnerImpl; class AdBAnnerC { public: AdBAnnerC(); ~AdBAnnerC(); private: AdBAnnerImpl* impl; }; #endif
#include "AdBAnnerC.h" #include "RootViewController.h" struct AdBAnnerImpl { GDTMobBAnnerView * _bAnnerView; }; AdBAnnerC::AdBAnnerC() { impl = new AdBAnnerImpl(); impl->_bAnnerView=[[GDTMobBAnnerView alloc] initWithFrame:CGRectMake(0,GDTMOB_AD_SUGGEST_SIZE_320x50.width,GDTMOB_AD_SUGGEST_SIZE_320x50.height) appkey:@"100720253" placementId:@"9079537207574943610"]; //调用RooViewController对象 auto rootViewController = (RootViewController*) [[[UIApplication sharedApplication] keyWindow] rootViewController]; impl->_bAnnerView.delegate = rootViewController; // 设置Delegate impl->_bAnnerView.currentViewController = rootViewController; //设置当前的ViewController impl->_bAnnerView.interval = 30; //【可选】设置刷新频率;默认30秒 impl->_bAnnerView.isGpsOn = NO; //【可选】开启GPS定位;默认关闭 impl->_bAnnerView.showCloseBtn = YES; //【可选】展示关闭按钮;默认显示 impl->_bAnnerView.isAnimationOn = YES; //【可选】开启bAnner轮播和展现时的动画效果;默认开启 [rootViewController.view addSubview:impl->_bAnnerView]; //添加到当前的view中 [impl->_bAnnerView loadAdAndShow]; //加载广告并展示 } AdBAnnerC::~AdBAnnerC() { impl->_bAnnerView.delegate = nil; impl->_bAnnerView.currentViewController = nil; [impl->_bAnnerView release]; delete impl; }
7)这样就可以愉快的往HelloWorld场景中添加AdBAnnerC对象,获取广告了。完整代码如下所示:
HelloWorldScene.h
#ifndef __HelLOWORLD_SCENE_H__ #define __HelLOWORLD_SCENE_H__ #include "cocos2d.h" #include "AdBAnnerC.h" class HelloWorld : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); // a SELEctor callBACk void menuCloseCallBACk(cocos2d::ref* pSender); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); //广告条对象 AdBAnnerC *adBAnner; }; #endif // __HelLOWORLD_SCENE_H__
#include "HelloWorldScene.h" //#include "AdBAnnerC.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; } 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. // add a "close" icon to exit the progress. it's an autorelease object auto closeItem = MenuItemImage::create( "CloseNormal.png","CloseSELEcted.png",CC_CALLBACK_1(HelloWorld::menuCloseCallBACk,this)); closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2,origin.y + closeItem->getContentSize().height/2)); // create menu,it's an autorelease object auto menu = Menu::create(closeItem,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::menuCloseCallBACk(Ref* pSender) { // Director::geTinstance()->end(); // //#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) // exit(0); //#endif //加广点通广告 adBAnner = new AdBAnnerC(); }
我们在这里把新建广告条函数放在了原先的关闭按钮回调函数里,这样只要按一下按钮就会弹出广告条。
8)编译运行。这时问题就来了。首先会提示出现7个错误:
"_MPMoviePlayerPlayBACkStateDidChangeNotification",referenced from: -[UIVideoViewWrapperIos dealloc] in libcocos2d iOs.a(UIVideoPlayer-ios.o) -[UIVideoViewWrapperIos setURL::] in libcocos2d iOs.a(UIVideoPlayer-ios.o) "_MPMoviePlayerPlayBACkDidFinishNotification",referenced from: -[UIVideoViewWrapperIos dealloc] in libcocos2d iOs.a(UIVideoPlayer-ios.o) -[UIVideoViewWrapperIos setURL::] in libcocos2d iOs.a(UIVideoPlayer-ios.o) "_OBJC_CLASS_$_GCController",referenced from: objc-class-ref in libcocos2d iOs.a(CCController-iOs.o) (maybe you meant: _OBJC_CLASS_$_GCControllerConnectionEventHandler) "_OBJC_CLASS_$_MPMoviePlayerController",referenced from: objc-class-ref in libcocos2d iOs.a(UIVideoPlayer-ios.o) "_GCControllerDidDisconnectNotification",referenced from: -[GCControllerConnectionEventHandler observerConnection:disconnection:] in libcocos2d iOs.a(CCController-iOs.o) "_GCControllerDidConnectNotification",referenced from: -[GCControllerConnectionEventHandler observerConnection:disconnection:] in libcocos2d iOs.a(CCController-iOs.o) ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)这时如果把第四步中设置的Other Linker Flags中的-ObjC去掉的话,便可以编译运行成功,但是当我们按下弹出广告条按钮时就会报错(包括unrecognized SELEctor sent to instance 0x79277930)。因此这个方法行不通,还得添加回去。那么问题在哪呢?决解这个问题的答案非常简单,就是添加两个Frameworks:GameController.framework和MediaPlayer.framework。但是要理解为什么就需要科普一下连接器的工作原理了:
连接器工作原理
在C语言里面,函数的调用和定义可以处于两个不同的文件里。比如main.c文件里调用了foo()函数(在调用之前必须声明该函数,但不必定义该函数),但是foo()的定义在B.c里面。那么编译器会在生成的目标文件main.o里给foo()函数做一个待定标记,告诉连接器该函数定义在别处。这样连接器就会找到定义该函数的目标文件B.o,并把它加进来。Unix的静态库其实就是一堆目标文件。在一般情况下,如果一个函数被声明了,但是没有被调用,那么它是没有待定标记的,连接器不会把静态库中定义该函数的目标文件加载进来,以减小可执行文件的大小。
对于Objective C,由于它的动态特性,情况略有不同。只有当某个方法(对应于C的函数)在运行时被调用了,计算机才知道它的实现(对应于C的函数定义)是什么(比如父类和子类对同一方法有不同实现。如果采用动态绑定,那么某个id对象即可以是父类也可以是子类,到底是什么只有在运行时才知道)。所以Objective C不对方法做待定标记,即便做了在连接时也不知道去哪里找实现。Objective C只对类做待定标记,因为类的实现是确定的。另一方面,Objective C里还有一个独特的存在叫做分类(category),它其实就是一堆方法的集合,是某个类的扩展。所以,如果某个文件调用了某个分类里面的方法,是不会产生这个分类的待定标记的,只会产生这个类的待定标记。所以默认情况下连接器不会把(静态库中)定义该分类的目标文件加进来。这样就会在运行时报错,找不到实现(unrecognized SELEctor)。解决方法就是“宁可错杀,不可放过”。添加-ObjC标志之后,连接器就把静态库中所有相关的分类实现都加进来,无论它们有没有被调用,只要头文件被包含过(也就是只要被声明过)就都加进来。
理解了这个原理之后就知道为啥去掉-ObjC后会在运行时出错,因为找不到某个实现了。但是加了-ObjC这个标志之后呢,连接器会将静态库中所有相关类和分类的实现都加进来,恰巧Cocos2d-x的文件里包含了两个静态库头文件GameController/GameController.h和MediaPlayer/MediaPlayer.h,连接器根据-ObjC必须加载它们对应的目标文件,但是又找不到,所以只好报错。解决办法就是添加这两个目标文件所在的Frameworks。参考资料在这里。
加了这两个Frameworks之后,果然可以编译运行了。但是在点击弹出广告按钮时还是报错:
App Transport Security has blocked a cleartext http (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
将这段报错信息拷贝到百度搜索栏里面,很快就能找到解决方法(参考这里)。原来是IOS9新增了App Transport Security特性,默认使用httpS协议,如果在IOS9下直接进行http请求就会报错。解决方法就是关闭这个特性: 进入项目TARGETS下的HelloWorld-mobile,找到info下的Cumstom ios Target Properties,添加App Transport Security SetTings,将其下面的AllowArbitrary Loads设置为Yes。如下图所示:
现在我们再来运行试试,发现没有报错了。但是在模拟器里一直获取不到广告。如果改用真机运行可以很容易获取到。运行结果如下图所示:
从上图可见我在新建HelloWorld项目中已经把横屏调成了竖屏。这只是个人喜好而已。在用真机测试时或者打包上传时可能还会遇到一个错误就是:-fembed-bitcode is not supported on versions of iOS prior to 6.0。这个问题是因为Xcode默认支持bitcode(程序的一种中间代码,它可以让苹果在后期对我们的二进制码进行优化),但是有些第三方库并不支持bitcode,所以解决办法就是关闭它:找到TARGETS->Build SetTings->Build Options->Enable Bitcode,将其设置为NO。参考在这里。
水平有限,如有不妥,欢迎指正!
参考资料:
1)广点通官方文档Guide 4.0.pdf
2) 广大网友
以上是大佬教程为你收集整理的Cocos2d-x 3.X, IOS版添加广点通广告平台全部内容,希望文章能够帮你解决Cocos2d-x 3.X, IOS版添加广点通广告平台所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。