Modernising the mobile trackers: version 5 is here

We’re very excited to announce the version 5 of our mobile trackers for Android and iOS. The major enhancement is the modernization of the trackers – we migrated the iOS tracker code base from Objective-C to Swift, and Android from Java to Kotlin. The trackers got a couple of brand new features too!
Act on events with tracker plugins
The new tracker plugins architecture, based around the PluginConfiguration
class, allows you to intercept events and run callbacks.
- The
entity
closure allows you to attach an entity just before an event is tracked. You can choose to add the entity to all events, or just events of a certain type. - The
afterTrack
closure lets you inspect tracked events and act based on their properties and entities. It’s called when the event is handed over to theEventStore
for buffering and processing into a request. So, once the event has been tracked, but before it’s been sent.
Here’s how it works on Android (it’s very similar on iOS):
// Create a new PluginConfiguration with a unique identifier
val plugin = PluginConfiguration(“myPlugin”)
// Use the entities closure to attach entities to events
// This plugin will add an entity based on the “iglu:xx” schema
// to events based on the “iglu:abc” schema only
plugin.entities(schemas = listOf(“iglu:abc”)) {
listOf(SelfDescribingJson(“iglu:xx”, hashMapOf(“property” to true)))
}
// The afterTrack callback is called on a background thread to inspect tracked events
// Here, a message is printed for every event tracked based on the “iglu:yy” schema
plugin.afterTrack(schemas = listOf(“iglu:yy”)) {
print(“Tracked event with ${it.entities.size} entities”)
}
// The plugin can be supplied to the tracker as a configuration on creation
val tracker = Snowplow.createTracker(
context = context,
namespace = “namespace”,
network = networkConfig,
plugin
// multiple PluginConfiguration can be provided!
)
// Alternatively, add plugins like this
tracker.plugins.addPlugin(plugin)
// You can inspect the enabled plugins and get the list of their identifiers
val pluginIdentifiers = tracker.plugins.identifiers
// Finally, remove registered plugins by their identifiers
tracker.plugins.removePlugin(“myPlugin”)
Some of the existing tracker functionality, such as the Global Contexts API for adding entities, is now based on plugins behind the scenes.
By the way, the tracker allows you to provide other closures too. Check out the requestCallback
option, set in EmitterConfiguration
, to act on counts of successful or unsuccessful event sending. There’s also the SessionConfiguration.onSessionUpdate
configuration that, as the name suggests, is a callback for every time the user session is updated.
Screen view tracking in SwiftUI and Jetpack Compose
One of the benefits of the language migration is support for the newer UI frameworks: SwiftUI on iOS and Jetpack Compose for Android. This is particularly important in tracking screen views. Both mobile trackers aim to automatically track an event every time a new screen loads – this default behaviour is set by the TrackerConfiguration.screenViewAutotracking
property.
On iOS, the tracker detects and tracks the loading of UIKit Views by swizzling the ViewController.viewDidAppear
method. SwiftUI views are not detected, so the autotracking doesn’t work! It’s a similar story for Android, where the tracker uses the Application.ActivityLifecycleCallbacks
interface. Screens in Compose apps use composable functions, not Activities. Unfortunately, we haven’t been able to replicate the fully automatic tracking for the new frameworks: the architecture doesn’t support that.
Instead, for the v5 iOS tracker, we’ve created a snowplowScreen
annotation for SwiftUI apps. It’s an extension of View
. Call snowplowScreen
on every View you want tracked.
import SwiftUI
struct ProductList: View {
var body: some View {
List {
...
}
// This View extension will track a screen view event when it loads
.snowplowScreen(name: "ProductList")
}
}
It’s also possible to attach one or more context entities to the screen view, by providing them as a list to snowplowScreen
. While the plugins feature is for general entity addition, this is the opposite – giving you fine control over adding specific entities to a specific screen view. For example, a product detail entity for a product page.
On Android, because Jetpack Compose is so flexible as to how apps are constructed, there’s no obvious single view component to extend in the same way. We suggest adding a listener to the Navigation component, using the NavController.addOnDestinationChangedListener
callback. This code will track a screen view every time the navigation destination changes. The screen name will be the name of the destination (without argument parsing).
fun autoTrackScreenView(navController: NavController) {
navController.addOnDestinationChangedListener { _, destination, _ ->
Snowplow.defaultTracker?.track(ScreenView(destination.route ?: "null"))
}
}
This solution unfortunately doesn’t provide the same kind of control as the SwiftUI snowplowScreen. For specific addition of entities to certain screens, we recommend manually tracking the screen view on a screen-by-screen basis.
We’d love to hear how you instrument your iOS and Android trackers! Chat to us on Discourse.
Upgraded documentation
All the iOS and Android documentation has been overhauled and improved. We’ve made the main Snowplow docs easier to use, and the trackers have new API docs (Android; iOS).
Both trackers have new demo apps! We’ve created very simple SwiftUI and Jetpack Compose apps to show how to instrument the trackers and track events in those frameworks. The demo apps use the Iglu Server API to show all the publicly available Iglu schemas.
For Android, we provide demo apps in Kotlin, Java, and Kotlin with Jetpack Compose. They’re all part of the main Android tracker repository. For iOS, we now provide demo apps in Swift with SPM or Cocoapods, Objective-C with Cocoapods, and Swift with SwiftUI. Find all these demos in the Examples
submodule in the iOS tracker repository.
Let us know what you think
We hope you enjoy using the v5 mobile trackers. Please let us know your thoughts! We’ve kept API changes to a minimum, but check out the migration guide to be sure.