Implementing Custom Advertisements in Cascades

by Developer on ‎03-21-2014 11:54 AM (842 Views)

Custom Adverts.png

 

Advertising services are great but sometimes you just want to show off your own applications on custom advertisement banners within your application(s). 

 

In this Knowledge Base article we will be using our main.qml file, a sheet (MyAds.qml) and a few C++ files - but do not worry if you don't understand C++ as I will guide you through the process! 

 

First, we will start with a skeleton structure using your Custom Ads, a Webview and a Progress Indicator. It is important to keep in mind that different layouts will need to be used so that the ads are positioned correctly at the top of the screen. 

 

import bb.cascades 1.0

TabbedPane {
    id: tabbedPane
    Tab {
        title: qsTr("Home") + Retranslate.onLocaleOrLanguageChanged
        imageSource: "IMG/101.Home.png"
        NavigationPane {
            id: navigationPane0
            Page {
                
                titleBar: TitleBar {
                    title: "BlackBerry Developer"
                }

                Container {
                    id: root
                    Container {
                        id: myAds
                        horizontalAlignment: HorizontalAlignment.Center
                        layout: StackLayout {

                        }
                        MyAds {
                            horizontalAlignment: HorizontalAlignment.Center
                            topPadding: 15.0
                        }
                    }
                    Container {

                        layout: DockLayout {

                        }
                        // To enable scrolling in the WebView, it is put inside a ScrollView.
                        ScrollView {
                            id: scrollView

                            // We let the scroll view scroll in both x and y and enable zooming,
                            // max and min content zoom property is set in the WebViews onMinContentScaleChanged
                            // and onMaxContentScaleChanged signal handlers.
                            scrollViewProperties {
                                scrollMode: ScrollMode.Vertical
                                pinchToZoomEnabled: true
                            }

                            WebView {
                                onLoadProgressChanged: {
                                    // Update the ProgressBar while loading.
                                    progressIndicator.value = loadProgress / 100.0
                                }
                                horizontalAlignment: HorizontalAlignment.Fill
                                verticalAlignment: VerticalAlignment.Fill
                                // The url that is loaded points to the QML of this recipe on GitHub.
                                url: "http://developer.blackberry.com"
                                id: eBayUK

                                // WebView settings, initial scaling and width used by the WebView when displaying its content.
                                settings.viewport: {
                                    "width": "device-width",
                                    "initial-scale": 1.0
                                }
                                onMinContentScaleChanged: {
                                    // Update the scroll view properties to match the content scale
                                    // given by the WebView.
                                    scrollView.scrollViewProperties.minContentScale = minContentScale;

                                    // Let's show the entire page to start with.
                                    scrollView.zoomToPoint(0, 0, minContentScale, ScrollAnimation.None)
                                }

                                onMaxContentScaleChanged: {
                                    // Update the scroll view properties to match the content scale
                                    // given by the WebView.
                                    scrollView.scrollViewProperties.maxContentScale = maxContentScale;
                                }

                                onLoadingChanged: {

                                    if (loadRequest.status == WebLoadStatus.Started) {
                                        // Show the ProgressBar when loading started.
                                        progressIndicator.opacity = 1.0
                                    } else if (loadRequest.status == WebLoadStatus.Succeeded) {
                                        // Hide the ProgressBar when loading is complete.
                                        progressIndicator.opacity = 0.0
                                    } else if (loadRequest.status == WebLoadStatus.Failed) {
                                        // If loading failed, fallback a local html file which will also send a java script message
                                        url = "asset:///WebViewFallback.html"

                                        progressIndicator.opacity = 0.0
                                    }
                                }

                                // This is the Navigation-requested signal handler so just print to console to illustrate usage.
                                onNavigationRequested: {
                                    console.debug("NavigationRequested: " + request.url + " navigationType=" + request.navigationType)
                                }

                                onMessageReceived: {
                                    // If not connected to a network the java script in the fallback page
                                    // WebViewFallback.html will send a message to this signal handler
                                    // illustrating communication between a java script and Cascades.
                                    console.debug("message.origin: " + message.origin);
                                    console.debug("message.data: " + message.data);
                                }
                                settings.credentialAutoFillEnabled: true
                                settings.formAutoFillEnabled: true
                            }

                        } // ScrollView - A progress indicator that is used to show the loading status
                        Container {
                            bottomPadding: 25
                            horizontalAlignment: HorizontalAlignment.Center
                            verticalAlignment: VerticalAlignment.Bottom

                            ProgressIndicator {
                                id: progressIndicator
                                opacity: 0.0
                            }
                        }
                    }
                } // End of container
            }
        }
    } //End of first tab
} // End of tabbedPane

We are using a stack layout for the Custom Ads, so that is placed above the other elements. We then use a dock layout for the Webview and Progress Indicator to slot them underneath the Custom AdsYou will also notice that each element has its own container and then the layout is determined within that container; having a container for each element is vital so that the layout gets set correctly. If you were to use the same layout in one container for all three elements, then you would end up with a black line appearing at the bottom of your screen where the Progress Indicator would appear - so make sure you have all three elements in their own containers. 

 

