No more than four days after publishing my article concerning the Dart package, ads, that utilized Google’s own plugin, firebase_admob, to add Ads to your Flutter app, I’ve began writing another article on somewhat the same subject. I didn’t like the Dart package you see. Now, why was that?
Well, because, as I explained at the end of my previous article, Add Ads to your App in a Snap!, there’s some things one must consider when supplying a program for ‘public consumption’ as it were. I hinted there were some things still outstanding that needed to be addressed. Well, four days on, they’ve been addressed. Again, this was concerns the Dart package, ads. I’ve made it better. That’s why.
For Public Consumption
I made it better to be used in production with unknown mobile apps. I had initially chosen it to be a Utility Class using much of the Singleton design pattern approach when developing this Dart package. In other words, the class was made up of a series of public static properties and public static functions that you can then access application-wide simply by using the class name as prefix, ‘Ads.’ By it’s very nature, there’s only one instance of it as it’s not meant to be instantiated. However, such a class is not without certain considerations. Ones that needed to be addressed with regards to the purpose of this particular class. It was to utilize a Google plugin involving Admob ads. Ads for a lone mobile app.
The Bigger Picture
In this article, it’s not so much about the Dart package itself. That was covered in the previous article, Ads to your App in a Snap! This article will explain why the turnaround from the Utility Class approach to the conventional class instantiation using the classical class constructor. I’ll explain the initial intent, and then I’ll explain why I feel the latest incarnation of the Dart package is more suitable to be used as a general-purpose utility program. One that provides, in this case, a Google plugin to display Admob ads in any sort of Flutter app you can dream of — big or small. By all appearances, it’ll look like any standard class, but there’s a twist. Read on and find out what.
No More Static!
As part of the rewrite, I did away with most of the static members of the class. As you see in the screenshot above, comparing the two Github branches, much of the original Dart package is preserved, but the keyword, static, was removed en masse. In this article, I’ll explain why, and what was, in my opinion, the better alternative for this particular Dart package.
Screenshots! Not Gists!
As always, I prefer using screenshots over gists to show code in my articles. I find them easier to work with, and easier to read. However, you can click/tap on them to see the code as a gist or in Github. Ironically, it’s better to read this article about mobile development on your computer than on your phone. Besides, we program mostly on our computers; not on our phones. For now.
Get Some Class
So I turned a utility class into a conventional class by literally changing the static init() function into a class constructor. You can see that below in the screenshot comparing the two branches of source code. Easy-peasy so far.
In recent years, there’s been much debate as to the benefits of the Singleton pattern. Just go to the overstackflow website and see for yourself. The primary consideration when using the Singleton pattern is resource demand and infrastructure accessibility. If the code in question places a heavy demand on resources (on memory for example) but its access can be regulated and or need only be accessed intermittently in the life of the app — a Singleton pattern may be the means to manage such a heavy and demanding bit of code. After all, with this pattern, only one instance of this bit of code is ever created.
And so, sure, if I wasn’t going to share this particular Ads library with anyone being somewhat a ‘heavy’ resource when it comes to the Google plugin, and if I was only going to be using it at the start of my app where I ‘d likely initialize it, set my event listeners, and display my ads — a Singleton pattern would be a ‘neat’ approach. After all, I’d have the added benefit of application-wide access to the ads with its global properties and global methods. For example, I could then easily implement event listeners or even close and open the ads whenever and where ever I wanted. If I was the only one using it, it would be relatively safe and easy to manage. However, I’m not the only one using it. Not any longer.
No Code is an Island
Like the poem describing an individual in society, so to is a piece of code ‘not an island’ if it’s to be used as a utility program for any and all who wants, in this case, to easily add ads to their app and set them with event listeners.
If I insisted on retaining the Singleton pattern, as the Dart package currently worked, anyone and everyone on your development team would be able to add in event listeners any time and any where they wanted to in your Flutter app. That wouldn’t be good. You’d want a bit of control as to who could do what with your ads. After all, the intent of all this to be make a bit of money on those ads. Who knows what those developers would be up to adding event listeners everywhere — without you knowing. In other words, a bunch of new code would have to be dedicated to merely ‘controlling’ who and how one would access your ads. It’d be a lot of work. Too much work. Let’s not do that.
Back To Basics
The short of it is, a quick and easy way to ‘manage’ who has access to your ads is to control access to the very class object that manages your ads. In this case, it’ll be one and only one class object that manages them. I’ll explain that last statement shortly. You can then manage the access to that one object. Get it?
However, at the start, when I was the only one using it, I had full access to the Ads class’ methods and it’s properties! I had access to everything through the use of getters. I had access to even the Admob app id and all the Admob unit id’s! Why? Why not! I thought I may want to use them somewhere else in my app. I didn’t know. I didn’t care. It was my own little Ads library, and I was using the Singleton approach: ‘The World was my Oyster!’
With the latest version, it’s been whittled down to five getters. As you see in the screenshot above looking that the column on the right, it’s now using the good ol’ class constructor. It’s no longer a list of static references. What else do you see? You see, if you want to execute a particular getter, you’re going to need to access a particular object. This approach allows for a easy means of control. You can control who has access to that particular object. Even if the Ads class is instantiated again elsewhere! More on that shortly.
For now, all you need to know is that no one needs to know your Admob app id, your unit id’s or even have access to the ads objects that are created within the Ads class. You only need to know you’re likely the first to use them to create the Ads object, and, as it turns out, that’s key to the changes made to this version of the Ads class.
Clear As Gravy.
So again, at one time when I alone was using the Ads class, I gleefully developed ‘clear’ functions that would clear a particular ‘type’ of event listeners with one fell swoop! However, releasing such a capability to the general public would not be a good idea. You’d be able to clear other people’s event listeners! Not good. With the plugin, you’re allowed to add event listeners to your ads. The Dart package gives you the means to do so, and is explained in more detail in the previous article, Add Ads to your App in a Snap! However, that means only you should then be allowed to remove them, and only them.
In the screenshot comparing the two branches, you see the Ads class dispose() function has changed a little bit, but with big consequences. Seven public functions have gone away. You now must have access to the Ads object to ‘dispose’ of it properly. If you want to clear the event listeners, they’ll have to be your event listeners in the first place.
Removed By Itself
So how do you remove an event handler object? By looking it up by its very object and removing it. That’s how. Note, it’s not too often the case you’d want to remove an event handler while running your app. In most cases, you’d “set it n’ forget it.” It’ll be cleared when the app closes down ( by the dispose() function). Regardless, if you need to, you have that option. Look closely at the screenshot below.
Above are all the functions available to remove a particular event handler. Notice the little event handler variables being created and then referenced as a parameter in the functions? This would be the way you’d create and then remove an event handler — if you wanted to.
Note, the ‘ads.screen’ and ‘ads.video’ has the same functions as the ‘ads.banner,’ and so I didn’t bother listing them there as well. I’m listing only the unique functions. All these functions return a boolean value. If the passed function object to be removed is found, it’s removed, and a boolean value of true is returned. If no event handler is found, false is returned. There’s no other complaint than that. The app will not crash if an event handler is not found. It just presses on — like a good utility program should. You should have access to your own event handlers, and so you should be able to successfully remove them. In any event, it’s in this fashion, where you've access only to your event handlers and not to those owned by others. A little built-in resilience there.
So you see in the example code an Ads class object is now instantiated. The idea is it’s to you now to dictate how and who has access to that object. You can work it into an InheritedWidget for example. You could defined the ‘ads’ variable as a static variable bringing you back to square one…if you like. Whatever you dream up, it’s on you. The object itself is self-contained.
Set It ‘n Forget It
Well, there you go. You now have a Dart package that displays ads for you. Let me suggest that you instantiate the Ads class and thus initialize the plugin at the start of your app somewhere. Supply the id’s, specify the appropriate options, define your event listeners, and you’re on your way. When the app closes down, you would have the dispose() function in the appropriate State object’s own dispose() function to perform the clean up. There’s three examples below where you’re passing in the unit id for a banner ad. The first two requires the ‘show’ function to be called later. While the last example defines and then shows the banner ad all in one function call. Nice.
Note how it’s all done in one place. You can regulate who of your developers will have access to that stretch of code. Alternatively, your compatriots need not have access to that stretch of code, and so not have access to those id’s (appId, bannerId, etc.). Again, you can regulate access by controlling who would have access to the object, ads.
Consider Some Assumptions
It’s at this point, where you should consider some assumptions made when using the plugin, firebase_admob:
- One plugin per app.
- At the most, one unit id per ‘type’ of ad (Banner, Interstitial and Video)
The plugin doesn’t allow for more than one ‘app id’ to be used in an app. At least, that’s the impression I’m getting from the documentation. You can’t have your ads running in one part of the app, and a buddy of yours running his ads in another part. They all have to be under one ‘app id.’ That’s a good thing as far as controlling the Ads class is concerned. It allowed me to implement a means to address the fact one could simply instantiate another Ads class object.
How About Another?
I mean, what’s stopping anyone from simply creating another instance of the Ads class? Nothing stopping them. As a utility program, it shouldn’t stop them. Such programs should ‘go with the flow’ with the every-day operations of a mobile app. Any mobile app — whatever it’s doing! And so, a mobile app might create a second Ads object. Again, by its very definition, a conventional class constructor will allow you to do that. It could create any number of Ads objects. So let’s see what happens when we create another Ads object.
There Must Only Be One!
While in development, let’s say you decide to go into your favourite IDE and type up the stretch of code you see above. You’re going to instantiate not one, but two Ads objects. One after the other. You then run it in ‘debug mode.’ Look what happens below. You’re presented with the ‘read screen of death!’
As you see in the constructor, there’s an assert statement that tests if the Ads class has already been instantiated. You can see the very assert statement highlighted with the little red arrow above. It was triggered when the second Ads constructor is also called.
An Init Flag
Dozen of static keywords were removed in this version of the Ads class. However, one static variable (one class property) was put in. It’s the boolean variable, _initialized. Remember the first assumption: ‘One plugin per app.’ Well, this is the means to enforce that assumption when using this Dart package. This property variable, and another boolean instance variable, _firstObject, will give you control over the Google plugin we’re currently using for our ads. They ensure the plugin is only initialized once as it was designed. You can see both of these variables defined in the screenshot below. One initially set to true; the other initially set to false. One an instance variable; the other a static variable — visible to all instances of that class.
Highlighted below with little red arrows is the logic that runs when an Ads class is instantiated into an object. The code is designed to run in production even if a null value is passed to the ‘app id’ for some reason, and to run in production even if the Ads class is instantiated dozen of times.
Such cases is not going to ‘blow up’ the app. Instead, the Ads class is just not going to display ads. Or, if it does displays ads, they’ll be test ads. Either way, it’s only in this fashion that the developer will be alerted to a possible problem — and not by an angry user with an app that is crashing. Displaying ads is nice and all, but don’t interfere with the main function of the mobile app. Whatever that may be.
The first red arrow shows you what happens if the passed appId value is null or an empty string. It doesn’t blow up. It doesn’t notify the developer (not directly anyway). It instead uses the ‘test app id’ provided by the plugin.
The second red arrow highlights the fact that the instance variable, _firstObject, is set to false if the class variable, _initialized, has already been set to true. The consequence being the object is still instantiated. It just doesn’t do anything. You’ll see this later.
Notice the remaining stretch of code. If it’s not ‘initialized’ (i.e. _initialized is set to false), that class (static) variable is immediately set to true, and then an attempt is made to initialize the plugin. Finally, there’s the then function to determine the boolean result of the asynchronous operation involved when initializing the plugin. That result is assigned to the class variable, _initialized. See how this works?
The App Must Go On!
The idea is that no matter what ‘garbage’ may be passed to the constructor, the Ads class should instantiate successfully. You can see below in the plugin code itself, the appId is required and if the parameter, analyticsEnabled, is not passed, it’s set to false. Looking at the last few arrows above then, you can see the Dart package ensures an appId is supplied (even if it’s a ‘test’ id) and a boolean value is passed to the parameter, analyticsEnabled, with the help of the ?? operator. The Ads object is instantiated. If it works is another matter.
The First Instance Wins
Now, how does one make a class object not do anything? Well, in this case, you test if it’s not the first one. That’s how. Let’s look at the showBannerAd() function. There’s two new lines in it compared to the last version of this class. They’re highlighted with arrows below. You’ll recognize the variable involved.
You can create your second Ads object, but if you call it’s showBannerAd() function, for example, you’re in for a bit of a disappointment. If you’re doing this in your IDE in ‘debug mode’, you’ll get the ‘red screen of death.’ If you’re running it in production with the second Ads object instantiated in some part of the app not under your control for example, it will simply not work. Thanks to the line,
if (!_firstObject) return;
You’ll find that every public function in this Ads class now has that line to ‘disable’ Ads objects which has been instantiated when frankly they shouldn’t have. By design, there can only be one. The first one. And by design, yours should be the first one. It’s your app after all. See how this works now? And if it’s not the first one, you’re going to know it! Yours won’t work! Or it’ll have test ads.
Screenshots of three public functions reveals each has an assert and if statement now at the start of their code. That’s true of all the public functions used in this class. If it’s not the first one, it’s a dull one. It’s not going to do much. The first Ads object is to deal with the ads in you app. No other. The Ads class itself makes sure if that.
A Single Solution
Now if you indeed like and want the Singleton approach that’s easily available to you. Just make one. With OOP languages like Dart, you can compose a class that utilizes this Dart package in just that fashion. You then have reference and have access to that single instance throughout your app.
Here you go. I’ve whipped up an example of this approach. You can fill in the rest of the functionality to the degree you need. I’ve only provided the ‘showBanner’ capability, for example, but you can do the rest. You’ve access to all its event handling however. Isn’t programming wonderful?
As you see above, you’ve now a self-contained means to access the Ads plugin any time and any where in your app. Further, event handlers can be added and removed any time and any where in your app while your valuable id’s are not exposed to wandering eyes.
Look at the init() function. See the ??= operator? It assigns only if the variable is null, and so it allows for only the ‘first’ call to init() function to instantiate this class once. If some overzealous developer calls the init() function again and again, there’s no harm done. Below, is a stretch of sample code now calling the static functions found in that utility class, AppAds.
Know There’s Unknowns
Take the time to examine the code. Look at the overkill here and there. Have you ever seen so many if statements checking for null in your life? Notice where the ?? operator is used. This is all because parameter values are coming from the outside world, and as this Dart package is to be used in any app, I will have no idea what’s out there. All I know is the Dart package is to display your ads. If it can’t display your ads, it’ll display test ads. If it can’t display test ads, it’ll do nothing at all. It’s to you to then figure out why. At least, it won’t crash your app, and that’s the goal. If it must fail, fail gracefully and quietly.
Highlighted by red arrows, you can see, as an example of coding defensively, how the values passed into the constructor as parameters are tested for null or empty strings. Further, the Strings passed as parameters are trimmed of any trailing or leading spaces. All this to provide valid values to the constructor if not provided by the parameters themselves — so the class would instantiate.
To Error Or Not
Right now, when it comes to the event handlers introduced to the plugin, the error handling is on you. Since it’s the developer’s code in the event handlers, the idea is that the Dart package itself will leave it to the developer to ensure that code will handle any exceptions. It’s thought that placing some error handling to allow the remaining event listeners to fire, for example, is too much ‘defensive’ code. Let the app blow up instead! It’s obvious there’s an issue with the developers code, and so they need to know as soon as possible with a little red screen.
Conceivably, however, a little change to the Dart package, and try..catch structures could be implemented (see below) to certainly record any exceptions that may occur, and allow the overall operation of handling events to continue. Again, who knows what’s going on out there in the outside world. In certain circumstances, maybe it would be best to handle any exceptions and possibly set an ‘error’ flag to notify the app, but to nevertheless continue and fire the next event handler in line. In any event, don’t let the app crash! Let me know what you think in the comments below.
To Error! Not!
Catch an Ad Error
And so, I’ve chosen the Ads Dart package to take the less intrusive route. If the code in your event handler crashes, it won’t crash the app…unless you explicitly want it to. For example, a developer could use an assert statement with the property, inError, to catch any errors while developing. If wished, any and all errors involving the event handlers could be addressed. See below at the screenshot depicting some example code. The exceptions and the type of event are recorded in the List object, eventErrors.
In The End
As a writer of such utility programs, you can’t anticipate the possible reasons for null values passed in as parameters for example. All you could do is test for null parameters and adapt to such instances. While developing such programs, you’re constantly asking yourself, ‘what if this happens?’ and ‘what if that happens?’ and write your code accordingly. However, there’s a balance you must achieve. Too much ‘defensive’ code is just as bad as too little.
Again, this Dart package is to display ads. It’s hoped, you’ll use it to do just that in your own app. I won’t know what sort of app you have. I won’t know how complex, how simple, how big or how small. I won’t know, and I won’t care. ‘The World’s your Oyster!’ All I know is it’s up to my Dart package to let you run your app — with ads.
#Source code as of July 04, 2019
*Source code as of June 27, 2019
^Source code as of May 30, 2019