考虑到以下两点:
1. Cocos2d-x从3.7版开始优化对Android Studio的支持,相信这一趋势还会继续。可惜目前相关帮助文档还不完善,很多东西需要自己摸索。
2. 广点通广告平台的官方帮助文档没有针对Cocos2d-x。
所以在此对自己所学所得做一些总结,也希望能帮助到那些处在摸索之中的朋友们。
本文所用cocos2d-x为3.8版,android studio为1.3.2版,广点通SDK为4.8版。
准备工作:
1)进入广点通官网,注册账号。注册时需要上传身份证正反面照片(好像还需要手持身份证照片)以及银行账户。然后等待审核。广点通审核时间略长,大概要一个礼拜。
2)审核通过后就可以创建应用和广告位。
3)下载广点通安卓版SDK。广点通的SDK文件夹里有示例代码,可以打开看一看,官网上也帮助文档,但是没有针对Cocos2d-x的。
开干正事:
1)在搞懂如何添加之前,建议不要直接在自己的工程里添加,最好新建一个HelloWorld项目用于试验。关于如何新建一个Android Studio版的HelloWorld项目,请参考博主另一篇博文。
2)打开下载下来的广点通文件夹,复制其中的GDTUnionSDK.4.8.509.jar文件,并拷贝到新建的HelloWorld项目下proj.android-studio->app->libs->armeabi文件夹中(该文件夹只有在第一步中完成编译之后才会出现)。并在Android Studio中打开HelloWorld项目,找到GDTUnionSDK.4.8.509.jar(在jiniLibs->armeabi下面),右击,选择Add As Library。这样就把广点通SDK添加到我们的项目中了。
3)在Android Studio中打开AndroidManifest.xml文件,往里面添加广点通权限声明和Activity声明。添加完后完整代码如下所示:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.istudy.HelloWorldGDT" android:installLocation="auto"> <!--广点通声明1开始--> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_UPDATES"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!--广点通声明1结束--> <uses-feature android:glEsVersion="0x00020000" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher"> <!-- Tell Cocos2dxActivity the name of our .so --> <Meta-data android:name="android.app.lib_name" android:value="cocos2dcpp" /> <!--广点通声明2开始--> <service android:name="com.qq.e.comm.DownloadService" android:exported="false" > </service> <activity android:name="com.qq.e.ads.ADActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" > </activity> <!--广点通声明2结束--> <activity android:name="org.cocos2dx.cpp.AppActivity" android:screenOrientation="portrait" android:configChanges="orientation|keyboardHidden|screenSize" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
4)在Android Studio里打开AppActivity,往里面添加显示广告的Java代码。但是跟由于我们Cocos2d-x的场景都是用C++实现的,所以我们在这里需要利用Handler来做接口。这和官方帮助文档不同。添加完后完整代码如下所示:
AppActivity
package org.cocos2dx.cpp; import org.cocos2dx.lib.Cocos2dxActivity; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.RelativeLayout; import com.qq.e.ads.banner.ADSize; import com.qq.e.ads.banner.AbstractBannerADListener; import com.qq.e.ads.banner.BannerView; public class AppActivity extends Cocos2dxActivity { //声明应用ID public static final String APPID = "1101152570"; //声明广告条容器,广告条和广告位ID private static RelativeLayout bannerContainer; BannerView bv; public static final String BannerPosID="9079537218417626401"; //声明handler用于发送消息 private static Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //创建广告条容器 bannerContainer = new RelativeLayout(this); RelativeLayout.LayoutParams parentLayoutParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT); this.addContentView(bannerContainer,parentLayoutParams); //加载或卸载广告 handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 0:// showBannerAd() if (bannerContainer.getChildCount() == 0) { //初始化并加载广告条 initBanner(); bv.loadAD(); }else{ if (bv != null) { bv.setVisibility(View.VISIBLE); bv.loadAD(); } } break; case 1: //hideBannerAd() if (bv != null) { doCloseBanner(); } break; default: break; } } }; } private void initBanner() { bv = new BannerView(this,ADSize.BANNER,APPID,BannerPosID); bv.setRefresh(30); bv.setADListener(new AbstractBannerADListener() { @Override public void onNoAD(int arg0) { Log.i("AD_DEMO","BannerNoAD,eCode=" + arg0); } @Override public void onADReceiv() { Log.i("AD_DEMO","ONBannerReceive"); } }); //添加广告并设置它的位置 RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT); //layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,RelativeLayout.TRUE); layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL,RelativeLayout.TRUE); bannerContainer.addView(AppActivity.this.bv,layoutParams); } //刷新 private void doRefreshBanner() { if (bv == null) { initBanner(); } bv.loadAD(); } //关闭 private void doCloseBanner() { bannerContainer.removeAllViews(); bv.destroy(); bv = null; } //打开和关闭广告接口 public static void showBannerAd() { handler.sendEmptyMessage(0); } public static void hideBannerAd() { handler.sendEmptyMessage(1); } }
注意我们这里是用代码来创建一个RelativeLayer布局对象来作为广告条容器的,而非通过布局文件xml来实现的,这一点和官方文档也不同。
5)在Cocos2d-x的Classes下面新建一个类,命名为GDTAD,在里面通过jni把Java的广告开关转换成了C++函数,以便在Cocos2d-x场景里调用。完整代码如下:
GDTAD.h
#ifndef CLASSES_GDTAD_H #define CLASSES_GDTAD_H class GDTAD { public: static void showBannerAd(); static void hideBannerAd(); }; #endif //CLASSES_GDTAD_H
#include "GDTAD.h" #include "cocos2d.h" USING_NS_CC; #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "platform/android/jni/JniHelper.h" #include <jni.h> const char* AppActivityCalssName = "org/cocos2dx/cpp/AppActivity"; //显示广告条 void GDTAD::showBannerAd() { cocos2d::JniMethodInfo showBanner; if (cocos2d::JniHelper::getStaticMethodInfo(showBanner,AppActivityCalssName,"showBannerAd","()V")) { showBanner.env->CallStaticVoidMethod(showBanner.classID,showBanner.methodID); } else{ log("jni:showBannerStatic false"); } } //隐藏广告条 void GDTAD::hideBannerAd() { cocos2d::JniMethodInfo hideBanner; if (cocos2d::JniHelper::getStaticMethodInfo(hideBanner,"hideBannerAd","()V")) { hideBanner.env->CallStaticVoidMethod(hideBanner.classID,hideBanner.methodID); } else{ log("jni:hideBannerStatic false"); } } #else //广告条 void GDTAD::showBannerAd() { log("showBannerAd() called"); return; } void GDTAD::hideBannerAd() { log("hideBannerAd() called"); return; } #endif
6)接下来就可以愉快的在Cocos2d-x场景里添加广告了。这里我们在HelloWorld场景的最上端添加一个广告条,完整代码如下
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include "GDTAD.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); }; #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; } 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... //添加广告条 GDTAD::showBannerAd(); // 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 }
7)编译并运行。在编译之前需要在Android.mk文件里面添加GDTAD.cpp的路径,否则新建的C++文件无法被编译进来。比如我这里可以输入vi ~/Documents/HelloWorld/proj.android-studio/app/jni/Android.mk进行添加。最终运行后效果如下图所示:
从效果图中可以看出我们已经在AndroidManifest.xml里把横屏改成了竖屏。
水平有限,如有不妥,欢迎指正!
参考文献:
[1]广点通官方示例代码。