JUCE + Firebase/AdMob: Lets monetize our JUCE iOS apps with Ads (partial How-To)

Progress update! I got the C++ SDK working.
Solution:

Create your juce project exactly as in the first post, then, download the C++ SDK linked in the previous post. Add the firebase.framework and firebase_admob.framework frameworks to the Extra Frameworks field in ProJucer.

add the folder holding the frameworks to the FRAMEWORK_SEARCH_PATHS list, after the original SDK framework. i.e.:

FRAMEWORK_SEARCH_PATHS="/Users/me/Firebase/Analytics 
/Users/me/Firebase/AdMob 
/Users/me/firebase_cpp_sdk/frameworks/ios/universal"

under `Custom plist, you’ll need to enable connections to http links:

<plist version="1.0">
  <dict>
  <key>NSAppTransportSecurity</key>
  <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
  </dict>
    </dict>
</plist>

change the .mm file in Projucer to no longer be a compile target. set Main.cpp to be a compile target. That’s right, you don’t need to do any Objective-C++ bridging anymore, unlike in the earlier post! it’s pure C++ the whole time!

Save and Open in IDE.
change initialise() to do what they say to do in the C++ SDK setup:

#include "firebase/admob.h"
#include "firebase/admob/types.h"
#include "firebase/app.h"
#include "firebase/future.h"

and place this in initialise()

// Create the Firebase app.
firebase::App* app = firebase::App::Create(firebase::AppOptions());
// Initialize the AdMob library with your AdMob app ID.
const char* kAdMobAppID = "ca-app-pub-XXXXXXXXXXXXXXXX~NNNNNNNNNN";
firebase::admob::Initialize(*app, kAdMobAppID);

Compile and run. your app is initialized to use Admob now. You should be able to follow the tutorial for Banner Ads and Interstitial Ads here now:
https://firebase.google.com/docs/admob/cpp/quick-start?authuser=0#interact_with_the_google_mobile_ads_sdk

With that said, this also opens the door for Firebase via the C++ SDK. just change with framework from the C++ SDK you add, based on the directions on the Firebase C++ page.

Here’s what my initialise() and MainContentComponent.cpp looked like:

#include "../JuceLibraryCode/JuceHeader.h"
#include "firebase/app.h"
#include "firebase/admob.h"
//...snip

    void initialise (const String& commandLine) override
    {
        // This method is where you should put your application's initialisation code..
        firebase::App* app = firebase::App::Create(firebase::AppOptions());

        StringRef googleTestAdID = "ca-app-pub-3940256099942544~1458002511";
        firebase::admob::Initialize(*app, googleTestAdID);
        
        mainWindow = new MainWindow (getApplicationName());
    }

MainContentComponent.h :

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"
#include "firebase/future.h"
#include "firebase/admob/banner_view.h"

class MainContentComponent   : public Component, public Timer
{
public:
    MainContentComponent();
    ~MainContentComponent();

    void paint (Graphics&) override;
    void resized() override;
    void timerCallback() override;
    static void initFutureCallback(const firebase::Future<void>& resultData,
                                           void* userData);
    static void showFutureCallback(const firebase::Future<void>& resultData, void* userData );
private:
    std::unique_ptr<firebase::admob::BannerView> bannerView;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

and MainContentComponent.cpp:

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

MainContentComponent::MainContentComponent()
{
    auto area  = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
    setSize(area.getWidth(), area.getHeight());
    startTimer(1000);
}

void MainContentComponent::timerCallback()
{
    stopTimer();
    bannerView = std::make_unique<firebase::admob::BannerView>();
    firebase::admob::AdSize adSize;
    adSize.ad_size_type = firebase::admob::kAdSizeStandard;
    adSize.width = getWidth();
    adSize.height = 50;


    StringRef googleTestBannerID = "ca-app-pub-3940256099942544/2934735716";
    bannerView->Initialize(static_cast<firebase::admob::AdParent>(getTopLevelComponent()->getWindowHandle()),
                           googleTestBannerID,
                           adSize);

    bannerView->InitializeLastResult().OnCompletion(MainContentComponent::initFutureCallback, bannerView.get());
}

void MainContentComponent::initFutureCallback(const firebase::Future<void> &resultData, void *userData)
{
    DBG( "MainContentComponent::initFutureCallback" );
    switch (resultData.status())
    {
        case firebase::FutureStatus::kFutureStatusComplete:
        {
            if( auto* bannerView = static_cast<firebase::admob::BannerView*>(userData) )
            {
                auto showFuture = bannerView->Show();
                showFuture.OnCompletion(MainContentComponent::showFutureCallback, bannerView);
            }
            break;
        }
        case firebase::FutureStatus::kFutureStatusPending:
        {
            DBG( "Init() still pending!" );
            jassertfalse;
            break;
        }
        case firebase::FutureStatus::kFutureStatusInvalid:
        {
            DBG( "invalid!" );
            jassertfalse;
            break;
        }
    }
}
void MainContentComponent::showFutureCallback(const firebase::Future<void> &resultData, void *userData)
{
    DBG( "MainContentComponent::showFutureCallback()" );
    switch (resultData.status())
    {
        case firebase::FutureStatus::kFutureStatusComplete:
        {
            if( auto* bannerView = static_cast<firebase::admob::BannerView*>(userData) )
            {
                firebase::admob::AdRequest request = {};
                request.gender = firebase::admob::kGenderUnknown;

                static const char* adKeywords[] = {"AdMob", "C++", "Fun"};
                request.keyword_count = sizeof(adKeywords) / sizeof(adKeywords[0]);
                request.keywords = adKeywords;

                static const char* testIds[] = {"kGADSimulatorID"};
                request.test_device_ids = testIds;
                request.test_device_id_count = sizeof(testIds) / sizeof(testIds[0]);;

                bannerView->LoadAd(request);
            }
            else
            {
                jassertfalse;
            }
            break;
        }
        case firebase::FutureStatus::kFutureStatusPending:
        {
            DBG( "Show() still pending" );
            jassertfalse;
            break;
        }
        case firebase::FutureStatus::kFutureStatusInvalid:
        {
            DBG( "invalid!" );
            jassertfalse;
            break;
        }
    }
}

MainContentComponent::~MainContentComponent()
{
    if( bannerView.get() )
    {
        bannerView->Destroy();
    }
}
4 Likes