diff --git a/404.html b/404.html index ea9b21d..441df31 100644 --- a/404.html +++ b/404.html @@ -5,13 +5,13 @@ Page Not Found | Courier Android - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/runtime~main.df4dc8b7.js b/assets/js/runtime~main.e6f76234.js similarity index 56% rename from assets/js/runtime~main.df4dc8b7.js rename to assets/js/runtime~main.e6f76234.js index 7d05b35..b299da0 100644 --- a/assets/js/runtime~main.df4dc8b7.js +++ b/assets/js/runtime~main.e6f76234.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,r,a,o,f={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var r=d[e]={exports:{}};return f[e].call(r.exports,r,r.exports,n),r.exports}n.m=f,e=[],n.O=(t,r,a,o)=>{if(!r){var f=1/0;for(b=0;b=o)&&Object.keys(n.O).every((e=>n.O[e](r[c])))?r.splice(c--,1):(d=!1,o0&&e[b-1][2]>o;b--)e[b]=e[b-1];e[b]=[r,a,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);n.r(o);var f={};t=t||[null,r({}),r([]),r(r)];for(var d=2&a&&e;"object"==typeof d&&!~t.indexOf(d);d=r(d))Object.getOwnPropertyNames(d).forEach((t=>f[t]=()=>e[t]));return f.default=()=>e,n.d(o,f),o},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,r)=>(n.f[r](e,t),t)),[])),n.u=e=>"assets/js/"+({48:"fb5adfad",145:"a6857b16",148:"8ad68633",150:"2b59e5d5",209:"d3d4ddd5",284:"239e8a52",325:"a98fac15",385:"36ada3df",387:"92bd0498",401:"17896441",409:"b9b35de4",416:"8a6052eb",473:"59424fb6",494:"e0a19902",500:"1ff659d4",569:"f2346e40",581:"935f2afb",634:"c4f5d8e4",649:"331638ff",653:"f864a7a1",704:"fb22182f",714:"1be78505",743:"1e8741b6",859:"242cc4f8",943:"65a61b25",975:"bf4d2693",999:"0f6e67ac"}[e]||e)+"."+{48:"a673808b",90:"18f31305",145:"6a5844f9",148:"35a6b60d",150:"e4bcb803",209:"f47c8956",284:"f9f3cf6b",325:"384d75d6",385:"9e6de260",387:"73ff1fac",401:"ff1617ee",409:"08b37934",416:"e1d9d4f9",473:"46f2d373",494:"01716327",500:"3073d25b",569:"4efbb6a1",581:"ec728681",634:"2bd3bf2f",649:"a4d218cd",653:"90587d72",704:"88a265ee",714:"40e337c5",743:"432cfea3",859:"62b81d33",943:"4b79dd97",975:"f1a6a83c",999:"c0191ef6"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="docs:",n.l=(e,t,r,f)=>{if(a[e])a[e].push(t);else{var d,c;if(void 0!==r)for(var i=document.getElementsByTagName("script"),b=0;b{d.onerror=d.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],d.parentNode&&d.parentNode.removeChild(d),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),c&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/courier-android/",n.gca=function(e){return e={17896441:"401",fb5adfad:"48",a6857b16:"145","8ad68633":"148","2b59e5d5":"150",d3d4ddd5:"209","239e8a52":"284",a98fac15:"325","36ada3df":"385","92bd0498":"387",b9b35de4:"409","8a6052eb":"416","59424fb6":"473",e0a19902:"494","1ff659d4":"500",f2346e40:"569","935f2afb":"581",c4f5d8e4:"634","331638ff":"649",f864a7a1:"653",fb22182f:"704","1be78505":"714","1e8741b6":"743","242cc4f8":"859","65a61b25":"943",bf4d2693:"975","0f6e67ac":"999"}[e]||e,n.p+n.u(e)},(()=>{var e={354:0,869:0};n.f.j=(t,r)=>{var a=n.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var f=n.p+n.u(t),d=new Error;n.l(f,(r=>{if(n.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),f=r&&r.target&&r.target.src;d.message="Loading chunk "+t+" failed.\n("+o+": "+f+")",d.name="ChunkLoadError",d.type=o,d.request=f,a[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,f=r[0],d=r[1],c=r[2],i=0;if(f.some((t=>0!==e[t]))){for(a in d)n.o(d,a)&&(n.m[a]=d[a]);if(c)var b=c(n)}for(t&&t(r);i{"use strict";var e,t,r,a,f,o={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var r=d[e]={exports:{}};return o[e].call(r.exports,r,r.exports,n),r.exports}n.m=o,e=[],n.O=(t,r,a,f)=>{if(!r){var o=1/0;for(i=0;i=f)&&Object.keys(n.O).every((e=>n.O[e](r[b])))?r.splice(b--,1):(d=!1,f0&&e[i-1][2]>f;i--)e[i]=e[i-1];e[i]=[r,a,f]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var f=Object.create(null);n.r(f);var o={};t=t||[null,r({}),r([]),r(r)];for(var d=2&a&&e;"object"==typeof d&&!~t.indexOf(d);d=r(d))Object.getOwnPropertyNames(d).forEach((t=>o[t]=()=>e[t]));return o.default=()=>e,n.d(f,o),f},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,r)=>(n.f[r](e,t),t)),[])),n.u=e=>"assets/js/"+({48:"fb5adfad",145:"a6857b16",148:"8ad68633",150:"2b59e5d5",209:"d3d4ddd5",284:"239e8a52",325:"a98fac15",385:"36ada3df",387:"92bd0498",401:"17896441",409:"b9b35de4",416:"8a6052eb",473:"59424fb6",494:"e0a19902",500:"1ff659d4",569:"f2346e40",581:"935f2afb",634:"c4f5d8e4",649:"331638ff",653:"f864a7a1",704:"fb22182f",714:"1be78505",743:"1e8741b6",859:"242cc4f8",943:"65a61b25",975:"bf4d2693",999:"0f6e67ac"}[e]||e)+"."+{48:"a673808b",90:"18f31305",145:"6a5844f9",148:"35a6b60d",150:"e4bcb803",209:"f47c8956",284:"f9f3cf6b",325:"384d75d6",385:"9e6de260",387:"73ff1fac",401:"ff1617ee",409:"08b37934",416:"e1d9d4f9",473:"46f2d373",494:"01716327",500:"3073d25b",569:"4efbb6a1",581:"ec728681",634:"2bd3bf2f",649:"a4d218cd",653:"90587d72",704:"88a265ee",714:"40e337c5",743:"432cfea3",859:"62b81d33",943:"4b79dd97",975:"f1a6a83c",999:"c0191ef6"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},f="docs:",n.l=(e,t,r,o)=>{if(a[e])a[e].push(t);else{var d,b;if(void 0!==r)for(var c=document.getElementsByTagName("script"),i=0;i{d.onerror=d.onload=null,clearTimeout(s);var f=a[e];if(delete a[e],d.parentNode&&d.parentNode.removeChild(d),f&&f.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),b&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/courier-android/",n.gca=function(e){return e={17896441:"401",fb5adfad:"48",a6857b16:"145","8ad68633":"148","2b59e5d5":"150",d3d4ddd5:"209","239e8a52":"284",a98fac15:"325","36ada3df":"385","92bd0498":"387",b9b35de4:"409","8a6052eb":"416","59424fb6":"473",e0a19902:"494","1ff659d4":"500",f2346e40:"569","935f2afb":"581",c4f5d8e4:"634","331638ff":"649",f864a7a1:"653",fb22182f:"704","1be78505":"714","1e8741b6":"743","242cc4f8":"859","65a61b25":"943",bf4d2693:"975","0f6e67ac":"999"}[e]||e,n.p+n.u(e)},(()=>{var e={354:0,869:0};n.f.j=(t,r)=>{var a=n.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(354|869)$/.test(t))e[t]=0;else{var f=new Promise(((r,f)=>a=e[t]=[r,f]));r.push(a[2]=f);var o=n.p+n.u(t),d=new Error;n.l(o,(r=>{if(n.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var f=r&&("load"===r.type?"missing":r.type),o=r&&r.target&&r.target.src;d.message="Loading chunk "+t+" failed.\n("+f+": "+o+")",d.name="ChunkLoadError",d.type=f,d.request=o,a[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,r)=>{var a,f,o=r[0],d=r[1],b=r[2],c=0;if(o.some((t=>0!==e[t]))){for(a in d)n.o(d,a)&&(n.m[a]=d[a]);if(b)var i=b(n)}for(t&&t(r);c Adaptive KeepAlive | Courier Android - +

Adaptive KeepAlive

Adaptive keepalive is a feature in the Courier library which tries to find the most optimal keepalive interval for a client on a particular network. This helps us in optimising the number of ping requests sent over the network and keeping the connection alive.

You can read about Adaptive KeepAlive in detail here.

Usage

To enable adaptive keepalive for your Courier connection, you just need to pass AdaptiveKeepAliveConfig inside ExperimentConfigs.

This will create a new connection having the same connect options as the original connection. Only the client id for this new connection is changed by appending the :adaptive suffix to the original client id.

AdaptiveKeepAliveConfig

AdaptiveKeepAliveConfig has the following configs:

  • lowerBoundMinutes : Lower bound of the window in which optimal keepalive interval has to be searched.

  • upperBoundMinutes : Upper bound of the window in which optimal keepalive interval has to be searched.

  • stepMinutes : Step size with which keep alive interval is incremented while searching for the optimal keepalive interval.

  • optimalKeepAliveResetLimit : Once optimal keepalive interval is found, it will be reset if it keeps failing beyond optimalKeepAliveResetLimit.

  • pingSender : Implementation of ping sender used for sending ping requests over the new MQTT connection used for finding the optimal keepalive interval.

- + \ No newline at end of file diff --git a/docs/Authenticator/index.html b/docs/Authenticator/index.html index 1b38f99..d72730d 100644 --- a/docs/Authenticator/index.html +++ b/docs/Authenticator/index.html @@ -5,13 +5,13 @@ Authenticator | Courier Android - +

Authenticator

When an MQTT client tries to make a connection with an MQTT broker, username and password are sent inside CONNECT packet, which the broker uses to authenticate the client. If username or password is incorrect, broker returns reason code 5.

Courier library uses the Authenticator to refresh the connect options, which contains the username and password, in order to reconnect with the broker successfully.

You can pass your own implementation of Authenticator interface or uses the library provided HttpAuthenticator

Http Authenticator

Courier library provides an implementation of Authenticator, which allows you to fetch the latest connect options by making an HTTP call.

Usage

Add this dependency for using Http Authenticator

dependencies {
implementation "com.gojek.courier:courier-auth-http:x.y.z"
}

An instance of HttpAuthenticator can be created using the factory class.

httpAuthenticator = HttpAuthenticatorFactory.create(
retrofit = retrofit,
apiUrl = TOKEN_AUTH_API,
responseHandler = responseHandler,
eventHandler = eventHandler,
authRetryPolicy = authRetryPolicy
)
- + \ No newline at end of file diff --git a/docs/CONTRIBUTION/index.html b/docs/CONTRIBUTION/index.html index 04c51f2..d383e95 100644 --- a/docs/CONTRIBUTION/index.html +++ b/docs/CONTRIBUTION/index.html @@ -5,14 +5,14 @@ How to Contribute | Courier Android - +

How to Contribute

Courier team would love to have your contributions.

We operate with a pull request system with GitHub. Read our contribution guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Courier Android library.

- + \ No newline at end of file diff --git a/docs/ConnectionSetup/index.html b/docs/ConnectionSetup/index.html index 1737df5..c313c06 100644 --- a/docs/ConnectionSetup/index.html +++ b/docs/ConnectionSetup/index.html @@ -5,13 +5,13 @@ Connection Setup | Courier Android - +

Connection Setup

MqttClient

An instance of MqttClient needs to be created in order to establish a Courier connection.

val mqttClient = MqttClientFactory.create(
context = context,
mqttConfiguration = mqttConfiguration
)

Connect using MqttClient

val alpnProtocol = "mqtt"
val connectOptions = MqttConnectOptions.Builder()
.serverUris(listof(ServerUri(SERVER_URI, SERVER_PORT)))
.clientId(clientId)
.userName(username)
.password(password)
.keepAlive(KeepAlive(timeSeconds = keepAliveSeconds))
.cleanSession(cleanSessionFlag)
.alpnProtocols(listOf(Protocol(alpnProtocol)))
.build()

mqttClient.connect(connectOptions)

Disconnect using MqttClient

mqttClient.disconnect()

MqttConnectOptions

MqttConnectOptions represents the properties of the underlying MQTT connection in Courier.

  • Server URIs : List of ServerUri representing the host and port of an MQTT broker.

  • Client Id : Unique ID of the MQTT client.

  • Username : Username of the MQTT client.

  • Password : Password of the MQTT client.

  • KeepAlive Interval : Interval at which keep alive packets are sent for the MQTT connection.

  • Clean Session Flag : When clean session is false, a persistent connection is created. Otherwise, non-persistent connection is created and all persisted information is cleared from both client and broker.

  • Read Timeout : Read timeout of the SSL/TCP socket created for the MQTT connection.

  • MQTT protocol version : It can be either VERSION_3_1 or VERSION_3_1_1.

  • User properties : Custom user properties appended to the CONNECT packet.

  • Socket Factory : Sets the socket factory used to create connections. If unset, the SocketFactory.getDefault socket factory will be used. Set shouldUseNewSSLFlow to true to enable this.

  • SSL Socket Factory: Sets the socket factory and trust manager used to secure MQTT connections. If unset, the system defaults will be used. Set shouldUseNewSSLFlow to true to enable this.

  • Connection Spec: Specifies configuration for the socket connection that MQTT traffic travels through. This includes the TLS version and cipher suites to use when negotiating a secure connection. Set shouldUseNewSSLFlow to true to enable this.

  • ALPN Protocols: Configure the alpn protocols used by this client to communicate with MQTT broker. Set shouldUseNewSSLFlow to true to enable this.

- + \ No newline at end of file diff --git a/docs/CourierService/index.html b/docs/CourierService/index.html index 91b5965..dc3dbdd 100644 --- a/docs/CourierService/index.html +++ b/docs/CourierService/index.html @@ -5,13 +5,13 @@ Courier Service Interface | Courier Android - +

Courier Service Interface

Courier provides the functionalities like Send, Receive, Subscribe, Unsubscribe through a service interface. This is similar to how we make HTTP calls using Retrofit.

Usage

Declare a service interface for various actions like Send, Receive, Subscribe, SubscribeMultiple, Unsubscribe.

interface MessageService {
@Receive(topic = "topic/{id}/receive")
fun receive(@Path("id") identifier: String): Observable<Message>

@Send(topic = "topic/{id}/send", qos = QoS.TWO)
fun send(@Path("id") identifier: String, @Data message: Message)

@Subscribe(topic = "topic/{id}/receive", qos = QoS.ONE)
fun subscribe(@Path("id") identifier: String): Observable<Message>

@SubscribeMultiple
fun subscribe(@TopicMap topicMap: Map<String, QoS>): Observable<Message>

@Unsubscribe(topics = ["topic/{id}/receive"])
fun unsubscribe(@Path("id") identifier: String)
}

Use Courier to create an implementation of service interface.

val courierConfiguration = Courier.Configuration(
client = mqttClient,
streamAdapterFactories = listOf(RxJava2StreamAdapterFactory()),
messageAdapterFactories = listOf(GsonMessageAdapter.Factory())
)

val courier = Courier(courierConfiguration)

val messageService = courier.create<MessageService>()

Following annotations are supported for service interface.

  • @Send : A method annotation used for sending messages over the MQTT connection.

  • @Receive : A method annotation used for receiving messages over the MQTT connection. Note: The topic needs to be subscribed for receiving messages.

  • @Subscribe : A method annotation used for subscribing a single topic over the MQTT connection.

  • @SubscribeMultiple : A method annotation used for subscribing multiple topics over the MQTT connection.

  • @Unsubscribe : A method annotation used for unsubscribing topics over the MQTT connection.

  • @Path : A parameter annotation used for specifying a path variable in an MQTT topic.

  • @Data : A parameter annotation used for specifying the message object while sending a message over the MQTT connection.

  • @TopicMap : A parameter annotation used for specifying a topic map. It is always used while subscribing multiple topics.

Note : While subscribing topics using @SubscribeMultiple along with a stream, make sure that messages received on all topics follow same format or a message adapter is added for handling different format.

- + \ No newline at end of file diff --git a/docs/ExperimentConfigs/index.html b/docs/ExperimentConfigs/index.html index f8a2451..b1ad66f 100644 --- a/docs/ExperimentConfigs/index.html +++ b/docs/ExperimentConfigs/index.html @@ -5,13 +5,13 @@ Experiment Configs | Courier Android - +

Experiment Configs

These are the experimentation configs used in Courier library. These are volatile configs i.e., they can be modified/moved/removed in future.

  • isPersistentSubscriptionStoreEnabled : When enabled, PersistableSubscriptionStore implementation of SubscriptionStore is used. Otherwise, InMemorySubscriptionStore is used. Read more about SubscriptionStore

  • adaptiveKeepAliveConfig : This config is used for enabling Adaptive KeepAlive feature in courier library.

  • activityCheckIntervalSeconds : Interval at which channel activity is checked for unacknowledged MQTT packets.

  • inactivityTimeoutSeconds : When acknowledgement for an MQTT packet is not received within this interval, the connection is reestablished.

  • policyResetTimeSeconds : After this interval, connect retry policy is reset once the connection is successfully made.

  • incomingMessagesTTLSecs : When there is no listener attached for an incoming message, messages are persisted for this interval.

  • incomingMessagesCleanupIntervalSecs : Interval at which cleanup for incoming messages persistence is performed.

  • shouldUseNewSSLFlow : Set this true for enabling alpn protocol, custom ssl socket factory.

- + \ No newline at end of file diff --git a/docs/GettingStarted/index.html b/docs/GettingStarted/index.html index a629c46..ca349df 100644 --- a/docs/GettingStarted/index.html +++ b/docs/GettingStarted/index.html @@ -5,13 +5,13 @@ Getting Started | Courier Android - + - + \ No newline at end of file diff --git a/docs/Installation/index.html b/docs/Installation/index.html index c68faa7..6b54304 100644 --- a/docs/Installation/index.html +++ b/docs/Installation/index.html @@ -5,13 +5,13 @@ Installation | Courier Android - +

Installation

Supported SDK versions

  • minSdkVersion: 21
  • targetSdkVersion: 34
  • compileSdkVersion: 34

Download

Maven Central

All artifacts of Courier library are available via Maven Central.

repositories {
mavenCentral()
}

dependencies {
implementation "com.gojek.courier:courier:x.y.z"

implementation "com.gojek.courier:courier-message-adapter-gson:x.y.z"
implementation "com.gojek.courier:courier-stream-adapter-rxjava2:x.y.z"
}

Modules

Courier Android library provides multiple use case specific modules

Core modules

These modules provide the core functionalities like Connect/Disconnect, Subscribe/Unsubscribe, Send/Receive

  • courier
  • mqtt-client

Message & Stream Adapters

Library provided implementations of message and stream adapters. Read more about them here.

  • courier-message-adapter-gson
  • courier-message-adapter-moshi
  • courier-message-adapter-protobuf
  • courier-stream-adapter-rxjava
  • courier-stream-adapter-rxjava2
  • courier-stream-adapter-coroutines

Ping Sender

Library provided implementations of Mqtt Ping Sender. Read more about them here.

  • timer-pingsender
  • workmanager-pingsender
  • workmanager-2.6.0-pingsender
  • alarm-pingsender

Http Authenticator

Library provided implementation of Authenticator. Read more about this here.

  • courier-auth-http

MQTT Chuck

HTTP Chuck inspired tool for debugging all MQTT packets. Read more about this here.

  • chuck-mqtt
- + \ No newline at end of file diff --git a/docs/Introduction/index.html b/docs/Introduction/index.html index b79cc76..2725ca3 100644 --- a/docs/Introduction/index.html +++ b/docs/Introduction/index.html @@ -5,14 +5,14 @@ Introduction | Courier Android - +

Introduction

image banner image banner

About Courier

Courier is a kotlin library for creating long running connections using MQTT protocol.

Long running connection is a persistent connection established between client & server for instant bi-directional communication. A long running connection is maintained for maximum possible duration with the help of keep alive packets. This helps in saving battery and data on mobile devices.

MQTT is an extremely lightweight protocol which works on publish/subscribe messaging model. It is designed for connections with remote locations where a "small code footprint" is required or the network bandwidth is limited.

The protocol usually runs over TCP/IP; however, any network protocol that provides ordered, lossless, bi-directional connections can support MQTT.

MQTT has 3 built-in QoS levels for Reliable Message Delivery:

  • QoS 0(At most once) - the message is sent only once and the client and broker take no additional steps to acknowledge delivery (fire and forget).

  • QoS 1(At least once) - the message is re-tried by the sender multiple times until acknowledgement is received (acknowledged delivery).

  • QoS 2(Exactly once) - the sender and receiver engage in a two-level handshake to ensure only one copy of the message is received (assured delivery).

Features

  • Clean API

  • Adaptive Keep Alive

  • Message & Stream Adapters

  • Subscription Store

  • Automatic Reconnect & Resubscribe

  • Database Persistence

  • Backpressure handling

  • Alarm, Timer & WorkManager Ping Sender

  • MQTT Chuck

More details about features in Courier library can be found here

- + \ No newline at end of file diff --git a/docs/LICENSE.paho/index.html b/docs/LICENSE.paho/index.html index 9fe9dd1..de5e312 100644 --- a/docs/LICENSE.paho/index.html +++ b/docs/LICENSE.paho/index.html @@ -5,7 +5,7 @@ LICENSE.paho | Courier Android - + @@ -182,7 +182,7 @@ file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

- + \ No newline at end of file diff --git a/docs/LICENSE/index.html b/docs/LICENSE/index.html index abc594e..fe79450 100644 --- a/docs/LICENSE/index.html +++ b/docs/LICENSE/index.html @@ -5,7 +5,7 @@ LICENSE | Courier Android - + @@ -23,7 +23,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

- + \ No newline at end of file diff --git a/docs/MessageStreamAdapters/index.html b/docs/MessageStreamAdapters/index.html index 317edf0..b20950a 100644 --- a/docs/MessageStreamAdapters/index.html +++ b/docs/MessageStreamAdapters/index.html @@ -5,13 +5,13 @@ Message & Stream Adapters | Courier Android - +

Message & Stream Adapters

Courier provides the functionality of passing your own custom or library-provided message & stream adapters.

Message Adapter

To serialize and deserialize received and published messages, Courier uses MessageAdapter. With this, you don't need to handle the serialization and deserialization process when publishing and receiving messages from broker.

Courier library provides the following message adapters:

  • courier-message-adapter-gson

  • courier-message-adapter-moshi

  • courier-message-adapter-protobuf

You can also create your own custom message adapter by implementing the MessageAdapter.Factory interface.

class MyCustomMessageAdapterFactory : MessageAdapter.Factory {

override fun create(type: Type, annotations: Array<Annotation>): MessageAdapter<*> {
return MyCustomMessageAdapter()
}
}

private class MyCustomMessageAdapter<T> constructor() : MessageAdapter<T> {

override fun fromMessage(topic: String, message: Message): T {
// convert message to custom type
}

override fun toMessage(topic: String, data: T): Message {
// convert custom type to message
}

override fun contentType(): String {
// content-type supported by this adapter.
}
}

Stream Adapter

Courier library provides the following stream adapters:

  • courier-stream-adapter-rxjava

  • courier-stream-adapter-rxjava2

  • courier-stream-adapter-coroutines

You can also create your own custom Stream adapter by implementing the StreamAdapter.Factory interface.

class MyCustomStreamAdapterFactory : StreamAdapter.Factory {

override fun create(type: Type): StreamAdapter<Any, Any> {
return MyCustomStreamAdapter()
}
}

private class MyCustomStreamAdapter<T> : StreamAdapter<T, Any> {

override fun adapt(stream: Stream<T>): Any {
// convert stream to custom stream
}
}
- + \ No newline at end of file diff --git a/docs/MqttChuck/index.html b/docs/MqttChuck/index.html index f660a52..15bef56 100644 --- a/docs/MqttChuck/index.html +++ b/docs/MqttChuck/index.html @@ -5,13 +5,13 @@ MQTT Chuck | Courier Android - +

MQTT Chuck

MQTT Chuck is used for inspecting all the outgoing or incoming MQTT packets for an underlying MQTT connection. MQTT Chuck is similar to HTTP Chuck, used for inspecting the HTTP calls on an android application.

MQTT Chuck uses an interceptor to intercept all the MQTT packets, persisting them and providing a UI for accessing all the MQTT packets sent or received over the MQTT connection. It also provides multiple other features like search, share, and clear data.

image chuck

Usage

Add this dependency for using MQTT chuck

dependencies {
implementation "com.gojek.courier:chuck-mqtt:x.y.z"
}

To enable MQTT chuck for your courier connection, just pass the MqttChuckInterceptor inside MqttConfiguration

mqttConfiguration = MqttV3Configuration(
mqttInterceptorList = listOf(MqttChuckInterceptor(context, mqttChuckConfig))
)
- + \ No newline at end of file diff --git a/docs/MqttConfiguration/index.html b/docs/MqttConfiguration/index.html index 5dbec57..ff240d1 100644 --- a/docs/MqttConfiguration/index.html +++ b/docs/MqttConfiguration/index.html @@ -5,13 +5,13 @@ MQTT Client Configuration | Courier Android - +

MQTT Client Configuration

As we have seen earlier, MqttClient requires an instance of MqttV3Configuration. MqttV3Configuration allows you to configure the following properties of MqttClient:

Required Configs

  • MqttPingSender : It is an implementation of MqttPingSender interface, which defines the logic of sending ping requests over the MQTT connection. Read more ping sender here.

  • Authenticator : MqttClient uses Authenticator to refresh the connect options when username or password are incorrect. Read more Authenticator here.

Optional Configs

  • Retry Policies : There are multiple retry policies used in Courier library - connect retry policy, connect timeout policy, subscription policy. You can either use the in-built policies or provide your own custom policies.

  • Logger : An instance of ILogger can be passed to get the internal logs.

  • Event Handler : EventHandler allows you to listen to all the library events like connect attempt/success/failure, message send/receive, subscribe/unsubscribe.

  • Mqtt Interceptors : By passing mqtt interceptors, you can intercept all the MQTT packets sent over the courier connection. This is also used for enabling MQTT Chuck.

  • Persistence Options : It allows you to configure the offline buffer present inside Paho. This buffer is used for storing all the messages while the client is offline.

  • Experimentation Configs : These are the experiment configs used inside Courier library which are explained in detail here.

  • WakeLock Timeout : When positive value of this timeout is passed, a wakelock is acquired while creating the MQTT connection. By default, it is 0.

- + \ No newline at end of file diff --git a/docs/NonStandardOptions/index.html b/docs/NonStandardOptions/index.html index 1005ea3..75fd5a9 100644 --- a/docs/NonStandardOptions/index.html +++ b/docs/NonStandardOptions/index.html @@ -5,14 +5,14 @@ Non-standard Connection options | Courier Android - +

Non-standard Connection options

UserProperties in MqttConnectionOptions

This option allows you to send user-properties in CONNECT packet for MQTT v3.1.1.

val connectOptions = MqttConnectOptions.Builder()
.serverUris(listOf(ServerUri(SERVER_URI, SERVER_PORT)))
.clientId(clientId)
...
.userProperties(
userProperties = mapOf(
"key1" to "value1",
"key2" to "value2"
)
)
.build()

mqttClient.connect(connectOptions)

⚠️ ** This is a non-standard option. As far as the MQTT specification is concerned, user-properties support is added in MQTT v5. So to support this in MQTT v3.1.1, broker needs to have support for this as well.

- + \ No newline at end of file diff --git a/docs/PingSender/index.html b/docs/PingSender/index.html index 6bba2d1..4ea5269 100644 --- a/docs/PingSender/index.html +++ b/docs/PingSender/index.html @@ -5,13 +5,13 @@ MQTT Ping Sender | Courier Android - +

MQTT Ping Sender

When an MQTT connection between a client and the broker is idle for a long time, it may get torn down due to TCP binding timeout. In order to keep the connection alive, the client needs to send PINGREQ packets through the connection. If the connection is alive, the broker responds with a PINGRESP packet. If the client does not receive the PINGRESP packet within some fixed interval, it breaks the connection and reconnects. The interval at which these packets are sent is the Keepalive Interval.

Ping Sender

Courier Android library uses Ping Sender for sending pings through the MQTT connection. It encapsulates the actual mechanism used for sending the ping requests.

Current Implementations

WorkManagerPingSender

  • Uses WorkManager for sending ping requests over the MQTT connection.
  • Ideal for cases where the connection needs to be maintained when the app is in background.
  • No user permission is required for using this.
  • Uses WorkManager version 2.7.0 which requires compileSdkVersion to be 31 or higher.

Usage

Add this dependency for using WorkManagerPingSender

dependencies {
implementation "com.gojek.courier:workmanager-pingsender:x.y.z"
}

Create ping sender using the factory class

pingSender = WorkPingSenderFactory.createMqttPingSender(
context, workManagerPingSenderConfig
)

WorkManager-2.6.0 PingSender

  • Uses WorkManager for sending ping requests over the MQTT connection.
  • Ideal for cases where the connection needs to be maintained when the app is in background.
  • No user permission is required for using this.
  • Uses WorkManager version 2.6.0 which is compatible with apps targeting lower than android 31.

Usage

Add this dependency for using WorkManagerPingSender

dependencies {
implementation "com.gojek.courier:workmanager-2.6.0-pingsender:x.y.z"
}

Create ping sender using the factory class

pingSender = WorkPingSenderFactory.createMqttPingSender(
context, workManagerPingSenderConfig
)

AlarmPingSender

  • Uses Alarms for sending ping requests over the MQTT connection.
  • Ideal for cases where the connection needs to be maintained when the app is in background.
  • On Android 12 & above, user permission is required for scheduling exact alarms.

Usage

Add this dependency for using AlarmPingSender

dependencies {
implementation "com.gojek.courier:alarm-pingsender:x.y.z"
}

Create ping sender using the factory class

pingSender = AlarmPingSenderFactory.createMqttPingSender(
context, alarmPingSenderConfig
)

TimerPingSender

  • Uses Timer for sending ping requests over the MQTT connection.
  • Ideal for cases where the connection needs to be maintained only when the app is in foreground.

Usage

Add this dependency for using TimerPingSender

dependencies {
implementation "com.gojek.courier:timer-pingsender:x.y.z"
}

Create ping sender using the factory class

pingSender = TimerPingSenderFactory.create()
- + \ No newline at end of file diff --git a/docs/QoS/index.html b/docs/QoS/index.html index 7f6039e..9643fba 100644 --- a/docs/QoS/index.html +++ b/docs/QoS/index.html @@ -5,7 +5,7 @@ Quality of Service | Courier Android - + @@ -14,7 +14,7 @@ These are non standard QoS options. You need to have compatible broker to use these QoS options

We added two more Qos options

  • QoS1 with no persistence and no retry: Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are neither persisted nor retried at send after one attempt. The message arrives at the receiver either once or not at all
  • QoS1 with no persistence and with retry: Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are not persisted. The messages are retried within active connection if delivery is not acknowledged.
Note: Both these Qos options have same behaviour (without retry) during publish and different behaviour for subscribe - + \ No newline at end of file diff --git a/docs/SampleApp/index.html b/docs/SampleApp/index.html index 17d6578..c3d8f45 100644 --- a/docs/SampleApp/index.html +++ b/docs/SampleApp/index.html @@ -5,13 +5,13 @@ Sample App | Courier Android - +

Sample App

A sample application is added here which makes Courier connection with a HiveMQ public broker. It demonstrates multiple functionalities of Courier like Connect, Disconnect, Publish, Subscribe and Unsubscribe.

image demo

Running sample app

  • Clone the project from GitHub
  • Run command ./gradlew :app:installDebug
- + \ No newline at end of file diff --git a/docs/SendReceiveMessage/index.html b/docs/SendReceiveMessage/index.html index be58b65..a290da7 100644 --- a/docs/SendReceiveMessage/index.html +++ b/docs/SendReceiveMessage/index.html @@ -5,13 +5,13 @@ Send & Receive messages | Courier Android - +

Send & Receive messages

Courier library provides the functionality of sending & receiving messages through both service interface and MqttClient.

Send/Receive using Service Interface

interface MessageService {
@Receive(topic = "topic/{id}/receive")
fun receive(@Path("id") identifier: String): Observable<Message>

@Send(topic = "topic/{id}/send", qos = QoS.TWO)
fun send(@Path("id") identifier: String, @Data message: Message)
}
messageService.send("user-id", message)

messageService.receive("user-id") { message ->
print(message)
}

Send/Receive using MqttClient

mqttClient.send(message, topic, QoS.TWO)

mqttClient.addMessageListener(topic, object : MessageListener {
override fun onMessageReceived(mqttMessage: MqttMessage) {
print(mqttMessage)
}
})

Note : Only messages for those topics can be received through receive api, which are already subscribed

- + \ No newline at end of file diff --git a/docs/SubscribeUnsubscribe/index.html b/docs/SubscribeUnsubscribe/index.html index d9abee9..9accf29 100644 --- a/docs/SubscribeUnsubscribe/index.html +++ b/docs/SubscribeUnsubscribe/index.html @@ -5,13 +5,13 @@ Subscribe & Unsubscribe topics | Courier Android - +

Subscribe & Unsubscribe topics

Courier library provides the functionality of subscribing & unsubscribing topics through both service interface and MqttClient.

Subscribe/Unsubscribe through Service Interface

interface MessageService {
@Subscribe(topic = "topic/{id}/receive", qos = QoS.ONE)
fun subscribe(@Path("id") identifier: String): Observable<Message>

@SubscribeMultiple
fun subscribeMultiple(@TopicMap topics: Map<String, QoS>): Observable<Message>

@Unsubscribe(topics = ["topic/{id}/receive"])
fun unsubscribe(@Path("id") identifier: String)
}
messageService.subscribe("user-id").subscribe { message ->
print(message)
}

messageService.subscribeMultiple(mapOf("topic1" to QoS.ONE, "topic2" to QoS.TWO)).subscribe { message ->
print(message)
}

messageService.unsubscribe("user-id")

Subscribe/Unsubscribe through MqttClient

mqttClient.subscribe("topic1" to QoS.ZERO, "topic2" to QoS.ONE)

mqttClient.unsubscribe("topic1", "topic2")

Note : While subscribing topics using @SubscribeMultiple along with a stream, make sure that messages received on all topics follow same format or a message adapter is added for handling different format.

- + \ No newline at end of file diff --git a/docs/SubscriptionStore/index.html b/docs/SubscriptionStore/index.html index 5059aeb..ebfedf4 100644 --- a/docs/SubscriptionStore/index.html +++ b/docs/SubscriptionStore/index.html @@ -5,13 +5,13 @@ Subscription Store | Courier Android - +

Subscription Store

Courier library uses Subscription Store for maintaining the current subscriptions and pending unsubscribe requests.

Currently there are two implementations of SubscriptionStore provided by Courier library.

PersistableSubscriptionStore

In this implementation, the current subscriptions are maintained in-memory and pending unsubscribe requests are maintained in shared preferences. When client reconnects, subscription packets are sent again and pending unsubscribe packets are also sent, if present.

InMemorySubscriptionStore

In this implementation, the current subscriptions are maintained in-memory and no pending unsubscribe requests are maintained. When client reconnects, subscription packets are sent again.

Usage

You can choose the subscription store implementation to be used using ExperimentConfigs

- + \ No newline at end of file diff --git a/index.html b/index.html index 3afa116..93ff473 100644 --- a/index.html +++ b/index.html @@ -5,13 +5,13 @@ Courier Android | Courier Android - +

Secure

Supports SSL/TLS for secure connection

Reliable Message Delivery

Supports MQTTv3.1.1 for reliable message delivery through various QoS levels

Android 12 compatible

Courier library is compatible with Android 12

- + \ No newline at end of file