Message Types Overview
GBGBridge uses three message types:
All messages share the same envelope structure (
BridgeMessage) with a correlationId for pairing requests and responses. Message data values are kotlinx.serialization.json.JsonElement — build payloads with JsonPrimitive(...) or buildJsonObject { }, and read values with extensions like jsonPrimitive.contentOrNull.
Sending Events to the Web Journey
Events are fire-and-forget messages from the native host to the web journey. Use them to notify the web journey of state changes, user actions, or lifecycle transitions.sendEvent returns Unit — there is no delivery confirmation. The SDK generates a correlationId of the form android-event-{uuid} for each event (the iOS SDK uses ios-event-{uuid}).
Common Event Patterns
Handling Incoming Requests
When the web journey sends a request, GBGBridge routes it to a registered handler or adds it topendingRequests.
Using Typed Capability Slots (Recommended)
For capture operations, use the typed slots onBridgeHost. Setting a handler declares support and routes requests automatically. The handler is a suspend lambda that runs on Dispatchers.Main:
CaptureResult into the bridge protocol format automatically. See the Capability Handling Guide for the full Compose integration pattern.
Using Custom Capabilities or BridgeCapabilityHandler
For other capabilities, useregisterCustomCapability() or implement BridgeCapabilityHandler:
handle is async, the Kotlin BridgeCapabilityHandler.handle(request, responder) signature is synchronous. For asynchronous work, retain the responder, do the work off the main thread, then hop back to the main thread and respond:
responder.respond(...) exactly once — subsequent calls on the same responder are silently ignored.
Handling Requests via the Delegate
For requests that don’t map to a single handler — or when you want centralized request handling — useBridgeHostDelegate. All four delegate methods have default no-op implementations, so override only what you need. onMessageSent and onError are Android-only additions with no iOS equivalent.
Responding to Pending Requests Manually
If a request arrives with no registered handler, it is stored inpendingRequests (and onUnhandledRequest fires). You can respond to it later:
pendingRequests is an immutable snapshot taken on each read — it is not observable. Re-read it after delegate callbacks fire and copy it into your own UI state. BridgeMessage has no id property on Android; key Compose lists by correlationId.
Choosing a respond Overload
BridgeHost has two respond overloads, and they behave differently. Both return Unit.
The lookup overload — respond(to, status, data, error) — finds the matching request in pendingRequests by correlationId, removes it, and sends the response using the action recorded on the original request. If no pending request matches the correlationId, the call silently no-ops. Use it for requests that landed on the unhandled path.
The explicit-action overload — respond(to, action, status, data, error) — sends a response without requiring a pending entry; you supply the action yourself. It deduplicates by correlationId: a second call with the same correlationId silently no-ops. If the send fails (encode error, or no WebView attached), the dedupe entry is rolled back so a retry with the same correlationId works once the underlying problem is fixed.
Response Patterns
When responding to a request, you supply a status, optional data, and an optional error payload. The patterns below cover the three response shapes you’ll use most: success-with-data, error, and cancellation.Success with Data
Error with Details
User Cancellation
Unsupported Action
Acknowledged (Async Processing)
UseACKNOWLEDGED when the operation will take time and you want to inform the web journey that the request was received.
Observing All Messages
The Android SDK has no Combine-style publishers. Observe traffic through the delegate callbacks, and read thereceivedMessages / pendingRequests snapshot properties when you need current state:
receivedMessages holds every inbound message, capped at 200 entries (BridgeHost.MAX_RECEIVED_MESSAGES) — older entries are evicted from the head. Both properties return an immutable copy on each read, so for Compose, copy them into your own state from the delegate callbacks rather than reading them directly in composition.
onMessageSent fires for every outbound envelope the SDK was asked to send — including envelopes that are then dropped at transport (no WebView attached) or fail to encode. Treat it as an intent trace, not delivery confirmation.Error Handling
Bridge messaging surfaces errors through two channels:lastError, a read-only string property on the host (clear it with clearError(); hosts cannot write it directly, unlike iOS), and BridgeHostDelegate.onError, an Android-only Throwable channel that fires for decode failures, handler exceptions, encode failures, and origin-gate rejections.
Encoding/Decoding Errors
If GBGBridge cannot decode an incoming message,lastError is set with a description, onError fires, and the message is not added to receivedMessages. If an outbound message fails to encode, lastError is set, onError fires, and the message is dropped — the explicit-action respond overload rolls back its dedupe entry in this case so a retry can succeed.
Sending While Detached
If you callsendEvent or respond before attaching a WebView (or after detach()), the message is silently dropped at transport. onMessageSent still fires — it records intent, not delivery — and no lastError is recorded. This deliberately diverges from iOS, which sets lastError = "WebView not attached". Since respond and sendEvent return Unit, there is no per-call failure signal; make sure the host is attached before sending.
Handler Exceptions
Exceptions thrown by capability handlers are caught by the SDK and routed toonError. If the handler had not yet responded, lastError is also set and an ERROR response with code HANDLER_FAILURE (recoverable = false) is dispatched to the web journey. A handler that responded successfully and then threw is reported via onError only — the request itself still succeeded.
JavaScript Delivery
Outbound delivery into the page is fire-and-forget: the injected script no-ops whenwindow.GBGBridge.receive is not defined (for example, after the page has navigated away), and no error is reported back to the host. This differs from iOS, where WebKit evaluation failures set lastError.
Next Steps
- Capability Handling Guide — Build handlers for camera capture and custom capabilities
- Embedding Guide — Compose and View-system integration patterns
- API Reference — Detailed method signatures and parameters