SPEAKER: Hey there, app developers.
So this episode of "A/B Test Like a Pro"
is completely optional.
I know I've been showing you the sample app that
makes use of Remote Config.
And some you want me to go into more of the details
around how I got this working.
And so while I don't really want to derail the series with kind
of detailed explanations of how to implement Remote
Config because we've already got docs and blog posts
and videos all about that, I thought for those of you who
are curious about how I got Remote Config working
on my app, I'd walk you through the code.
So ready?
Let's start.
[MUSIC PLAYING]
Now I do want to preface this by saying,
this is one way you can get your app up
and running with Remote Config.
It's not the only way, and it's not necessarily the best way.
So if you think you've got a better system set up
within your app, keep using it.
And maybe tell me about it in the comments below.
All right, let's take a look at my code.
So let's start off by taking a look at my RC values
object, which is what I use for accessing all of my Remote
Config values and abstracting away some of the implementation
details.
Now it's a singleton because I'm as
guilty as overusing singletons as the next engineer.
But it does make life awfully easy for me.
So the first thing I want to point out
is that I'm storing all of my Remote Config keys
here as a swift enum with the backing type as a string.
Now this is nice in that if I ask
for the raw value of an enum, it will
be a string that's equal to this value
here unless I specify otherwise.
So the raw value of sloganText is actually
a string called sloganText.
And it turns out that if I do need to override one of these,
like maybe because the Android team already
shipped their version of the app and they're
using a different term, I can do that easily like this.
So when my singleton object is first initialized,
which as you can see, I am doing here in my AppDelegate,
I do two things.
First, I specify default values, and then I fetch new values
from the cloud.
So first, let's take a look at how I'm specifying my defaults.
The two things I want to point out here
are that I'm grabbing the raw value from my enum
as the key, which as you recall, is
a string that usually has the same name as the enum itself.
And then here, you can see that I'm using my NSLocalizedString
to set my default values for my strings
so that at runtime, I can make sure my default values are
still appropriately localized, even though I'm
going through Remote Config.
Now fetching values from the cloud
should look pretty familiar.
I'm making a call and then calling activateFetched here
in the completion Handler.
Although this bit here might be new,
notice that I'm setting fetchComplete to true,
and calling my loadingDoneCallback
if it exists.
And that's because I'm using a loading screen.
Now if you haven't watched our video called Remote Config
Loading Strategies, I do recommend taking a look at it.
I go over three different strategies
for how to load and apply Remote Config values.
And one solution I recommend is creating a loading screen
that you can put up while you're waiting for your Remote Config
values to finish loading.
And that's what I'm doing here.
So over here in my waiting screen view controller,
I'm basically setting our loadingDoneCallback
to this readyToGo method that segueways to the next view
controller.
I'm also calling it right away if fetchComplete is true,
just on the off chance that Remote Config somehow completed
its fetch before this view is loaded.
I don't know if that's possible, but you know, better
safe than sorry.
And so you'll notice this is why,
even if I get an error fetching Remote Config,
I don't want to completely bail out early from this function.
I still want to set fetchComplete as true
and call my loadingDoneCallback so that if I'm offline
or my app is throttled or something,
I'm not stuck forever on the loading screen.
Now once we get into my main view controller,
you can see I have this method, applyConfigValues,
where I'm setting a bunch of values for my app
from what's in Remote Config.
And this is because I need to set all this stuff
through code, and I can't necessarily
rely on what I've set in the storyboard.
Now you can see that instead of accessing the Remote Config
Service directly, I'm making calls like this
config.string(forKey) method.
Let's take a closer look at some of these methods.
I think most of them are pretty straightforward.
What I'm doing here is simply taking my values
from Remote Config and calling bool value, stream value,
number value, whatever on them.
If I do end up with a nil value, I provide a simple default.
That way I don't have to deal with these things
as optionals in the rest of my code.
You'll notice that color for key returns
a UI color based on the string value
that I retrieved from Remote Config.
Now this is not currently a native UI color method.
I'm using the UI color hex swift library,
which adds it onto the UI color class as an extension.
Now the one place I am getting a little tricky
is here in the Populate Image View for Key Method.
Basically I wanted to find an easy way to change images
through Remote Config, and I decided to do that
through JSON object--
or I guess more accurately, a string
that looks like a JSON object, something like this.
Now the source here is either local or remote.
If it's local, there will be a name field
that's the name of the local file to use.
And if it's remote, there will be a URL field for the images
URL that I want to load.
And so in my code, the first thing you can see I'm doing
is loading up a default image just in case my JSON is broken
or something.
Next, I try to grab my string from Remote Config
and parse it as JSON object.
I then look to see if the source value is
equal to the string remote.
If it is, then I look for a URL and try and load that
into my image.
Now if that fails for any reason or I forget
to include a URL parameter, I can go back
to using my default image.
Otherwise, I try to grab the value of the name field
for my JSON, and then I'll simply load the image locally
based on that name.
Note that I'm using both the Swifty JSON library
to parse my JSON, and the SDwebImage library
to take care of all the hey, load this image from the web
work for me.
One note about the Swifty JSON library
is that it doesn't really rely on optionals.
So if my JSON is broken or it doesn't include a source value,
it will give me an empty string instead of nil.
And that's why you don't see me doing
a whole bunch of guardlets in most of my JSON interpreting
code here.
If my JSON doesn't have a field called source,
this local or remote value will just be an empty string.
As for this default image, one option
could be to just simply hard code
this to some placeholder UI image.
But what I decide to do instead is take a look
at what I specified within my Remote Config defaults, which
makes sense, right?
That seems like a pretty reasonable backup image
to use if my Remote Config value is incorrect.
And so that's what I'm doing here.
I'm calling this Default Value for Key
to ask Remote Config for the default value
instead of what's been loaded from the cloud.
Note that by the time you see this video,
you might not need to make this call
with the namespace argument, but I had to.
Then basically, all I'm going to do here
is grab the contents of my JSON's name field
and try to get a local UI image from that value.
Now I am making two assumptions here.
One is that it will have a valid JSON object representing
images for my default options in Remote Config.
And two is that they'll all be local.
But at least for my app, I think those are both safe assumptions
to make.
And in fact, that's why I'm throwing an assertion
error here, because I do want to make sure
I have good default options to fall back on,
and I want to catch that in development.
But of course, feel free to change this logic if it's not
appropriate for your app.
And then well, that's basically it.
I grabbed these values from my RC values singleton
as I need them, using these methods that either return
non-optional values of the right type,
or this populateImageView method that
loads the appropriate image right into the correct view.
I used the same approach when animating my views
and just as a fun side note here,
I'm animating my slide-in panel by changing
the constraint constant here, which
is a neat way of being able to animate my views
while still using constraints within my app.
This really has nothing to do with Remote Config.
I just thought it was kind of cool.
And there you go.
So that's the app I have set up in iOS.
If you do want any more information
about any of this stuff, head on over to the Remote Config
section of our documentation.
And be sure to check out the samples and all the guides
and all the videos we've got waiting for you there.
And yes, we even have stuff there for you Android folks.
So in the meantime, if you enjoyed this video,
please feel free to subscribe to the Firebase YouTube channel,
and I will see you soon on another exciting episode
of "A/B Test Like a Pro."
Thanks for watching.
[MUSIC PLAYING]