cocos2d-x 3.16 接入admob广告流程

先上成功图

image.png

下面开始讲我历时5个月(断断续续利用业余时间) 头铁硬刚、不服周(湖北话)的结果
虽然接sdk对别人可能是一个很简单的事情, 但是之前项目一直是做框架和逻辑sdk都交给别人了
所以自己接还是费了许多力气的

如果要接这个sdk 请耐心看完这篇教程 可能到处都是坑 如果不仔细看 你可能会花更多时间采坑
当然也许有些坑我也没有踩过:)

首先admob 是基于filebase的

cocos的环境安装我就不教了 因为这里主要是讲admob 所以环境安装请自行百度
我目前机器里面的环境有
android studio 3.2.1
sdk(android studio 自带)
ndk(sdk 里面的子目录 我的是F:\android_sdk\sdk\ndk-bundle) ndk-r14d以上
java 以及设置JAVA_HOME 和 path

创建项目调用cocos 命令行

cocos new MyGame -l cpp

但是我们使用的是android studio 并不是cocos的命令行打包
为什么 因为3.17 以后命令行打包方式已经被cocos 官方放弃了
所以我建议从3.16版本就开始熟悉使用android studio 熟悉打包
下面所有的android studio 简称[as]

首先你需要用as 成功打包一个 cocos2d-x 3.16 的 cpp hello world 项目 能够成功在真机上运行
然后
先阅读链接1

https://firebase.google.com/docs/admob/cpp/cocos2d-x?hl=zh-cn

按照链接1里面的要求先下载sdk


image.png

注意这里的sdk一般是官方最新的
一开始我下载的时候是5.4.2 过了一段时间又下载到了5.4.3
然后接sdk突然卡住了2个月(期间经历公司破产换工作,新工作压力的时间,最近从新开始研究)下载了 5.6.0

image.png

最终我使用了5.6.0

另外我也没有接入ios 我只接入了android的 如果有需要的朋友可以自行研究
下载过后解压放入自己的MyGame项目目录


我的目录结构

我的目录结构2

接着来填写Android.mk
官方给出的示例是这样的


image.png
LOCAL_PATH := $(call my-dir)

# The path to the Firebase C++ SDK, in the project's root directory.
FIREBASE_CPP_SDK_DIR := ../../../firebase_cpp_sdk

APP_ABI := armeabi-v7a x86
STL := $(firstword $(subst _, ,$(APP_STL)))
FIREBASE_LIBRARY_PATH := $(FIREBASE_CPP_SDK_DIR)/libs/android/$(TARGET_ARCH_ABI)/$(STL)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_app
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libfirebase_app.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/$(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := firebase_feature
LOCAL_SRC_FILES := $(FIREBASE_LIBRARY_PATH)/libfirebase_admob.a
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/$(FIREBASE_CPP_SDK_DIR)/include
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d)
$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/external)
$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/cocos)
$(call import-add-path,$(LOCAL_PATH)/../../../cocos2d/cocos/audio/include)

LOCAL_MODULE := MyGame_shared

LOCAL_MODULE_FILENAME := libMyGame

LOCAL_SRC_FILES := $(LOCAL_PATH)/hellocpp/main.cpp \
                   $(LOCAL_PATH)/../../../Classes/AppDelegate.cpp \
                   $(LOCAL_PATH)/../../../Classes/HelloWorldScene.cpp \
                   $(LOCAL_PATH)/../../../Classes/FirebaseHelper.cpp

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../Classes

# _COCOS_HEADER_ANDROID_BEGIN
# _COCOS_HEADER_ANDROID_END


LOCAL_STATIC_LIBRARIES := cocos2dx_static
LOCAL_STATIC_LIBRARIES += firebase_app
LOCAL_STATIC_LIBRARIES += firebase_feature

# _COCOS_LIB_ANDROID_BEGIN
# _COCOS_LIB_ANDROID_END

include $(BUILD_SHARED_LIBRARY)

$(call import-module,.)

# _COCOS_LIB_IMPORT_ANDROID_BEGIN
# _COCOS_LIB_IMPORT_ANDROID_END

这里被坑了很久
与官方教程不同的是


image.png

填完后as里面编译


image.png

或者


image.png

同官方教程


image.png

接下来是官方教程的第3步


image.png

打开这个链接
首先重要的是


image.png

请按要求准备前提条件

继续


image.png

image.png

image.png

添加项目这里由于我已经注册过了 写教程的时候就没了这个过程 可能需要你自己去尝试

继续往下看教程


image.png

image.png

这里的设置是指的刚刚的filebase控制台设置


image.png

点击这里下载这个重要的链接文件

点击这里下载这个重要的链接文件

image.png

image.png

这是我的目录结构

image.png

image.png

请真机运行你这个时候的项目 确保能够看到cocos的 hello world 界面而没有报错

这个时候添加sdk

根级 build.gradle

image.png

这是我的版本


image.png
classpath 'com.google.gms:google-services:4.0.1'

