How Herald passes calls on¶
Herald is the object behind all five interfaces. When a class calls track, Herald passes the
call to every vendor you registered, and takes care of everything around it: threads, running
vendors side by side, and failures.
flowchart LR
VM[ViewModel] -- "track(CheckoutStarted)" --> H[Herald]
H --> F[Firebase rules]
H --> M[Mixpanel rules]
H --> A[Adjust rules]
F --> FS[(GA4)]
M --> MS[(Mixpanel)]
A -. no token, not sent .-> X[nothing]
What each call does¶
- Keeps vendor work off your UI. See Threads for how, on each platform.
- Calls every vendor that supports it. A vendor registered without
properties, for example, is skipped forset. - Waits for all of them. The call returns when every vendor has the call, so a second
trackthat waits for the first never overtakes it at any vendor. - Catches failures. If a vendor fails, the others carry on.
- Reports the failures to your error reporter, one at a time.
Herald doesn't decide which events a vendor sends. It passes everything on, and each vendor's
factories decide.
Threads¶
Herald runs vendor calls on a coroutine dispatcher, Dispatchers.Default unless you pass
another:
Herald {
dispatcher(Dispatchers.IO) // or a thread of your own
// dispatcher(UnconfinedTestDispatcher(testScheduler)) // in tests
}
A call suspends until every vendor has finished, so call Herald from a scope that lives long
enough: viewModelScope for work that belongs to a screen, or an app-wide scope for work that
must finish even if the screen closes.
There is no queue or dispatcher. Herald calls each vendor on the thread you call it from, one after another, and returns once every vendor has the call. Vendor SDKs do their own work in the background, so a call takes very little time, and calls never wait or throw.
The order is kept for you, with no await:
A provider of your own must return quickly too: do slow work, such as a network request, in a
Task. See Custom providers.
There is no dispatcher. A call returns a Future that completes when every vendor has
finished, and vendor plugins already do their work off the UI thread.
A call starts at once and doesn't wait for earlier ones. Two calls you don't await can reach a vendor in either order, so await a call when the next one depends on it:
There is no dispatcher. A call returns a promise that settles when every vendor has finished, and vendor SDKs do their work in native code, off the JavaScript thread. The promise never rejects, so it's safe not to await it.
A call starts at once and doesn't wait for earlier ones. Two calls you don't await can reach a vendor in either order, so await a call when the next one depends on it:
Failures¶
Analytics must never break your app, so Herald catches failures at every step:
| What fails | What happens |
|---|---|
| a vendor call fails | caught; the other vendors still run; reported to you |
| your error reporter throws | caught; the other failures are still reported |
| the calling coroutine is cancelled (Android) | the cancellation goes on as usual: that's your code stopping, not a vendor failing |
Your error reporter gets the vendor's name, the operation that failed, and the error. The operation reads the same on every platform:
| Operation | Holds |
|---|---|
Track(eventName) |
the event's name, never its parameters |
SetProperty(propertyName) |
the property's name, never its value |
Identify, Reset |
nothing, so never the user id |
SetEnabled(enabled) |
whether analytics was being turned on or off |
Start, Flush |
nothing |
Because it holds names only, you can send it to a crash reporting tool without copying any personal data into it:
An event that reaches a required-mapping factory, such as
RequireMappedFirebaseEventTrackerFactory, arrives here too, as an unhandled-event error. That's
how Herald tells you an event reached a vendor that nobody wrote a factory for.
Providers¶
A provider is a name and at least one of the five interfaces. Herald refuses to build one with an empty name or no interfaces, because nothing could ever call it. Pick names you'd recognise in a crash log, and give each provider its own. Set up your app shows how to build them on your platform.
Next¶
The factory chain: how each vendor decides what to send.