Now that we have our skeleton layout, we need to make the ads work. For the Custom Ads to work, we are using a Sheet:

 

Container {
                        id: myAds
                        horizontalAlignment: HorizontalAlignment.Center
                        layout: StackLayout {

                        }
                        MyAds {
                            horizontalAlignment: HorizontalAlignment.Center
                            topPadding: 15.0
                        }
                    }

 

You will need to create a new qml document within your assets folder, and name it MyAds.qml

 

Simply use the code below and add it to your MyAds.qml document:

 

 

// Default empty project template
import bb.cascades 1.0
import CustomTimer 1.0

// creates one page with a label
Container {
    Container {
        layout: DockLayout {
        }
        Timer {
            id: adTimer
            
            // Specify a timeout interval of 10 seconds
            interval: 10000
            
            onTimeout: {
                if (adOne.visible) {
                    adOne.visible = false;
                    adTwo.visible = true;
                } else if (adTwo.visible) {
                    adTwo.visible = false;
                    adThree.visible = true;
                } else if (adThree.visible) {
                    adThree.visible = false;
                    adFour.visible = true;
                } else if (adFour.visible) {
                    adFour.visible = false;
                    adFive.visible = true;
                } else if (adFive.visible) {
                    adFive.visible = false;
                    adSix.visible = true;
                } else if (adSix.visible) {
                    adSix.visible = false;
                    adSeven.visible = true;
                }
                else if (adSeven.visible) {
                    adSeven.visible = false;
                    adEight.visible = true;
                }
                else if (adEight.visible) {
                    adEight.visible = false;
                    adOne.visible = true;
                }
                restartTimer.start();
                adTimer.stop();
            }
        }
        
        Timer {
            id: restartTimer
            interval: 0
            onTimeout: {
                adTimer.start()
                restartTimer.stop()
            }
        }
        Container {
            ImageView {
                id: adOne
                imageSource: "asset:///IMG/placeholder_728x90.png"
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invokeBBMChannel.trigger("bb.action.OPENBBMCHANNEL")
                        }
                    }
                ]
                horizontalAlignment: HorizontalAlignment.Center
                attachedObjects: [
                    Invocation {
                        id: invokeBBMChannel
                        query {
                            invokeTargetId: "sys.bbm.channels.card.previewer"
                            invokeActionId: "bb.action.OPENBBMCHANNEL"
                            uri: "bbmc:C00120C46"
                        }
                    }
                ]

            }
            ImageView {
                id: adTwo
                imageSource: "asset:///IMG/WhatTo-Do.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke2.trigger("bb.action.OPEN");
                        }
                    }
                ]
                attachedObjects: [
                    Invocation {
                        id: invoke2
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/42064925"
                        }
                    }
                ]

            }
            ImageView {
                id: adThree
                imageSource: "asset:///IMG/Berryflow.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke3.trigger("bb.action.OPEN")
                        }
                    }
                ]
                horizontalAlignment: HorizontalAlignment.Center
                attachedObjects: [
                    Invocation {
                        id: invoke3
                        query {
                            mimeType: "plain/html"
                            uri: "http://www.berryflow.com"
                        }
                    }
                ]

            }
            ImageView {
                id: adFour
                imageSource: "asset:///IMG/WDCS.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke4.trigger("bb.action.OPEN")
                        }
                    }
                ]
                horizontalAlignment: HorizontalAlignment.Center
                attachedObjects: [
                    Invocation {
                        id: invoke4
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/21797691"
                        }
                    }
                ]

            }
            ImageView {
                id: adFive
                imageSource: "asset:///IMG/Whine.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke5.trigger("bb.action.OPEN");
                        }
                    }
                ]
                attachedObjects: [
                    Invocation {
                        id: invoke5
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/36249891"
                        }
                    }
                ]
            
            }
            ImageView {
                id: adSix
                imageSource: "asset:///IMG/VisualConnectionAd.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke6.trigger("bb.action.OPEN");
                        }
                    }
                ]
                attachedObjects: [
                    Invocation {
                        id: invoke6
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/25226872"
                        }
                    }
                ]

            }
            ImageView {
                id: adSeven
                imageSource: "asset:///IMG/RandomStoriesAd.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke7.trigger("bb.action.OPEN");
                        }
                    }
                ]
                attachedObjects: [
                    Invocation {
                        id: invoke7
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/21798104"
                        }
                    }
                ]

            }
            ImageView {
                id: adEight
                imageSource: "asset:///IMG/LogicPuzzlesAd.png"
                visible: false
                gestureHandlers: [
                    TapHandler {
                        onTapped: {
                            invoke.trigger("bb.action.OPEN");
                        }
                    }
                ]
                attachedObjects: [
                    Invocation {
                        id: invoke8
                        query {
                            mimeType: "application/x-bb-appworld"
                            uri: "appworld://content/22029056"
                        }
                    }
                ]

            }
        }

    }
    onCreationCompleted: {
        adTimer.start();
    }
}

 