模块 Gradle 文件(通常是 app/build.gradle)

image.png

这是我的版本


image.png
    implementation 'com.google.firebase:firebase-core:16.0.7'
    implementation 'com.google.firebase:firebase-ads:17.1.3'
    implementation 'com.google.firebase:firebase-common:16.1.0'

接下来看教程


image.png

这些都是最新的库版本 但是得对应最新的官方sdk包 就是上面说的sdk版本5.6.0(也许你接的时候并不是5.6.0)

image.png

接下来 我们回到主教程

https://firebase.google.com/docs/admob/cpp/cocos2d-x?hl=zh-cn

再次真机运行app看有没有报错

再次真机运行app看有没有报错

没有报错 继续
这里需要注册一下admob的 尽量与google filebase 账号关联
https://apps.admob.com/

image.png

注册完了以后 这里会有2个ID
这个是广告单元的ID 简称 [广告ID]
image.png

这里是Firebase 应用ID 简称 [应用ID]

image.png

然后有了这2个ID 继续我们刚才的主教程


image.png

头文件包含


image.png

我的

#include "../firebase_cpp_sdk/include/firebase/admob/types.h"

接着按照教程做 到


image.png

我的头文件 HelloWorldScene.h 请看中文注释 有细节

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

//这里是我的目录 你可以参考
#include "../firebase_cpp_sdk/include/firebase/admob.h"
#include "../firebase_cpp_sdk/include/firebase/admob/types.h"
#include "../firebase_cpp_sdk/include/firebase/app.h"
#include "../firebase_cpp_sdk/include/firebase/future.h"
#include "../firebase_cpp_sdk/include/firebase/admob/banner_view.h"

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include 
#include 
#include "platform/android/jni/JniHelper.h"
#endif

class HelloWorld : public cocos2d::Scene
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();
    
    // a selector callback
    void menuCloseCallback(cocos2d::Ref* pSender);

    void update(float delta);
    
    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);

    //这里添加一个成员变量
    // Create and initialize banner view. 
    firebase::admob::BannerView* banner_view;
};

#endif // __HELLOWORLD_SCENE_H__

这是我的HelloWorldScene.cpp 请看中文注释 有细节

#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"

#include "FirebaseHelper.h"




USING_NS_CC;

Scene* HelloWorld::createScene()
{
    return HelloWorld::create();
}

// Print useful error message instead of segfaulting when files are not there.
static void problemLoading(const char* filename)
{
    printf("Error while loading: %s\n", filename);
    printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in HelloWorldScene.cpp\n");
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Scene::init() )
    {
        return false;
    }

    auto 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));

    if (closeItem == nullptr ||
        closeItem->getContentSize().width <= 0 ||
        closeItem->getContentSize().height <= 0)
    {
        problemLoading("'CloseNormal.png' and 'CloseSelected.png'");
    }
    else
    {
        float x = origin.x + visibleSize.width - closeItem->getContentSize().width/2;
        float y = origin.y + closeItem->getContentSize().height/2;
        closeItem->setPosition(Vec2(x,y));
    }

    // 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);
    if (label == nullptr)
    {
        problemLoading("'fonts/Marker Felt.ttf'");
    }
    else
    {
        // 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");
    if (sprite == nullptr)
    {
        problemLoading("'HelloWorld.png'");
    }
    else
    {
        // 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);
    }

    //sdk从这里开始
#if defined(__ANDROID__)


    //这个测试广告ID来自 https://developers.google.com/admob/android/test-ads#enable_test_devices 请仔细阅读
    //建议一开始使用这个ID来测试 先能够正常显示后 再进行下面的进一步的正式广告ID测试
    //const char* kBannerAdUnit = "ca-app-pub-3940256099942544/6300978111";

    // !!!重要 这里是斜杠的广告ID
    // Android ad unit IDs.
    const char* kBannerAdUnit = "ca-app-pub-XXXXXXXXXXXXXXXX/XXXXXXXXXX";

#else
    // iOS ad unit IDs.
  const char* kBannerAdUnit = "ca-app-pub-3940256099942544/2934735716";
#endif

    banner_view = new firebase::admob::BannerView();
    firebase::admob::AdSize ad_size;
    ad_size.ad_size_type = firebase::admob::kAdSizeStandard;
    ad_size.width = 320;
    ad_size.height = 50;
    banner_view->Initialize(getAdParent(), kBannerAdUnit, ad_size);

    // Schedule updates so that the Cocos2d-x update() method gets called.
    this->scheduleUpdate();

    return true;
}

