When building mobile apps, you are often required to implement analytics and, in some cases, to support multiple analytics providers. Analytics tracking alone can easily pollute your logic code but when you need to add that multi-provider support, things quickly get out of hand.
Taking a quick look at an example, you can see how cluttered an activity can become, even without having to handle event payloads.
class MainActivity : AppCompatActivity() {
...
private fun onFeedbackGiven() {
Toast.makeText(this, "Thank you for your feedback!", Toast.LENGTH_LONG).show()
// Report to Fabric
Answers.getInstance().logCustom(
CustomEvent("feedback_given")
)
// Report to Firebase
FirebaseAnalytics.getInstance(this).logEvent("feedback_given", null)
}
}
With the example above, we have a very tightly couple solution. Should we need to add or remove a provider, we would have to go through each activity, fragment, etc., in order to make our changes.
Wouldn't it be nice to report those events in an unified, provider-agnostic one-liner way? Let's consider a hub-like approach for this scenario.
Like so, we could replace the code above with the following.
class MainActivity : AppCompatActivity() {
...
private fun onFeedbackGiven() {
Toast.makeText(this, "Thank you for your feedback!", Toast.LENGTH_LONG).show()
// Report to all providers
analyticsHub.trackEvent(FeedbackGivenEvent())
}
}
Let's start by setting up our AnalyticsHub
. This object will be responsible for dispatching the events to each analytics provider. In short, it will contain a collection of providers, and forward the events to each one of those.
class AnalyticsHub(
private vararg var providers: Provider
) {
fun trackContentView(name: String) {
providers.forEach { it.trackContentView(name) }
}
fun trackEvent(event: Event) {
providers.forEach { it.trackEvent(event) }
}
}
interface Provider {
fun trackContentView(name: String)
fun trackEvent(event: Event)
}
interface Event {
val eventName: String
}
Creating the events
We should create a specific class, which implements the Event
protocol, for each event we want to support. For this example, we'll stick to the feedback example but the same principle applies to pretty much any kind of event — login, purchasing, so on and so forth.
class FeedbackGivenEvent : Event {
override val eventName = "feedback_given"
}
Creating a provider
Starting with the Fabric implementation, we simply need to create a class that conforms to our Provider
protocol and add the Fabric-specific code to track the events.
class AnswersProvider : Provider {
private val answers = Answers.getInstance()
override fun trackContentView(name: String) {
answers.logContentView(
ContentViewEvent()
.putContentName(name)
)
}
override fun trackEvent(event: Event) {
answers.logCustom(
CustomEvent(event.eventName)
)
}
}
Wrapping things up
Lastly, we need to instantiate the AnalyticsHub
with our desired providers and we're done. We could have it managed by Dagger for instance, but for simplicity's sake let's create it in our Application
.
class PlaygroundApp : Application() {
lateinit var analyticsHub: AnalyticsHub
private set
override fun onCreate() {
super.onCreate()
analyticsHub = AnalyticsHub(
AnswersProvider()
)
}
}
We can now call our AnalyticsHub
like we wanted. Simple and with minimal impact on business logic.
If we were to add another provider to the mix, say Firebase, we'd only need to create another class conforming to Provider
and modify the AnalyticsHub
initialization like so.
class FirebaseProvider(
context: Context
) : Provider {
private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
override fun trackContentView(name: String) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.VIEW_ITEM, Bundle().apply {
putString(FirebaseAnalytics.Param.VALUE, name)
})
}
override fun trackEvent(event: Event) {
firebaseAnalytics.logEvent(event.eventName, null)
}
}
...
analyticsHub = AnalyticsHub(
AnswersProvider(),
FirebaseProvider(this)
)
Bonus provider
Notificare goes far beyond marketing messages. You can also leverage our platform to track events, gather all the insights you need in beautiful charts or reports and even run automation workflows based on such events. This is what we call Actionable Analytics, and with it you can easily create automated messages or categorize your users in response to these events.
class NotificareProvider : Provider {
override fun trackContentView(name: String) {
Notificare.shared().eventLogger.logCustomEvent(
"content_view",
mapOf(
Pair("view", name)
)
)
}
override fun trackEvent(event: Event) {
Notificare.shared().eventLogger.logCustomEvent(event.eventName)
}
}
That's it. Most of of the work is done. In a real-world app you'd need to create all the events you want to track and hook the hub across your app.