Courier Android Library
repository·main·Indexed 41 days ago
https://github.com/gojek/courier-androidA Kotlin library for establishing long-running, bi-directional MQTT connections on Android. It optimizes for battery and data efficiency using adaptive keep-alive and automatic reconnection. Courier features a service-oriented approach using annotations like @Receive and @Send, and provides multiple adapters for serialization (Gson, Moshi, Kotlin Serialization, Protobuf) and streaming (RxJava2, Kotlin Coroutines Flow/Channels).
What's inside Courier
- Courier is a Kotlin library designed to create and manage long-running connections using the MQTT protocol. It facilitates persistent, bi-directional communication between a client and a server, optimized for mobile devices by using keep-alive packets to minimize battery and data consumption.
Key features of the Courier library
mainCourier provides several features for robust mobile connectivity:
- Adaptive Keep Alive: Optimizes connection maintenance.
- Automatic Reconnect & Resubscribe: Handles connection drops gracefully.
- Subscription Store & Database Persistence: Ensures subscriptions and state are maintained.
- Backpressure handling: Manages data flow to prevent overwhelming the client.
- Reliable Pinging: Uses Alarm, Timer, and WorkManager to send pings.
- Extensibility: Supports Message & Stream Adapters and MQTT Chuck.
Inspect MQTT packets with MQTT Chuck
mainMQTT Chuck is a debugging tool used to inspect all outgoing and incoming MQTT packets for an underlying MQTT connection. It functions similarly to HTTP Chuck for Android, using an interceptor to capture, persist, and provide a UI for viewing MQTT traffic. It includes features for searching, sharing, and clearing packet data.What is an Authenticator in Courier
mainIn Courier, an
Authenticatoris an interface used to manage MQTT connection credentials. When an MQTT client attempts to connect to a broker, it sends a username and password within the CONNECT packet. If the broker rejects these credentials (returning reason code5), the Courier library uses theAuthenticatorto refresh the connection options (username and password) to enable a successful reconnection.You can either provide your own custom implementation of the
Authenticatorinterface or use the library's built-inHttpAuthenticator.What is a Ping Sender in Courier Android
mainMQTT connections can be terminated by TCP binding timeouts if they remain idle for too long. To prevent this, the client must send
PINGREQpackets at a specificKeepalive Interval. The broker responds with aPINGRESPpacket to confirm the connection is alive.In the Courier Android library, a
Ping Senderis an abstraction that encapsulates the mechanism used to send these ping requests. Different implementations are available depending on whether you need to maintain the connection while the app is in the background or foreground.Split placeholder values in MQTT topics
mainYou can extract specific parts of a placeholder value using a delimiter and a 0-based index with the syntax
(<placeholder>,<delimiter>,<index>).Example: If the client id (
%c) isregion:tenant:device:- Topic:
user/(%c,:,2)/send - Logic: Splits
region:tenant:deviceby:into[region, tenant, device]and picks index2. - Resolved Topic:
user/device/send.
Warning: An index that is out of range will result in an
IllegalArgumentException.@Send(topic = "user/(%c,:,2)/send", qos = QoS.ONE) fun send(@Data message: Message)- Topic:
Use Connection Placeholders in MQTT Topics
mainCourier supports connection placeholders that are automatically resolved from the established MQTT connection. These can be used in
@Send,@Subscribe,@SubscribeMultiple, and@Unsubscribeannotations.Supported Placeholders:
%u: The connection's username.%c: The connection's client id.
Important Limitation: Placeholders are not resolved for
@Receivetopics. For@Receive, the topic string is used as-is. If you need placeholder-based receiving, use@Subscribewith a stream instead.interface MessageService { @Send(topic = "user/%u/send", qos = QoS.ONE) fun send(@Data message: Message) @Subscribe(topic = "client/%c/receive", qos = QoS.ONE) fun subscribe(): Observable<Message> }Configure MqttV3Configuration for MqttClient
mainTo useMqttClient, you must provide an instance ofMqttV3Configuration. This configuration object allows you to define both required and optional properties that govern the behavior of the MQTT connection, including authentication, retry logic, logging, and persistence.MQTT Quality of Service (QoS) levels in Courier
mainCourier utilizes MQTT's built-in QoS levels to manage reliable message delivery. You can choose from three levels depending on your requirements for delivery guarantees:
- QoS 0 (At most once): Fire and forget. The message is sent once without acknowledgment from the client or broker.
- QoS 1 (At least once): Acknowledged delivery. The sender retries the message until an acknowledgment is received.
- QoS 2 (Exactly once): Assured delivery. Uses a two-level handshake between sender and receiver to ensure exactly one copy of the message is delivered.
Understand Subscription Store implementations
mainThe Courier library uses a
SubscriptionStoreto manage current subscriptions and pending unsubscribe requests. This ensures that the client's subscription state is synchronized with the server, especially after reconnections.There are two available implementations:
PersistableSubscriptionStore:- Subscriptions: Maintained in-memory.
- Unsubscribe Requests: Maintained in
SharedPreferences. - Behavior: Upon reconnection, the client automatically re-sends subscription packets and any pending unsubscribe packets. This is the more robust option for ensuring state consistency across app restarts or reconnections.
InMemorySubscriptionStore:- Subscriptions: Maintained in-memory.
- Unsubscribe Requests: Not maintained (lost if the process is killed).
- Behavior: Upon reconnection, the client re-sends subscription packets, but does not re-send pending unsubscribe requests.
Understand MQTT Quality of Service (QoS) levels
mainQuality of Service (QoS) defines the delivery guarantee for a message between a sender and a receiver. In MQTT, there are three standard levels:
- At most once (0): The message is sent without an acknowledgment. It may arrive once or not at all.
- At least once (1): The message is acknowledged with
PUBACK. The receiver is guaranteed to receive the message, but it might receive it more than once if the acknowledgment is lost. - Exactly once (2): The highest level of guarantee, ensuring the message is delivered exactly one time through a four-step handshake.
When configuring QoS, consider both directions of delivery:
- From the publishing client to the broker.
- From the broker to the subscribing client.
Install website dependencies
mainTo install the necessary dependencies for the documentation website, run theyarncommand in the root directory.$ yarn