void HelloWorld::update(float delta) {
    // Check that the banner has been initialized.
    if (banner_view->InitializeLastResult().status() ==
        firebase::kFutureStatusComplete) {
        // Check that the banner hasn't started loading.
        if (banner_view->LoadAdLastResult().status() ==
            firebase::kFutureStatusInvalid) {
            // Make the banner visible and load an ad.
            CCLOG("Loading a banner.");
            banner_view->Show();

            //官方只有这一句
            firebase::admob::AdRequest my_ad_request = {};


            // ad_request 属性设置 AAA ------------------
            // 这里的段落来自上面测试ID的那个网站

            // 这里请自行翻译英文 我采用的官方默认值
            // If the app is aware of the user's gender, it can be added to the
            // targeting information. Otherwise, "unknown" should be used.
            my_ad_request.gender = firebase::admob::kGenderUnknown;

            // 这里请自行翻译英文 我采用的官方默认值
            // The user's birthday, if known. Note that months are indexed from one.
            my_ad_request.birthday_day = 10;
            my_ad_request.birthday_month = 11;
            my_ad_request.birthday_year = 1976;

            // 这里请自行翻译英文 我采用的官方默认值
            // Additional keywords to be used in targeting.
            static const char* kKeywords[] = {"AdMob", "C++", "Fun"};
            my_ad_request.keyword_count = sizeof(kKeywords) / sizeof(kKeywords[0]);
            my_ad_request.keywords = kKeywords;

            // 这里请自行翻译英文 我采用的官方默认值
            // "Extra" key value pairs can be added to the request as well.
            static const firebase::admob::KeyValuePair kRequestExtras[] = {
                    {"the_name_of_an_extra", "the_value_for_that_extra"}};
            my_ad_request.extras_count = sizeof(kRequestExtras) / sizeof(kRequestExtras[0]);
            my_ad_request.extras = kRequestExtras;

            //!!!重要 这里是你的测试设备队列 请参考上面测试ID网站说明
            // 如果不添加这个 要么你的真机测试流程无法跑起来 要么你点击广告会被别人举报(无效点击) 可能导致被封号 慎重
            // 另外我测试这些机器 有3台安装了360手机助手的 谷歌安装器 并且安装了相关的谷歌套件 有2台什么也没有安 但是都可以运行成功
            // 请关注 as logcat 的 AdRequest.Builder.addTestDevice 得到你的测试设备ID填入下面队列
            // Register the device IDs associated with any devices that will be used to
            // test your app. Below are sample test device IDs used for making the ad request.
            static const char* kTestDeviceIDs[] =
                    {"B22C21BE0A5510577E3141D66C34B72B",//测试机1
                     "28399F3437D1FA3CA8F8C4BC150A4CEA",//测试机2
                     "89B5AD7495729AE69BFA72D5477C66BA",//测试机3
                     "BFCF6E25A5308D10E4F798C40D261CE2",//测试机4
                     "B621B231ECA4C84418EE7FDA1073CAE5"};//测试机5
            my_ad_request.test_device_id_count =
                    sizeof(kTestDeviceIDs) / sizeof(kTestDeviceIDs[0]);
            my_ad_request.test_device_ids = kTestDeviceIDs;
            // ad_request 属性设置 AAA ------------------

            //官方的第二句
            banner_view->LoadAd(my_ad_request);
        }
    }
}

void HelloWorld::menuCloseCallback(Ref* pSender)
{
    //Close the cocos2d-x game scene and quit the application
    Director::getInstance()->end();

    #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif

    /*To navigate back to native iOS screen(if present) without quitting the application  ,do not use Director::getInstance()->end() and exit(0) as given above,instead trigger a custom event created in RootViewController.mm as below*/

    //EventCustom customEndEvent("game_scene_close_event");
    //_eventDispatcher->dispatchEvent(&customEndEvent);


}

关于测试admob 重要 请仔细阅读
https://developers.google.com/admob/android/test-ads#enable_test_devices

这是我使用的测试ID效果


image.png

重要1


image.png

重要2


image.png

到这里 基本就运行完毕了
如果中间有错误 请查看as logcat 尽量先看error
如果出现
Ad failed to load : 0
有2种情况 一种是你刚刚发布admob账号下的广告应用 可能需要等几小时 或者几天
具体以关联admob的 邮箱收件为准
如果收到了这一条消息 证明你已经通过了这一条


image.png

还有一种情况就是我遇到的情况 就是我错把广告ID 填成了应用ID导致 广告显示部分完全是黑色的
这里注意我上面反复强调的应用ID就行

重要链接:

https://firebase.google.com/docs/admob/android/quick-start
还有一处重要位置我也有更改

image.png

注意这里是应用ID


 
image.png

!!! 还有一个非常重要的设置
就是刚刚的admob的控制台
https://apps.admob.com/

image.png

一定要设置付款信息 否则也是会导致广告无法正常播放的

到这里基本就已经成功了

如果还没有成功 建议google搜索 一定比百度有用
搜索结果尽量先看https://stackoverflow.com/
这里给出的建议 我的问题基本都是这样解决的

另外百度基本解决不了这个SDK的问题

加油 我相信你也可以!!!

另外宣传一下我的独立游戏开发QQ群:386239391
欢迎讨论

你可能感兴趣的:(cocos2d-x 3.16 接入admob广告流程)