If you wish to change the time in which the ads are changed, then you can edit 

 

interval: 10000

 

the number, in milliseconds, to a specific number.

 

Furthermore, if you would like to add or remove ads, you simply add or remove ImageView - and their attached objects - and then edit the onTimeout:

 

onTimeout: {
                if (adOne.visible) {
                    adOne.visible = false;
                    adTwo.visible = true;
                } else if (adTwo.visible) {
                    adTwo.visible = false;
                    adThree.visible = true;
                } else if (adThree.visible) {
                    adThree.visible = false;
                    adFour.visible = true;
                } else if (adFour.visible) {
                    adFour.visible = false;
                    adFive.visible = true;
                } else if (adFive.visible) {
                    adFive.visible = false;
                    adSix.visible = true;
                } else if (adSix.visible) {
                    adSix.visible = false;
                    adSeven.visible = true;
                } else if (adSeven.visible) {
                    adSeven.visible = false;
                    adEight.visible = true;
                }
                else if (adEight.visible) {
                    adEight.visible = false;
                    adOne.visible = true;
                }
                restartTimer.start();
                adTimer.stop();
            }

 

To add one more ad, all you would need to do is add another ImageView and attached objects and then edit the onTimeOut to:

 

onTimeout: {
                if (adOne.visible) {
                    adOne.visible = false;
                    adTwo.visible = true;
                } else if (adTwo.visible) {
                    adTwo.visible = false;
                    adThree.visible = true;
                } else if (adThree.visible) {
                    adThree.visible = false;
                    adFour.visible = true;
                } else if (adFour.visible) {
                    adFour.visible = false;
                    adFive.visible = true;
                } else if (adFive.visible) {
                    adFive.visible = false;
                    adSix.visible = true;
                } else if (adSix.visible) {
                    adSix.visible = false;
                    adSeven.visible = true;
                } else if (adSeven.visible) {
                    adSeven.visible = false;
                    adEight.visible = true;
                }
                else if (adEight.visible) {
                    adEight.visible = false;
                    adNine.visible = true;
                }
                else if (adNine.visible) {
                    adNine.visible = false;
                    adOne.visible = true;
                }
                restartTimer.start();
                adTimer.stop();
            }

 

That's it for the QML side of the Custom Ads. We will now need to use C++ for the timer to operate and for the ads to appear. 

 

First, go into your SRC folder and open applicationui.cpp and add the following code to the very top:

 

#include "timer.hpp"

Also, in the same document, you will need to register the timer to be used in QML. To do that, simply place the below code above where your ("asset:///main.qml") is created:

 

qmlRegisterType<Timer>("CustomTimer", 1, 0, "Timer");

You can now close that document and create another and name it Timer.cpp. Simply add the below code into your document:

 

#include <QTimer>
#include "timer.hpp"

Timer::Timer(QObject* parent)
     : bb::cascades::CustomControl(),
     _timer(new QTimer(this))
{
    Q_UNUSED(parent);
    connect(_timer, SIGNAL(timeout()), this, SIGNAL(timeout()));
    setVisible(false);
}

bool Timer::isActive()
{
    return _timer->isActive();
}

int Timer::interval()
{
    return _timer->interval();
}

void Timer::setInterval(int m_sec)
{
    // If the timer already has the specified interval, do nothing
    if (_timer->interval() == m_sec)
        return;

    // Otherwise, set the interval of the timer and emit the
    // intervalChanged() signal
    _timer->setInterval(m_sec);
    emit intervalChanged();
}

void Timer::start()
{
    // If the timer has already been started, do nothing
    if (_timer->isActive())
        return;

    // Otherwise, start the timer and emit the activeChanged()
    // signal
    _timer->start();
    emit activeChanged();
}

void Timer::stop()
{
    // If the timer has already been stopped, do nothing
    if (!_timer->isActive())
        return;

    // Otherwise, stop the timer and emit the activeChanged()
    // signal
    _timer->stop();
    emit activeChanged();
}

 You can now save and close that document and create your last document and name it Timer.hpp

 

Simply use the below code and add it to that document:

 

#include <QObject>
#include <bb/cascades/CustomControl>
class QTimer;

class Timer : public bb::cascades::CustomControl
{
    Q_OBJECT

    Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
    Q_PROPERTY(int interval READ interval WRITE setInterval
               NOTIFY intervalChanged)

public:
    explicit Timer(QObject* parent = 0);

    bool isActive();
    void setInterval(int m_sec);
    int interval();

public slots:
    void start();
    void stop();

    signals:
        void timeout();
        void intervalChanged();
        void activeChanged();

private:
    QTimer* _timer;
};

 That's everything done for the C++! 

  

For the ads to function correctly, you will need to alter the images to your own images (size of 500x150px) and then you will need to change the links too. Once you have done that, you are finished and the ads will appear within your application!